简体   繁体   中英

Tap Gesture on TextView and its super view does not work in iOS 11

I have a view with made something like this View 1 and it is having a subview of UITextView.

I've had to enable links and date events in my textview for which i have enabled user interaction on it. However i need some tap handling on it's super view ie View 1 , So i have a tap gesture enabled on the super view as well.

With this setting i would get link detection and handling in the text view and if i did not tap on a link the tap gesture would pass to super view by itself. However in iOS 11 this seems to be broken and i can never seem to get the tap gesture passed to super view. Can someone please help me get back the same behaviour on iOS 11 the way it was in previous versions.

The code I have written is something like this -

  [V addSubView:tv];
  [tv setFrame:[self calculateFrameForTextView]];
  [tv setUserInteractionEnabled:YES];
  [tv setEditable:NO];
  [tv setSelectable:YES];
  [tv setDataDetectorTypes:UIDataDetectorTypeAll];

  UITapGestureRecognizer *tap= [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSomething)];
  [V addGestureRecognizer:tap];


   ............................
   |    UIView (V)             |
   |                           |
   |   |-------------------|   |
   |   |  UITextView  (tv) |   |
   |   |...................|   |
   .............................

If I tap on any content on Text View which is not a link/other data detector type i want "doSomething" to be called the selector registered with tap on the super view. This behaviour was working in versions < iOS11

I finally figure out one solution to detect touch from text view works in iOS 11. Not yet tested on earlier versions.
Tap on the link or attachment won't trigger the closure.

/// Provide a callback when single tapping on a non-attachment area
@IBDesignable class UITextViewFixed: UITextView {

    var didTappedOnAreaBesidesAttachment: (() -> ())? = nil

    // A single tap won't move.
    private var isTouchMoved = false

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesMoved(touches, with: event)

        isTouchMoved = true
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)

        if !isTouchMoved &&
            !isTapOnAttachment(touches.first!.location(in: self)) &&
            selectedRange.length == 0 {
            didTappedOnAreaBesidesAttachment?()
        }

        isTouchMoved = false
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesCancelled(touches, with: event)

        // `UITextView` will cancel the touch then starting selection

        isTouchMoved = false
    }

    private func isTapOnAttachment(_ point: CGPoint) -> Bool {
        let range = NSRange(location: 0, length: attributedText.length)
        var found = false
        attributedText.enumerateAttribute(.attachment, in: range, options: []) { (value, effectiveRange, stop) in
            guard value is NSTextAttachment else {
                return
            }
            let rect = layoutManager.boundingRect(forGlyphRange: effectiveRange, in: textContainer)
            if rect.contains(point) {
                found = true
                stop.pointee = true
            }
        }
        return found
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM