Как перехватить долгое нажатие на UITextView без отключения контекстного меню? - PullRequest
10 голосов
/ 20 марта 2012

Я хочу перехватить долгое нажатие на UITextview, но не хочу одновременно отключать опцию контекстного меню.

Если я использую распознаватель жестов в режиме просмотра текста, он отключит контекстное меню, поэтому я использую метод, описанный ниже.

- (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;
}

@ Я использовал задержку для разрешения конфликта жестом касания, реализованным в 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;
}

Ответы [ 6 ]

8 голосов
/ 20 марта 2012

Я обычно избегаю подклассов, если в документах не указано иное, это работает для меня. Длительное нажатие и контекстное меню. Ой - Ответ только что загружен @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
4 голосов
/ 02 июня 2015

Это сработало для меня. Я просто хотел контролировать, что происходит, когда пользователь нажимает или долго нажимает на ссылку

- (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 голосов
/ 24 сентября 2015

Адаптация ответа Лукаса Чве для работы на 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.

2 голосов
/ 20 марта 2012

Это немного сложно, но это работает для меня.

Я добавляю подкласс 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
}
0 голосов
/ 21 октября 2015

Для 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
    }
}

Выше код также имеет функцию для отключения опции «Вставить» в меню содержимого.

0 голосов
/ 20 марта 2012

Не могли бы вы использовать textViewDidChangeSelection метод протокола UITextViewDelegate?

...