Search code examples
iosswiftuilabel

How add button in label?


I need to add a button at the end of the text to trigger an alert. The text can be in several lines How can I do that?

it should look like this enter image description here


Solution

  • Based on response https://stackoverflow.com/a/62150640/13642906

    let fullString = NSMutableAttributedString(string: "")
    let imageAttachment = NSTextAttachment()
    imageAttachment.image = UIImage(named: "awesomeIcon.png")
    let imageString = NSAttributedString(attachment: imageAttachment)
    
    fullString.append(NSAttributedString(string: " ", attributes: nil))
    fullString.append(imageString)
    fullString.append(NSAttributedString(string: " ", attributes: nil))
    
    self.text.isUserInteractionEnabled = true
    
    let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(showBlurbMessage(tapGesture:)))
    self.text.addGestureRecognizer(tapGesture!)
    

    in showBlurbMessage

     @objc func showBlurbMessage(tapGesture: UITapGestureRecognizer) {
        let location = (text.text?.count ?? 0)
        if tapGesture.didTapAttributedTextInLabel(label: self.text, inRange: NSRange(location: location - 2, length: 1)) {
    
            let alert = UIAlertController.createOkAlert(WithTitle: "", message: assessment.blurbDescription, okTitle: "Close")
            self.present(alert, animated: true, completion: nil)
        }
    }
    

    and extension for UITapGestureRecognizer

    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 textStorage = NSTextStorage(attributedString: label.attributedText!)
    
        // Configure layoutManager and textStorage
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)
    
        // Configure textContainer
        textContainer.lineFragmentPadding = 0.0 // 0.0 - left, 0.5 - center, 1 - right
        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)
    }
    }