-1

I have a UITextView that looks like so:

enter image description here

What I am looking to do is have "Terms and Agreement" underlined and present another controller when pressed and have "Privacy Policies" underlined and present another controller when pressed.

How would I go about doing that? I can't find anything online about it.

I was able to make them linkable like so:

let attributedString = NSMutableAttributedString(string: "I have read and agreed to all terms and agreements and Privacy Policies")

        attributedString.addAttribute(.link, value: "https://www.hackingwithswift.com", range: NSRange(location: 30, length: 20))
        attributedString.addAttribute(.link, value: "https://www.hackingwithswift.com", range: NSRange(location: 55, length: 16))

        conditionsText.attributedText = attributedString

but instead of making them thinks, I would like them to be gestures that would present another controller....and make them underlined I guess.

user979331
  • 11,039
  • 73
  • 223
  • 418

1 Answers1

0

You can achieve this many ways , here with UILabel

1- Extend UITapGestureRecognizer

extension UITapGestureRecognizer {

  func didTapLabel(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
    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.init(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.init(x:locationOfTouchInLabel.x - textContainerOffset.x, y:   locationOfTouchInLabel.y - textContainerOffset.y);
    let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

    return NSLocationInRange(indexOfCharacter, targetRange)
  }

}

2- Then detect clickable part

@IBAction func tapLabel(_ gesture: UITapGestureRecognizer) {
    let text = (myLabel.text)!
    let termsRange = (text as NSString).range(of: "Terms & Conditions")
    let privacyRange = (text as NSString).range(of: "Privacy Policy")

    if gesture.didTapLabel(label: myLabel, inRange: termsRange) {
        print("Tapped terms")
    } else if gesture.didTapLabel(label: myLabel, inRange: privacyRange) {
        print("Tapped privacy")
    } else {
        print("Tapped none")
    }
}

3- Usage

    var myLabel:UILabel!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    myLabel = UILabel()
    myLabel.frame = self.view.frame
    myLabel.isUserInteractionEnabled = true
    self.view.addSubview(myLabel!)
    myLabel.text = "By signing Terms & Conditions and Privacy Policy"
    let tapPress = UITapGestureRecognizer(target: self, action: #selector(self.tapLabel(_:)))           
    myLabel.addGestureRecognizer(tapPress)

}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • This sure looks a lot like code in the answers to [Create tap-able “links” in the NSAttributedString of a UILabel?](https://stackoverflow.com/questions/1256887/create-tap-able-links-in-the-nsattributedstring-of-a-uilabel) – rmaddy Jun 02 '18 at 20:23