Create tap-able “links” in the NSAttributedString of a UILabel?

前端 未结 30 2652
半阙折子戏
半阙折子戏 2020-11-22 02:07

I have been searching this for hours but I\'ve failed. I probably don\'t even know what I should be looking for.

Many applications have text and in this text are web

30条回答
  •  伪装坚强ぢ
    2020-11-22 02:49

    TAGS #Swift2.0

    I take inspiration on - excellent - @NAlexN's answer and I decide to write by myself a wrapper of UILabel.
    I also tried TTTAttributedLabel but I can't make it works.

    Hope you can appreciate this code, any suggestions are welcome!

    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)
                    }
                }
            }
        }
    
    }
    

提交回复
热议问题