如何更改UILabel中链接的颜色?

时间:2017-12-26 21:23:53

标签: ios swift

我想更改UILabel中链接的颜色。我已经找到了大量过去关于如何为UITextView执行此操作的问题,以及过去在Obj-C中回答的问题(但是无法将这些问题转换为Swift,因为Obj-c中存在的属性不再像NSMutableAttributedString那样.linkTextAttribtues例如)。 但我找不到如何为UILabel和Swift 4做到这一点。

5 个答案:

答案 0 :(得分:4)

您可以在html字符串中配置href链接,然后将其转换为属性字符串:

let html = "<a href=\"https://www.google.com\" style=\"color: rgb(255,0,0)\">Link to Google</a>"
do {
    label.attributedText = try NSAttributedString(data: Data(html.utf8), options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch {
    print(error)
}

答案 1 :(得分:0)

尝试使用Objective {C桥接它KILabel并启用链接检测

答案 2 :(得分:0)

对于默认的 NSAttributedString.Key。链接 颜色将为蓝色。
如果您需要链接的自定义颜色,则可以将属性设置为 NSAttributedString.Key。附件 ,而不是 .link 并设置前景和下划线颜色,如下所示:

let linkCustomAttributes = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 14),
                            NSAttributedString.Key.foregroundColor: UIColor.red,
                            NSAttributedString.Key.underlineColor: UIColor.magenta,
                            NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue,
                            NSAttributedString.Key.attachment: URL(string: "https://www.google.com")] as [NSAttributedString.Key : Any]

如果您需要处理链接的触摸,则可以使用以下自定义标签类:

import UIKit

public protocol UILabelTapableLinksDelegate: NSObjectProtocol {
    func tapableLabel(_ label: UILabelTapableLinks, didTapUrl url: String, atRange range: NSRange)
}

public class UILabelTapableLinks: UILabel {

    private var links: [String: NSRange] = [:]
    private(set) var layoutManager = NSLayoutManager()
    private(set) var textContainer = NSTextContainer(size: CGSize.zero)
    private(set) var textStorage = NSTextStorage() {
        didSet {
            textStorage.addLayoutManager(layoutManager)
        }
    }

    public weak var delegate: UILabelTapableLinksDelegate?

    public override var attributedText: NSAttributedString? {
        didSet {
            if let attributedText = attributedText {
                textStorage = NSTextStorage(attributedString: attributedText)
                findLinksAndRange(attributeString: attributedText)
            } else {
                textStorage = NSTextStorage()
                links = [:]
            }
        }
    }

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

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

    public override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

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

    private func setup() {
        isUserInteractionEnabled = true
        layoutManager.addTextContainer(textContainer)
        textContainer.lineFragmentPadding = 0
        textContainer.lineBreakMode = lineBreakMode
        textContainer.maximumNumberOfLines  = numberOfLines
    }

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

    private func findLinksAndRange(attributeString: NSAttributedString) {
        links = [:]
        let enumerationBlock: (Any?, NSRange, UnsafeMutablePointer<ObjCBool>) -> Void = { [weak self] value, range, isStop in
            guard let strongSelf = self else { return }
            if let value = value {
                let stringValue = "\(value)"
                strongSelf.links[stringValue] = range
            }
        }
        attributeString.enumerateAttribute(.link, in: NSRange(0..<attributeString.length), options: [.longestEffectiveRangeNotRequired], using: enumerationBlock)
        attributeString.enumerateAttribute(.attachment, in: NSRange(0..<attributeString.length), options: [.longestEffectiveRangeNotRequired], using: enumerationBlock)
    }

    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let locationOfTouch = touches.first?.location(in: self) else {
            return
        }
        textContainer.size = bounds.size
        let indexOfCharacter = layoutManager.glyphIndex(for: locationOfTouch, in: textContainer)
        for (urlString, range) in links where NSLocationInRange(indexOfCharacter, range) {
            delegate?.tapableLabel(self, didTapUrl: urlString, atRange: range)
            return
        }            
    }
}

代码中的设置标签:

customLabel.attributedText = <<Your attributed text with custom links>>
customLabel.delegate = self

实施代表:

extension YourClass: UILabelTapableLinksDelegate {
    func tapableLabel(_ label: UILabelTapableLinks, didTapUrl url: String, atRange range: NSRange) {
        print("didTapUrl: ", url)
    }
}

答案 3 :(得分:0)

上面的答案是正确的,但是将.attachment设置为URL不会打开URL,至少对我来说不是(使用iOS 13)。 .link的颜色不受.foregroundColorNSAttributedString的影响,而是受tintColor的{​​{1}}的影响

UITextView

应将链接的文本和下划线设置为绿色

答案 4 :(得分:-1)

使用UITextView代替UILabel并编写类似以下内容更容易:

textView.linkTextAttributes = [
        .foregroundColor: UIColor.red,
        .underlineColor: UIColor.red,
        .underlineStyle: NSUnderlineStyle.single.rawValue
    ]