30

What I want:

In an iPhone app, I'd like to show information in a tableView. In each cell, the text is like: John recently listen to music abcdefg.mp3. and if needed, the text can have two lines.

In the text, a.mp3 should be clickable so when the user touches the abcdefg.mp3 part, another page will be invoked. When user touches abcdefg.mp3, it will also have some effects, just like touching a button.

What I do:

I calculate the frame of the text, and I use a UIButton for abcdefg.mp3.

My Problem:

Sometimes abcdefg.mp3 may be in multiline, like:

abc is at the end of the first line

defg.mp3 is in second line.

What should I do in this case?

I've already searched about: Create tap-able "links" in the NSAttributedString of a UILabel? However I think it is not suitable here as the clickable text is all in one line in the sample.

Community
  • 1
  • 1
scorpiozj
  • 2,687
  • 5
  • 34
  • 60

8 Answers8

120

The most simple way is to just add a gesture recognizer to the actual view (be it a UILabel or some custom view of your own). In order for the gesture recognizer to work, the view must be set userInteractionEnabled.

Here's an example, assuming that your label view (or whatever it is) is called labelView:

UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(userTappedOnLink:)];
// if labelView is not set userInteractionEnabled, you must do so
[labelView setUserInteractionEnabled:YES];
[labelView addGestureRecognizer:gesture];

In this example, an action message will be sent to self and the message would be defined as

- (void)userTappedOnLink:(UIGestureRecognizer*)gestureRecognizer;

This works the same as wiring up any other UIControl subclass, such as a button.

Other notes: don't try to add the same gesture recognizer to multiple views, it won't work. Don't add more than one copy of the gesture recognizer to multiple views (it doesn't replace them, it just stacks them up and wastes memory). You should add the gesture recognizer when you initially create and configure your view.

For more information, see the documentation for UIGestureRecognizer.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Jason Coco
  • 77,985
  • 20
  • 184
  • 180
  • thanks~however, I think it is complicated if the clickable area is in two lines. – scorpiozj Jan 20 '11 at 05:08
  • @scorpiozj: Nope, not as long as it's all part of the same view. – Jason Coco Jan 20 '11 at 05:11
  • @Jason:I also want there will be some effect when user touches the clickable part. if there is line-break in the clickable part, it is not easy to handle it, is it? Or can you explain a little more? thanks. – scorpiozj Jan 20 '11 at 05:19
  • @scorpiozj: I guess I don't fully understand what you mean by 'line-break'. When you have a line-break, do you write the second line in a totally separate view? Can you post a screen shot? – Jason Coco Jan 20 '11 at 05:22
  • @Jason: your solution is easy to some extent. But I met another one: I separate the text"John recently listen to music abcdefg.mp3" into two:"John recently listen to music" and "abcdefg.mp3". if "abcdefg.mp3" must be shown in two-line, how can I use one control to hold it so that it can add a gestureRecognizer? – scorpiozj Jan 20 '11 at 05:26
  • @jason: OK~ it just like below: John recently listen to music i-like -sun.mp3 so it is not in a whole line, and the text "i-like-sun.mp3" should be clickable. – scorpiozj Jan 20 '11 at 05:30
  • @scorpiozj: Well, if you need that functionality and you're laying out these views yourself, simply add another UIGestureRecognizer instance to your second-line view that has the same target. So, if the user hits either bit, she will create the same action message. – Jason Coco Jan 20 '11 at 05:31
  • What about when the gesture recognizer is in a custom label within a tableview cell? In my case this breaks tableview scrolling. I have tried tapGesture.cancelsTouchesInView = false but it doesn't fix tableview scrolling. Any suggestions? – lucius degeer Nov 29 '17 at 15:15
11

Swift 4.2 Version:

var labelView = UILabel()
let gesture = UITapGestureRecognizer(target: self, action: #selector(userTappedOnLink))
// if labelView is not set userInteractionEnabled, you must do so
labelView.isUserInteractionEnabled = true
labelView.addGestureRecognizer(gesture)


@objc func userTappedOnLink() {
    print("clicked!")
}
Brainzzz
  • 3
  • 1
  • 3
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
2

Swift 2.0 version:

  func userTappedOnLink() {
    print("clicked!")
  }

///tap and link to FB page
let gesture = UITapGestureRecognizer(target: self, action: "userTappedOnLink")
// if labelView is not set userInteractionEnabled, you must do so
lblStaff.userInteractionEnabled = true
lblStaff.addGestureRecognizer(gesture)
Bill Chan
  • 3,199
  • 36
  • 32
1

You could also just put an "invisible Button" above, by using a custom button without text and images.

enter image description here

Chris
  • 4,403
  • 4
  • 42
  • 54
1

Sounds similar to what they accomplished in Twitteriffic with Fancy UILabels. Basically, Craig Hockenberry made his own custom "data detector", so that he could insert links within labels and multi-line text. See this question: Is there a way to create custom UIDataDetectorTypes?

Community
  • 1
  • 1
Reed Olsen
  • 9,099
  • 4
  • 37
  • 47
0

I think you can use textView and diable the scrolling. I did same for my project where I need to point to website addresses. just uncheck everything as shown in screenshot in 'scroll view' section in inspector window. disable scrolling

Alok C
  • 2,787
  • 3
  • 25
  • 44
0

By adding UITapGestureRecognizer to the label, to make UIlabel clickable.

Before adding the label to tapgesture, don't forgot to enable userinteraction for UIlabel

Here is the sample code:

//Tap Gesture
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(userTapped:)];
//Adding userinteraction for label
[labelName setUserInteractionEnabled:YES];
//Adding label to tap gesture
[labelName addGestureRecognizer:gesture];
legoscia
  • 39,593
  • 22
  • 116
  • 167
ashok
  • 1
  • 1
  • 1
0

This solution for clickable UILabel. It isn't for select link in text. Just nice solution in my opinion for clickable UILabel like UIButton:

#import <UIKit/UIKit.h>

@protocol ClickableLablelDelegate <NSObject>

@required
- (void)onClickLabel:(UILabel *) label;

@end

@interface ClickableLable : UILabel

@property (nonatomic, weak) id <ClickableLablelDelegate> delegate;

@end


#import "ClickableLable.h"

@implementation ClickableLable

-(void)awakeFromNib
{
    [super awakeFromNib];

    [self setUserInteractionEnabled:YES];
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self setBackgroundColor:[UIColor lightGrayColor]];
}

-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self setBackgroundColor:[UIColor clearColor]];

    if ([_delegate respondsToSelector:@selector(onClickLabel:)]) {
        [_delegate onClickLabel:self];
    }
}

-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self setBackgroundColor:[UIColor clearColor]];
}
Alex P
  • 41
  • 3