iOS 13.1 UITextView delegate method shouldInteract called when scrolling on attachment

前端 未结 2 628
情深已故
情深已故 2021-02-13 04:40

I\'m using the UITextView delegate method to do some custom work like opening a in-app browser when user tapping on URL or attachment:



        
相关标签:
2条回答
  • 2021-02-13 04:55

    It looks like textView:shouldInteractWithURL:inRange:interaction: ends up being called 3 times during a normal link press (if you always return YES).

    A couple of times to see if the default action can be invoked (assuming that's what canInvokeDefaultAction is about):

      * frame #0: 0x0000000101610038 Engage`::-[BubbleMessageCell textView:shouldInteractWithURL:inRange:interaction:](self=0x00007ff19e999600, _cmd="textView:shouldInteractWithURL:inRange:interaction:", textView=0x00007ff19eaf2000, url="https://9to5mac.com/2019/09/07/imessage-for-business/", characterRange=location=235, length=33, interaction=UITextItemInteractionInvokeDefaultAction) at BubbleMessageCell.mm:623:5
        frame #1: 0x00007fff478b2902 UIKitCore`-[UITextView _allowInteraction:forTextInteractableItem:] + 532
        frame #2: 0x00007fff46b8ba1c UIKitCore`-[_UITextInteractableItem _allowInteraction:] + 135
        frame #3: 0x00007fff46b8b84d UIKitCore`-[_UITextInteractableItem canInvokeDefaultAction] + 97
        frame #4: 0x00007fff477f76f7 UIKitCore`-[_UITextSimpleLinkInteraction _canBeginInteractionSessionForLinkAtPoint:asTap:] + 127
        frame #5: 0x00007fff477f75c7 UIKitCore`-[_UITextSimpleLinkInteraction interaction_gestureRecognizer:shouldReceiveTouch:] + 217
        frame #6: 0x00007fff477f6506 UIKitCore`-[UITextInteraction gestureRecognizer:shouldReceiveTouch:] + 127
        frame #7: 0x00007fff47133669 UIKitCore`-[UIGestureRecognizer _delegateShouldReceiveTouch:] + 493
    
      * frame #0: 0x0000000101610038 Engage`::-[BubbleMessageCell textView:shouldInteractWithURL:inRange:interaction:](self=0x00007ff19e999600, _cmd="textView:shouldInteractWithURL:inRange:interaction:", textView=0x00007ff19eaf2000, url="https://9to5mac.com/2019/09/07/imessage-for-business/", characterRange=location=235, length=33, interaction=UITextItemInteractionInvokeDefaultAction) at BubbleMessageCell.mm:623:5
        frame #1: 0x00007fff478b2902 UIKitCore`-[UITextView _allowInteraction:forTextInteractableItem:] + 532
        frame #2: 0x00007fff46b8ba1c UIKitCore`-[_UITextInteractableItem _allowInteraction:] + 135
        frame #3: 0x00007fff46b8b84d UIKitCore`-[_UITextInteractableItem canInvokeDefaultAction] + 97
        frame #4: 0x00007fff477f77fb UIKitCore`-[_UITextSimpleLinkInteraction _beginInteractionSessionForLinkAtPoint:asTap:] + 167
        frame #5: 0x00007fff477f74d0 UIKitCore`-[_UITextSimpleLinkInteraction interaction_gestureRecognizerShouldBegin:] + 196
        frame #6: 0x00007fff477f62a1 UIKitCore`-[UITextInteraction gestureRecognizerShouldBegin:] + 307
        frame #7: 0x00007fff471339b6 UIKitCore`-[UIGestureRecognizer _shouldBegin] + 413
    

    And then finally when the gesture is actually recognized:

      * frame #0: 0x0000000101610038 Engage`::-[BubbleMessageCell textView:shouldInteractWithURL:inRange:interaction:](self=0x00007ff19e999600, _cmd="textView:shouldInteractWithURL:inRange:interaction:", textView=0x00007ff19eaf2000, url="https://9to5mac.com/2019/09/07/imessage-for-business/", characterRange=location=235, length=33, interaction=UITextItemInteractionInvokeDefaultAction) at BubbleMessageCell.mm:623:5
        frame #1: 0x00007fff478b2902 UIKitCore`-[UITextView _allowInteraction:forTextInteractableItem:] + 532
        frame #2: 0x00007fff46b8ba1c UIKitCore`-[_UITextInteractableItem _allowInteraction:] + 135
        frame #3: 0x00007fff46b8b8cc UIKitCore`-[_UITextInteractableItem invokeDefaultAction] + 94
        frame #4: 0x00007fff477f6f32 UIKitCore`-[_UITextSimpleLinkInteraction linkTapped:] + 188
        frame #5: 0x00007fff4712bbfb UIKitCore`-[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 44
    

    When scrolling, only the first call happens.

    This is presumably an iOS 13.1 change, where it checks sooner to see if the link can be interacted with. If you want textView:shouldInteractWithURL:inRange:interaction: to have side effects, you only want to do them when the gesture is actually recognized.

    What appears to work for us to to check textView.gestureRecognizers and only do the custom actions if a tap gesture was being recognized.

        BOOL recognizedTapGesture = NO;
        for (UIGestureRecognizer *recognizer in textView.gestureRecognizers) {
            if ([recognizer isKindOfClass:UITapGestureRecognizer.class] && recognizer.state == UIGestureRecognizerStateEnded) {
                recognizedTapGesture = YES;
                break;
            }
        }
        if (!recognizedTapGesture) {
            // Tap gesture is not being recognized, this must be an early 
            // check when touches begin. Leave the link handling alone.
            return YES;
        }
    
        // Do custom action here
    
        return NO;
    
    0 讨论(0)
  • 2021-02-13 04:58

    I just encountered the same frustrating issue in iOS 13. Here is a fix that worked for me in Swift inspired by Mihai's answer above.

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    
        switch interaction {
        case .invokeDefaultAction:
            if textView.gestureRecognizers?.contains(where: {$0.isKind(of: UITapGestureRecognizer.self) && $0.state == .ended}) == true {
    
                // Handle your custom logic here.
    
                return false
            }
            return true
        case .presentActions:
    
            // Default action.
    
            return true
        case .preview:
    
            // Default action.
    
            return true
        @unknown default:
            fatalError()
        }
    }
    
    0 讨论(0)
提交回复
热议问题