Swift : tap on a part of text of UILabel

前端 未结 7 982
北海茫月
北海茫月 2020-12-02 21:36

I have a problem that \"boundingRectForGlyphRange\" always returns CGRect.zero \"0.0, 0.0, 0.0, 0.0\". \"boundingRectForGlyphRange\" is not working. For example, I am coding

7条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-02 22:02

    To enable multiline tappable & don't want to subclass the UILabel then:

    • Write Extension function for UITapGestureRecognizer
    extension UITapGestureRecognizer {
    
       func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {
           guard let attributedText = label.attributedText else { return false }
    
           let mutableStr = NSMutableAttributedString.init(attributedString: attributedText)
           mutableStr.addAttributes([NSAttributedString.Key.font : label.font!], range: NSRange.init(location: 0, length: attributedText.length))
    
           // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
           let layoutManager = NSLayoutManager()
           let textContainer = NSTextContainer(size: CGSize.zero)
           let textStorage = NSTextStorage(attributedString: mutableStr)
    
           // Configure layoutManager and textStorage
           layoutManager.addTextContainer(textContainer)
           textStorage.addLayoutManager(layoutManager)
    
           // Configure textContainer
           textContainer.lineFragmentPadding = 0.0
           textContainer.lineBreakMode = label.lineBreakMode
           textContainer.maximumNumberOfLines = label.numberOfLines
           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 = 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 = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x,
                                                        y: locationOfTouchInLabel.y - textContainerOffset.y);
           let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
           return NSLocationInRange(indexOfCharacter, targetRange)
       }
    
    }
    
    • Configure your UILable
    label.text = "For any type of query please call us on +9186XXX-XXXXX or mail us at example@yourdomain.com"
    label.isUserInteractionEnabled = true
    label.lineBreakMode = .byWordWrapping
    let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(tappedOnLabel(_:)))
    tapGesture.numberOfTouchesRequired = 1
    label.addGestureRecognizer(tapGesture)
    
    • Add the gesture recogniser selector function:
    @objc func tappedOnLabel(_ gesture: UITapGestureRecognizer) {
        guard let text = label.text else { return }
        let numberRange = (text as NSString).range(of: "+9186XXX-XXXXX")
        let emailRange = (text as NSString).range(of: "example@yourdomain.com")    
        if gesture.didTapAttributedTextInLabel(label: self.label, inRange: numberRange) {
            print("number tapped")
        } else if gesture.didTapAttributedTextInLabel(label: self.label, inRange: emailRange) {
            print("Email tapped")
        }
    }
    

提交回复
热议问题