Iphone 如何在不禁用关联菜单的情况下拦截长按UITextView?

Iphone 如何在不禁用关联菜单的情况下拦截长按UITextView?,iphone,uitextview,uigesturerecognizer,Iphone,Uitextview,Uigesturerecognizer,我想截取UITextview上的长按,但不想同时禁用关联菜单选项 如果我在textview上使用手势识别器,它将禁用上下文菜单,因此我现在使用下面的方法 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { //fire my method here } 但是,它只在用户长按某些单词后出现上下文菜单时触发该方法。因此,当用户长按一个空格时,只有放大镜显示,此时我无法启动该方法 有人有更好的主意吗?谢谢 ////

我想截取UITextview上的长按,但不想同时禁用关联菜单选项

如果我在textview上使用手势识别器,它将禁用上下文菜单,因此我现在使用下面的方法

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {    
    //fire my method here
}
但是,它只在用户长按某些单词后出现上下文菜单时触发该方法。因此,当用户长按一个空格时,只有放大镜显示,此时我无法启动该方法

有人有更好的主意吗?谢谢

//////问题解决了//////

多亏了@danh和@Beppe,我在UITextView上用轻触手势实现了平衡。我想通过长按在textview上显示字体栏

@首先,我对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;
}

您可以使用
UITextViewDelegate
协议的
textViewDidChangeSelection
方法吗?

这有点棘手,但对我来说很有效

我在UITextView的顶部添加了UIButton的子类,检查是否有长时间接触,并通过以下方式将其传递给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
}

我通常避免子类化,除非文档明确指出,这对我来说很有效。长按和上下文菜单。哎哟-回答刚刚由@Beppe加载。英雄所见略同:-)


这对我有用。我只是想控制当用户点击或长按链接时会发生什么

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

将Lucas Chwe的答案改编为iOS 9(和iOS 8)。见他的回答中的评论

要点:从“no long press”(无长按)开始反转逻辑,然后如果至少有一个
UILongPressGestureRecognitor
处于
Start
状态,则切换到“long press detected”(长按检测)

BOOL isLongPress = NO;
for (UIGestureRecognizer *recognizer in textView.gestureRecognizers) {
    if ([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
        if (recognizer.state == UIGestureRecognizerStateBegan) {
            isLongPress = YES;
        }
    }
}

仍然有点老土,但现在正在为iOS 8和iOS 9工作。

用于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
    }
}

上面的代码还具有禁用内容菜单中“粘贴”选项的功能。

尽管我仍在努力解决与在UITextview上实现的TapPaste的冲突,但这就是我问题的答案。非常感谢。我成功地解决了冲突,所以在答案部分写下了工作缺陷。我没有尝试过这种方法,因为我是UITextview的子类。但是,这也必须起作用。谢谢。我想我需要选择文本来截取它:(这对我来说在iOS 9中是失败的。当记录识别器时,有一个新的神秘识别器处于
失败
状态。我切换了逻辑,在
开始
状态下寻找至少一个长按识别器。仍然有点黑客,但现在在iOS 8和9中工作。请参阅下面的文章,了解新代码。)(单独发布以便能够格式化代码)。我认为这不起作用的原因是
UIPreviewGetureRecognizer
,它是
UILongPressGestureRecognizer
的子类,但该子类失败。因此我认为与其使用
isKindOfClass
,不如使用
isMemberOfClass
不检查子类。
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
    }
}