如何不使用UITextView在UILabel中检测并创建可点击链接 [英] how do I detect and make clickable links in a UILabel NOT using UITextView

查看:151
本文介绍了如何不使用UITextView在UILabel中检测并创建可点击链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个聊天应用程序,并且出于性能原因,我需要使用UILabel而不是UITextView来显示聊天消息.我以前使用过TextView,但是在滚动时进行数据检测非常缓慢且不稳定.

I am building a chat app and for performance reasons I need to use UILabel's instead of UITextView's to display the chat messages. I have previously used TextView's but with data detection on the scrolling is very slow and choppy.

问题是当前没有链接/电话/地址等...用于UILabels的检测.

The problem is there is currently no link/phone/address etc... detection for UILabels.

我怎么知道字符串中的链接或电话号码在哪里,然后突出显示并在UILabel中使其可单击?

How can I know where a link or phone number exists in a string, and then highlight and make it clickable within a UILabel?

我读过很多关于如何为链接添加属性的文章,但是它们都是您知道链接范围或子字符串的链接.

I have read many articles on how to add attributes for links to do just that but they have all been links which you know the range or substring of.

我想获取任何字符串,找出是否包含链接以及这些链接在何处,然后将tapGestureRecognizer添加到标签中,并根据点击发生的位置执行操作.

I would like to take any string and find out whether is contains links and where those links are and then add the tapGestureRecognizer to the label and perform actions based on where the tap occurred.

我试图合并一个外部库(TTTAttributedLabel),但是我使用的是swift,发现swift的文档受到限制.我确实设法导入了库,但是未自动检测到链接.

I have tried to incorporate an external library (TTTAttributedLabel) but I'm using swift and found the documentation for swift to be limited. I did manage to import the library but the links are not being automatically detected.

推荐答案

参考源-

创建可点击的"; links在UILabel的NSAttributedString中?

它已转换为Swift 4.0

It is Converted into swift 4.0

尝试一下-

为UILabel创建一个子类,如下所示-

Create a sub class for UILabel like below -

Swift 4.0

class CustomLabel: 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
    }
}

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

override init(frame: CGRect) {
    super.init(frame: frame)
    setUp()
}
func setUp() {
    isUserInteractionEnabled = true
    layoutManager.addTextContainer(textContainer)
    textContainer.lineFragmentPadding = 0
    textContainer.lineBreakMode = lineBreakMode
    textContainer.maximumNumberOfLines = numberOfLines
    tapGesture.addTarget(self, action: #selector(CustomLabel.labelTapped(_:)))
    addGestureRecognizer(tapGesture)
}

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

@objc func labelTapped(_ gesture: UITapGestureRecognizer) {
    guard gesture.state == .ended else {
        return
    }
    let locationOfTouch = gesture.location(in: gesture.view)
    let textBoundingBox = layoutManager.usedRect(for: 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.characterIndex(for: locationOfTouchInTextContainer,
                                                        in: textContainer,  fractionOfDistanceBetweenInsertionPoints: nil)

    onCharacterTapped?(self, indexOfCharacter)
 }

}

在View控制器的viewDidLoad方法内,创建该类的实例,如下所示-

Within your viewDidLoad method of View controller create an instance of that class like below -

    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    let label = CustomLabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(label)
    view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[view]-|",
                                                       options: [], metrics: nil, views: ["view" : label]))
    view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "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: [NSAttributedStringKey : AnyObject] = [
        NSAttributedStringKey.foregroundColor : UIColor.blue, NSAttributedStringKey.underlineStyle : NSUnderlineStyle.styleSingle.rawValue as AnyObject,
        NSAttributedStringKey.link: "http://www.apple.com" as AnyObject ]
    attributedString.setAttributes(linkAttributes, range:linkRange)

    label.attributedText = attributedString

    label.onCharacterTapped = { label, characterIndex in

        // DO YOUR STUFF HERE
    }
}

这篇关于如何不使用UITextView在UILabel中检测并创建可点击链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆