3

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

sergey_s
  • 113
  • 11

2 Answers2

3

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)
}
}
sergey_s
  • 113
  • 11
1

You can use NSTextAttachment to add image at the end of text.

let fullString = NSMutableAttributedString(string: "Text")

// Create our NSTextAttachment
let imageAttachment = NSTextAttachment()
imageAttachment.image = UIImage(named: "awesomeIcon.png")

// Wrap the attachment in its own attributed string so we can append it
let imageString = NSAttributedString(attachment: imageAttachment)

// Add the NSTextAttachment
fullString.append(imageString)

// Draw the result in a label
yourLabel.attributedText = fullString

and then add UITapGestureRecognizer to trigger action after tap.

let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(showAlert(tapGesture:)))
yourLabel.addGestureRecognizer(tapGesture)

@objc func showAlert(tapGesture: UITapGestureRecognizer){
    // Show alert
}
Denis Kakačka
  • 697
  • 1
  • 8
  • 21
  • 1
    good way! But I would like UITapGestureRecognizer to listen only to the image. so trying to add a button – sergey_s Jun 02 '20 at 13:02