Как перехватить длительное нажатие на UITextView без отключения контекстного меню?
Я хочу перехватить длительное нажатие на UITextview, но не хочу одновременно отключать параметр контекстного меню.
Если я использую распознаватель жестов в textview, он отключит контекстное меню, поэтому теперь я использую метод, подобный приведенному ниже.
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
//fire my method here
}
Но он вызывает только метод, когда контекстное меню появляется после того, как пользователь долго нажимает несколько слов. Поэтому, когда пользователь долго нажимает пустое место, появляется только увеличительное стекло, я не могу запустить этот метод в то время.
Есть ли у кого-нибудь лучшие идеи? Благодарю!
//////Проблема решена //////
Благодаря @danh и @Beppe, я сделал это даже с жестом нажатия на UITextView. Я хотел показать панель шрифтов в текстовом виде, долгое нажатие.
@Сначала я подклассифицировал UITextview.
@interface LisgoTextView : UITextView {
BOOL pressing_;
}
@property (nonatomic) BOOL pressing;
@end
@interface LisgoTextView (private)
- (void)longPress:(UIEvent *)event;
@end
@implementation LisgoTextView
@synthesize pressing = pressing_;
//--------------------------------------------------------------//
#pragma mark -- Long Press Detection --
//--------------------------------------------------------------//
- (void)longPress:(UIEvent *)event {
if (pressing_) {
//post notification to show font edit bar
NSNotification *fontEditBarNotification = [NSNotification notificationWithName:@"fontEditBarNotification"
object:nil userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotification:fontEditBarNotification];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self performSelector:@selector(longPress:) withObject:event afterDelay:0.7];
pressing_ = YES;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
pressing_ = NO;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
pressing_ = NO;
}
@Я использовал задержку для разрешения конфликта с помощью жестов tap, который я реализовал в UITextView.
- (void)tapGestureOnTextView:(UITapGestureRecognizer *)sender {
//cancel here if long press was fired first
if (cancelTapGesture_) {
return;
}
//don't fire show font bar
cancelShowFontBar_ = YES;
[self performSelector:@selector(enableShowFontBar) withObject:nil afterDelay:1.0];
//method here
}
- (void)showFontEditBar {
//cancel here if tap gesture was fired first
if (cancelShowFontBar_) {
return;
}
if (fontEditBarExists_ == NO) {
//method here
//don't fire tap gesture
cancelTapGesture_ = YES;
[self performSelector:@selector(enableTapGesture) withObject:nil afterDelay:1.0];
}
}
- (void)enableTapGesture {
cancelTapGesture_ = NO;
}
- (void)enableShowFontBar {
cancelShowFontBar_ = NO;
}
Ответы
Ответ 1
Я обычно избегаю подклассификации, если явным образом предлагаю документы, это сработало для меня. Длительное нажатие и контекстное меню. Упс - ответ, просто загруженный @Beppe. Великие мысли думают одинаково: -)
@interface TextViewSubclass ()
@property(assign,nonatomic) BOOL pressing;
@end
@implementation TextViewSubclass
@synthesize pressing=_pressing;
- (void)longPress:(UIEvent *)event {
NSLog(@"long press");
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
self.pressing = YES;
[self performSelector:@selector(longPress:) withObject:event afterDelay:2.0];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
[NSObject cancelPreviousPerformRequestsWithTarget:self];
self.pressing = NO;
}
@end
Ответ 2
Это сработало для меня. Я просто хотел контролировать, что происходит, когда пользователь кратковременно нажимает ссылку
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
// check for long press event
BOOL isLongPress = YES;
for (UIGestureRecognizer *recognizer in self.commentTextView.gestureRecognizers) {
if ([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]){
if (recognizer.state == UIGestureRecognizerStateFailed) {
isLongPress = NO;
}
}
}
if (isLongPress) {
// user long pressed a link, do something
} else {
// user tapped on a link, do something
}
// return NO cause you dont want the normal behavior to occur
return NO;
}
Ответ 3
Адаптация Лукаса Чью отвечает за работу с iOS 9 (и 8). См. Комментарий в своем ответе.
Суть: инвертировать логику, начиная с "без длинного нажатия", а затем переключиться на "длинное нажатие", если хотя бы один UILongPressGestureRecognizer
находится в состоянии Began
.
BOOL isLongPress = NO;
for (UIGestureRecognizer *recognizer in textView.gestureRecognizers) {
if ([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
if (recognizer.state == UIGestureRecognizerStateBegan) {
isLongPress = YES;
}
}
}
По-прежнему немного хакерский, но теперь он работает для iOS 8 и 9.
Ответ 4
Это немного сложно, но это работает для меня.
Я добавляю подкласс UIButton поверх моего UITextView, проверяю длинные касания и передаю их UITextView следующим образом:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
isLongTouchDetected = NO;
[self performSelector:@selector(longTouchDetected) withObject:nil afterDelay:1.0];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (isLongTouchDetected == YES) {
[super touchesCancelled:touches withEvent:event];
} else {
[super touchesEnded:touches withEvent:event];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(longTouchDetected) object:nil];
}
}
- (void)longTouchDetected {
isLongTouchDetected = YES;
// pass long touch to UITextView
}
Ответ 5
Можете ли вы использовать метод textViewDidChangeSelection
протокола UITextViewDelegate
?
Ответ 6
Для SWIFT [Самый простой способ]
extension UITextField {
override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
if action == "paste:" {
return false
}
return super.canPerformAction(action, withSender: sender)
}
override public func addGestureRecognizer(gestureRecognizer: UIGestureRecognizer) {
if gestureRecognizer.isKindOfClass(UILongPressGestureRecognizer) {
gestureRecognizer.enabled = false
}
super.addGestureRecognizer(gestureRecognizer)
return
}
}
Выше код также работает для отключения опции "PASTE" в меню содержимого.