Tapping URL doesn't work in TTTAttributedLabel while there is a UITapGestureRecognizer on its superview
Asked Answered
S

6

19

There is container view and a UITapGestureRecognizer on it. And it also has a subview which kind of TTTAttributedLabel.

When I remove the gesture recognizer from the container view, the delegate method of TTTAttributedLabelDelegate

- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url can be called.

When I add the gesture recognizer on container view. Only its action method gets called. The delegate method of TTTAttributedLabelDelegate won't be called.

Now I need the delegate method to be called when I tap on a link in TTTAttributedLabel, and action method to called when I tap on other area of container view.

Thanks.

Spikes answered 12/3, 2014 at 7:42 Comment(0)
S
15

use this gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch for detection your event.

- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
      if ([touch.view isKindOfClass:[TTTAttributedLabel class]])
      {
           return FALSE;
      }
      else
      {

         return TRUE;
      }
}

you can also use if ([touch.view isKindOfClass:[UIControl class]]) for all UIControl e.g Button even detect with UIGestureRecognizer. hope this help's you

Soph answered 12/3, 2014 at 7:50 Comment(0)
P
8

I tried @Nitin's solution but it has a problem as @n00bProgrammer pointed out. Furthermore, user experience became very bad. I had to tap several times to fire tapGesture which is added on a superView.

Here you have a better solution. TTTAttributedLabel has a useful instance method like below.

- (BOOL)containslinkAtPoint:(CGPoint)point

This returns whether an NSTextCheckingResult is found at the given point.

So, use the following code snippet then only link added part of the text will be working as a tappable link and the rest of area will fire your tapGesture as you desired. User experience is excellent as well.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if ([yourTTTAttributedLabel containslinkAtPoint:[touch locationInView:yourTTTAttributedLabel]])
        return FALSE;
    else
        return TRUE;    
}
Pires answered 12/1, 2016 at 21:58 Comment(0)
E
3

Set the cancelsTouchesInView property of the gesture recognizer to NO.

gestureRecognizer.cancelsTouchesInView = NO;
Empathic answered 9/8, 2016 at 10:25 Comment(1)
Found your answer very late. Unfortunately spent 5 hours before found it. Thanks man!Enravish
R
1

@Nitin's answer is somewhat correct provided you do not want the tap gesture to work if user taps on part of your label, which is not a link. In case your label has text other than just the link, I suggest you do the following :

  • Create a new delegate method (like "handleSingleTap") in the TTTAttributedLabel.h file as @optional.

  • In TTTAttributedLabel.m find the touchesEnded method. Here you have an if (self.activeLink) condition.

  • Create an else case for this condition as follows :

    else {
    
        if ([self.delegate respondsToSelector:@selector(handleSingleTap)]) {
    
            [self.delegate handleSingleTap];            
        }
    }
    
  • Override this new delegate method in your class where you use the label.

This way, if the user taps a link, the if takes care of handling link selection. If user taps text other than link, the else will call the method in your class (which is the target method for your tapGesture).

Also, remove the tapGesture from your view, or use @Nitin's code to NOT handle taps on your label, and let the label handle the tap on it's own.

Reichard answered 12/3, 2014 at 8:19 Comment(0)
I
0

Nitin's suggestion didn't work for me (uncertain why), but this did:

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    if let touch = touches.first as? UITouch {
        if touch.view !== self.myTTTAttributedLabel {
            // Handle container view tap
        }
    }
    super.touchesBegan(touches, withEvent: event)
}

You must also remove the gesture recognizer from your container view and handle those taps in the if-clause above instead.

Illogicality answered 8/5, 2015 at 11:23 Comment(0)
A
0

here is my solution

override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view == self.lblContent {
        gr?.isEnabled = false
        return false
    }
    else {
        gr?.isEnabled = true
        return true
    }
}

gr is my view's gesture and lblContent(TTTAttributedLabel) is my label when i click label both gesture was working same time (label's gesture and view's gesture) so I have solved this problem with above code

what i have tried before solution

cancelsTouchesInView = false
isUserInteractionEnabled = true
Albatross answered 3/2, 2020 at 14:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.