许多应用程序都有文本,文本中是圆角矩形的web超链接,当我点击它们时,UIWebView就会打开。让我困惑的是,他们经常有自定义链接,例如,如果单词以#开头,它也是可点击的,应用程序通过打开另一个视图来响应。我该怎么做呢?是否可以用UILabel或者我需要UITextView或者其他什么?


当前回答

一般来说,如果我们想在UILabel显示的文本中有一个可点击的链接,我们需要解决两个独立的任务:

更改部分文本的外观,使其看起来像链接 检测和处理链接上的触摸(打开URL是一个特殊情况)

第一个很简单。从ios6开始,UILabel支持显示带属性的字符串。你所需要做的就是创建并配置一个NSMutableAttributedString实例:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"String with a link" attributes:nil];
NSRange linkRange = NSMakeRange(14, 4); // for the word "link" in the string above

NSDictionary *linkAttributes = @{ NSForegroundColorAttributeName : [UIColor colorWithRed:0.05 green:0.4 blue:0.65 alpha:1.0],
                                  NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle) };
[attributedString setAttributes:linkAttributes range:linkRange];

// Assign attributedText to UILabel
label.attributedText = attributedString;

就是这样!上面的代码使UILabel显示带有链接的String

现在我们应该检测这个链接上的触摸。其思想是捕获UILabel中的所有点击,并确定点击的位置是否足够接近链接。为了捕捉触摸,我们可以在标签中添加点击手势识别器。确保为标签启用userInteraction,默认情况下是关闭的:

label.userInteractionEnabled = YES;
[label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapOnLabel:)]]; 

现在最复杂的事情是:找出点击是否在显示链接的地方,而不是在标签的任何其他部分。如果我们有单行UILabel,这个任务可以通过硬编码链接显示的区域边界来相对容易地解决,但是让我们更优雅地解决这个问题,对于一般情况-多行UILabel,而不需要对链接布局有初步的了解。

其中一种方法是使用iOS 7中引入的Text Kit API功能:

// Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];

// Configure layoutManager and textStorage
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];

// Configure textContainer
textContainer.lineFragmentPadding = 0.0;
textContainer.lineBreakMode = label.lineBreakMode;
textContainer.maximumNumberOfLines = label.numberOfLines;

将创建和配置的NSLayoutManager, NSTextContainer和NSTextStorage实例保存在类的属性中(很可能是UIViewController的后代)-我们将在其他方法中需要它们。

现在,每当标签改变它的框架,更新textContainer的大小:

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    self.textContainer.size = self.label.bounds.size;
}

最后,检测点击是否恰好在链接上:

- (void)handleTapOnLabel:(UITapGestureRecognizer *)tapGesture
{
    CGPoint locationOfTouchInLabel = [tapGesture locationInView:tapGesture.view];
    CGSize labelSize = tapGesture.view.bounds.size;
    CGRect textBoundingBox = [self.layoutManager usedRectForTextContainer:self.textContainer];
    CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                              (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
    CGPoint locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
                                                         locationOfTouchInLabel.y - textContainerOffset.y);
    NSInteger indexOfCharacter = [self.layoutManager characterIndexForPoint:locationOfTouchInTextContainer
                                                            inTextContainer:self.textContainer
                                   fractionOfDistanceBetweenInsertionPoints:nil];
    NSRange linkRange = NSMakeRange(14, 4); // it's better to save the range somewhere when it was originally used for marking link in attributed string
    if (NSLocationInRange(indexOfCharacter, linkRange)) {
        // Open an URL, or handle the tap on the link in any other way
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://stackoverflow.com/"]];
    }
}

其他回答

标签# Swift2.0

我从- excellent - @NAlexN的回答中获得灵感,我决定自己写一个UILabel的包装器。 我还尝试了TTTAttributedLabel,但我不能使它工作。

希望你能欣赏这段代码,欢迎任何建议!

import Foundation

@objc protocol TappableLabelDelegate {
    optional func tappableLabel(tabbableLabel: TappableLabel, didTapUrl: NSURL, atRange: NSRange)
}

/// Represent a label with attributed text inside.
/// We can add a correspondence between a range of the attributed string an a link (URL)
/// By default, link will be open on the external browser @see 'openLinkOnExternalBrowser'

class TappableLabel: UILabel {

    // MARK: - Public properties -

    var links: NSMutableDictionary = [:]
    var openLinkOnExternalBrowser = true
    var delegate: TappableLabelDelegate?

    // MARK: - Constructors -

    override func awakeFromNib() {
        super.awakeFromNib()
        self.enableInteraction()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.enableInteraction()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    private func enableInteraction() {
        self.userInteractionEnabled = true
        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: Selector("didTapOnLabel:")))
    }

    // MARK: - Public methods -

    /**
    Add correspondence between a range and a link.

    - parameter url:   url.
    - parameter range: range on which couple url.
    */
    func addLink(url url: String, atRange range: NSRange) {
        self.links[url] = range
    }

    // MARK: - Public properties -

    /**
    Action rised on user interaction on label.

    - parameter tapGesture: gesture.
    */
    func didTapOnLabel(tapGesture: UITapGestureRecognizer) {
        let labelSize = self.bounds.size;

        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: CGSizeZero)
        let textStorage = NSTextStorage(attributedString: self.attributedText!)

        // configure textContainer for the label
        textContainer.lineFragmentPadding = 0
        textContainer.lineBreakMode = self.lineBreakMode
        textContainer.maximumNumberOfLines = self.numberOfLines
        textContainer.size = labelSize;

        // configure layoutManager and textStorage
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)

        // find the tapped character location and compare it to the specified range
        let locationOfTouchInLabel = tapGesture.locationInView(self)

        let textBoundingBox = layoutManager.usedRectForTextContainer(textContainer)
        let textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
            (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y)
        let locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
            locationOfTouchInLabel.y - textContainerOffset.y)
        let indexOfCharacter = layoutManager.characterIndexForPoint(locationOfTouchInTextContainer,
            inTextContainer:textContainer,
            fractionOfDistanceBetweenInsertionPoints: nil)

        for (url, value) in self.links {
            if let range = value as? NSRange {
                if NSLocationInRange(indexOfCharacter, range) {
                    let url = NSURL(string: url as! String)!
                    if self.openLinkOnExternalBrowser {
                        UIApplication.sharedApplication().openURL(url)
                    }
                    self.delegate?.tappableLabel?(self, didTapUrl: url, atRange: range)
                }
            }
        }
    }

}

基于Charles Gamble的答案,这是我使用的(我删除了一些让我困惑并给我错误索引的行):

- (BOOL)didTapAttributedTextInLabel:(UILabel *)label inRange:(NSRange)targetRange TapGesture:(UIGestureRecognizer*) gesture{
    NSParameterAssert(label != nil);

    // create instances of NSLayoutManager, NSTextContainer and NSTextStorage
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:label.attributedText];

    // configure layoutManager and textStorage
    [textStorage addLayoutManager:layoutManager];

    // configure textContainer for the label
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(label.frame.size.width, label.frame.size.height)];

    textContainer.lineFragmentPadding = 0.0;
    textContainer.lineBreakMode = label.lineBreakMode;
    textContainer.maximumNumberOfLines = label.numberOfLines;

    // find the tapped character location and compare it to the specified range
    CGPoint locationOfTouchInLabel = [gesture locationInView:label];
    [layoutManager addTextContainer:textContainer]; //(move here, not sure it that matter that calling this line after textContainer is set

    NSInteger indexOfCharacter = [layoutManager characterIndexForPoint:locationOfTouchInLabel
                                                           inTextContainer:textContainer
                                  fractionOfDistanceBetweenInsertionPoints:nil];
    if (NSLocationInRange(indexOfCharacter, targetRange)) {
        return YES;
    } else {
        return NO;
    }
}

以下是NAlexN的回答。

class TapabbleLabel: UILabel {

let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: CGSize.zero)
var textStorage = NSTextStorage() {
    didSet {
        textStorage.addLayoutManager(layoutManager)
    }
}

var onCharacterTapped: ((label: UILabel, characterIndex: Int) -> Void)?

let tapGesture = UITapGestureRecognizer()

override var attributedText: NSAttributedString? {
    didSet {
        if let attributedText = attributedText {
            textStorage = NSTextStorage(attributedString: attributedText)
        } else {
            textStorage = NSTextStorage()
        }
    }
}

override var lineBreakMode: NSLineBreakMode {
    didSet {
        textContainer.lineBreakMode = lineBreakMode
    }
}

override var numberOfLines: Int {
    didSet {
        textContainer.maximumNumberOfLines = numberOfLines
    }
}

/**
 Creates a new view with the passed coder.

 :param: aDecoder The a decoder

 :returns: the created new view.
 */
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setUp()
}

/**
 Creates a new view with the passed frame.

 :param: frame The frame

 :returns: the created new view.
 */
override init(frame: CGRect) {
    super.init(frame: frame)
    setUp()
}

/**
 Sets up the view.
 */
func setUp() {
    userInteractionEnabled = true
    layoutManager.addTextContainer(textContainer)
    textContainer.lineFragmentPadding = 0
    textContainer.lineBreakMode = lineBreakMode
    textContainer.maximumNumberOfLines = numberOfLines
    tapGesture.addTarget(self, action: #selector(TapabbleLabel.labelTapped(_:)))
    addGestureRecognizer(tapGesture)
}

override func layoutSubviews() {
    super.layoutSubviews()
    textContainer.size = bounds.size
}

func labelTapped(gesture: UITapGestureRecognizer) {
    guard gesture.state == .Ended else {
        return
    }

    let locationOfTouch = gesture.locationInView(gesture.view)
    let textBoundingBox = layoutManager.usedRectForTextContainer(textContainer)
    let textContainerOffset = CGPoint(x: (bounds.width - textBoundingBox.width) / 2 - textBoundingBox.minX,
                                      y: (bounds.height - textBoundingBox.height) / 2 - textBoundingBox.minY)        
    let locationOfTouchInTextContainer = CGPoint(x: locationOfTouch.x - textContainerOffset.x,
                                                 y: locationOfTouch.y - textContainerOffset.y)
    let indexOfCharacter = layoutManager.characterIndexForPoint(locationOfTouchInTextContainer,
                                                                inTextContainer: textContainer,
                                                                fractionOfDistanceBetweenInsertionPoints: nil)

    onCharacterTapped?(label: self, characterIndex: indexOfCharacter)
}
}

然后你可以在你的viewDidLoad方法中创建一个类的实例,就像这样:

let label = TapabbleLabel()
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[view]-|",
                                               options: [], metrics: nil, views: ["view" : label]))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[view]-|",
                                               options: [], metrics: nil, views: ["view" : label]))

let attributedString = NSMutableAttributedString(string: "String with a link", attributes: nil)
let linkRange = NSMakeRange(14, 4); // for the word "link" in the string above

let linkAttributes: [String : AnyObject] = [
    NSForegroundColorAttributeName : UIColor.blueColor(), NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleSingle.rawValue,
    NSLinkAttributeName: "http://www.apple.com"]
attributedString.setAttributes(linkAttributes, range:linkRange)

label.attributedText = attributedString

label.onCharacterTapped = { label, characterIndex in
    if let attribute = label.attributedText?.attribute(NSLinkAttributeName, atIndex: characterIndex, effectiveRange: nil) as? String,
        let url = NSURL(string: attribute) {
        UIApplication.sharedApplication().openURL(url)
    }
}

最好有一个自定义属性,以便在点击字符时使用。它是NSLinkAttributeName,但可以是任何东西你可以使用那个值去做其他的事情除了打开一个url,你可以做任何自定义动作。

是的,这是可能的,尽管一开始很困惑。我将进一步向您展示如何甚至可以单击文本中的任何区域。

使用这个方法,你可以有一个UI标签,如下所示:

多行友好 Autoshrink友好 可点击友好型(是的,甚至是单个角色) 斯威夫特5

步骤1:

使UILabel具有'Truncate Tail'的换行属性,并设置最小字体比例。

如果你不熟悉字体比例,请记住以下规则:

minimumFontSize/defaultFontSize = fontscale

在我的例子中,我希望7.2是最小字体大小,而我的起始字体大小是36。因此7.2 / 36 = 0.2

步骤2:

如果你不关心标签是可点击的,只是想要一个工作多行标签你就完成了!

然而,如果你想要标签是可点击阅读…

添加以下扩展我创建

extension UILabel {

    func setOptimalFontSize(maxFontSize:CGFloat,text:String){
        let width = self.bounds.size.width

        var font_size:CGFloat = maxFontSize //Set the maximum font size.
        var stringSize = NSString(string: text).size(withAttributes: [.font : self.font.withSize(font_size)])
        while(stringSize.width > width){
            font_size = font_size - 1
            stringSize = NSString(string: text).size(withAttributes: [.font : self.font.withSize(font_size)])
        }

        self.font = self.font.withSize(font_size)//Forcefully change font to match what it would be graphically.
    }
}

它的用法是这样的(只需将<Label>替换为您实际的标签名):

<Label>.setOptimalFontSize(maxFontSize: 36.0, text: formula)

这个扩展是需要的,因为自动收缩不会改变标签的'字体'属性后,它自动收缩,所以你必须通过计算它通过使用.size(withAttributes)函数模拟它的大小将与特定的字体。

这是必要的,因为检测在标签上单击的位置的解决方案需要知道确切的字体大小。

步骤3:

添加以下扩展名:

extension UITapGestureRecognizer {

    func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {
        // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: CGSize.zero)

        let mutableAttribString = NSMutableAttributedString(attributedString: label.attributedText!)
        mutableAttribString.addAttributes([NSAttributedString.Key.font: label.font!], range: NSRange(location: 0, length: label.attributedText!.length))

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 6
        paragraphStyle.lineBreakMode = .byTruncatingTail
        paragraphStyle.alignment = .center
        mutableAttribString.addAttributes([.paragraphStyle: paragraphStyle], range: NSMakeRange(0, mutableAttribString.string.count))

        let textStorage = NSTextStorage(attributedString: mutableAttribString)

        // Configure textContainer
        textContainer.lineFragmentPadding = 0.0
        textContainer.lineBreakMode = label.lineBreakMode
        textContainer.maximumNumberOfLines = label.numberOfLines

        // Configure layoutManager and textStorage
        layoutManager.addTextContainer(textContainer)

        textStorage.addLayoutManager(layoutManager)

        let labelSize = label.bounds.size

        textContainer.size = labelSize

        // Find the tapped character location and compare it to the specified range
        let locationOfTouchInLabel = self.location(in: label)

        let textBoundingBox = layoutManager.usedRect(for: textContainer)
        //let textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                              //(labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
        let textContainerOffset = CGPoint(x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x, y: (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y)

        //let locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
                                                        // locationOfTouchInLabel.y - textContainerOffset.y);
        let locationOfTouchInTextContainer = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x, y: locationOfTouchInLabel.y - textContainerOffset.y)

        let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        print("IndexOfCharacter=",indexOfCharacter)

        print("TargetRange=",targetRange)
        return NSLocationInRange(indexOfCharacter, targetRange)
    }

}

您将需要修改这个扩展为您的特定多行情况。在我的例子中,您将注意到我使用了段落样式。

let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 6
        paragraphStyle.lineBreakMode = .byTruncatingTail
        paragraphStyle.alignment = .center
        mutableAttribString.addAttributes([.paragraphStyle: paragraphStyle], range: NSMakeRange(0, mutableAttribString.string.count))

确保在扩展中将此更改为您实际使用的行间距,以便一切计算正确。

步骤4:

添加gestureRecognizer到标签在viewDidLoad或你认为合适的地方,就像这样(只需替换< label >与你的标签名再次:

<Label>.addGestureRecognizer(UITapGestureRecognizer(target:self, action: #selector(tapLabel(gesture:))))

这是我的tapLabel函数的一个简化示例(只需将<Label>替换为您的UILabel名称):

@IBAction func tapLabel(gesture: UITapGestureRecognizer) {
        guard let text = <Label>.attributedText?.string else {
            return
        }

        let click_range = text.range(of: "(α/β)")

        if gesture.didTapAttributedTextInLabel(label: <Label>, inRange: NSRange(click_range!, in: text)) {
           print("Tapped a/b")
        }else {
           print("Tapped none")
        }
    }

在我的例子中,我的字符串是BED = N * d * [RBE + (d / (α/β))],所以我只是在这种情况下得到α/β的范围。您可以在字符串中添加“\n”以添加换行符和任何您想要的文本,并测试此以在下一行中找到字符串,它仍然会找到它并正确地检测点击!

就是这样!你完成了。享受多行可点击标签。

这是一个Objective-C类别,它支持现有UILabel中的可点击链接。attributedText字符串,利用现有的NSLinkAttributeName属性。

@interface UILabel (GSBClickableLinks) <UIGestureRecognizerDelegate>
@property BOOL enableLinks;
@end

#import <objc/runtime.h>
static const void *INDEX;
static const void *TAP;

@implementation UILabel (GSBClickableLinks)

- (void)setEnableLinks:(BOOL)enableLinks
{
    UITapGestureRecognizer *tap = objc_getAssociatedObject(self, &TAP); // retreive tap
    if (enableLinks && !tap) { // add a gestureRegonzier to the UILabel to detect taps
        tap = [UITapGestureRecognizer.alloc initWithTarget:self action:@selector(openLink)];
        tap.delegate = self;
        [self addGestureRecognizer:tap];
        objc_setAssociatedObject(self, &TAP, tap, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // save tap
    }
    self.userInteractionEnabled = enableLinks; // note - when false UILAbel wont receive taps, hence disable links
}

- (BOOL)enableLinks
{
    return (BOOL)objc_getAssociatedObject(self, &TAP); // ie tap != nil
}

// First check whether user tapped on a link within the attributedText of the label.
// If so, then the our label's gestureRecogizer will subsequently fire, and open the corresponding NSLinkAttributeName.
// If not, then the tap will get passed along, eg to the enclosing UITableViewCell...
// Note: save which character in the attributedText was clicked so that we dont have to redo everything again in openLink.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer != objc_getAssociatedObject(self, &TAP)) return YES; // dont block other gestures (eg swipe)

    // Re-layout the attributedText to find out what was tapped
    NSTextContainer *textContainer = [NSTextContainer.alloc initWithSize:self.frame.size];
    textContainer.lineFragmentPadding = 0;
    textContainer.maximumNumberOfLines = self.numberOfLines;
    textContainer.lineBreakMode = self.lineBreakMode;
    NSLayoutManager *layoutManager = NSLayoutManager.new;
    [layoutManager addTextContainer:textContainer];
    NSTextStorage *textStorage = [NSTextStorage.alloc initWithAttributedString:self.attributedText];
    [textStorage addLayoutManager:layoutManager];

    NSUInteger index = [layoutManager characterIndexForPoint:[gestureRecognizer locationInView:self]
                                             inTextContainer:textContainer
                    fractionOfDistanceBetweenInsertionPoints:NULL];
    objc_setAssociatedObject(self, &INDEX, @(index), OBJC_ASSOCIATION_RETAIN_NONATOMIC); // save index

    return (BOOL)[self.attributedText attribute:NSLinkAttributeName atIndex:index effectiveRange:NULL]; // tapped on part of a link?
}

- (void)openLink
{
    NSUInteger index = [objc_getAssociatedObject(self, &INDEX) unsignedIntegerValue]; // retrieve index
    NSURL *url = [self.attributedText attribute:NSLinkAttributeName atIndex:index effectiveRange:NULL];
    if (url && [UIApplication.sharedApplication canOpenURL:url]) [UIApplication.sharedApplication openURL:url];
}

@end 

这将通过一个UILabel子类(即没有objc_getAssociatedObject的混乱)来完成,但如果你像我一样,你更喜欢避免不必要的(第三方)子类,只是为了给现有的UIKit类添加一些额外的功能。此外,这有一个漂亮的地方,它添加了任何现有的UILabel的点击链接,例如现有的UITableViewCells!

我已经试着让它尽可能的最小化侵入性通过使用现有的NSLinkAttributeName属性在NSAttributedString中已经可用。所以很简单:

NSURL *myURL = [NSURL URLWithString:@"http://www.google.com"];
NSMutableAttributedString *myString = [NSMutableAttributedString.alloc initWithString:@"This string has a clickable link: "];
[myString appendAttributedString:[NSAttributedString.alloc initWithString:@"click here" attributes:@{NSLinkAttributeName:myURL}]];
...
myLabel.attributedText = myString;
myLabel.enableLinks = YES; // yes, that's all! :-)

基本上,它通过添加一个UIGestureRecognizer到你的UILabel来工作。最难的工作是在gestureRecognizerShouldBegin:中完成的,它会重新布局attributedText字符串,以找出被点击的字符。如果这个字符是NSLinkAttributeName的一部分,那么手势识别器将随后触发,检索相应的URL(从NSLinkAttributeName值),并打开每个通常的[UIApplication。sharedApplication openURL:url进程。

注意:通过在gestureRecognizerShouldBegin:中执行所有这些操作,如果你没有碰巧点击标签中的链接,事件就会被传递。因此,例如,你的UITableViewCell将捕获点击链接,但其他行为正常(选择单元格,取消选择,滚动,…)。

我把它放在了GitHub仓库里。 改编自Kai Burghardt的SO帖子。