NSAttributedString click event in UILabel using swift

若如初见. 提交于 2019-12-03 03:13:37

There's no need to use a separate gesture recognizer as some of the answers state. Instead, you can use attributed text in combination with the UITextViewDelegate's textView:shouldInteractWithURL:inRange:interaction: method to achieve this, ex:

class ViewController: UIViewController, UITextViewDelegate {

    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let text = NSMutableAttributedString(string: "Already have an account? ")
        text.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 12), range: NSMakeRange(0, text.length))

        let selectablePart = NSMutableAttributedString(string: "Sign in!")
        selectablePart.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 12), range: NSMakeRange(0, selectablePart.length))
        // Add an underline to indicate this portion of text is selectable (optional)
        selectablePart.addAttribute(NSAttributedString.Key.underlineStyle, value: 1, range: NSMakeRange(0,selectablePart.length))
        selectablePart.addAttribute(NSAttributedString.Key.underlineColor, value: UIColor.black, range: NSMakeRange(0, selectablePart.length))
        // Add an NSLinkAttributeName with a value of an url or anything else
        selectablePart.addAttribute(NSAttributedString.Key.link, value: "signin", range: NSMakeRange(0,selectablePart.length))

        // Combine the non-selectable string with the selectable string
        text.append(selectablePart)

        // Center the text (optional)
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = NSTextAlignment.center
        text.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, text.length))

        // To set the link text color (optional)
        textView.linkTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.black, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12)]
        // Set the text view to contain the attributed text
        textView.attributedText = text
        // Disable editing, but enable selectable so that the link can be selected
        textView.isEditable = false
        textView.isSelectable = true
        // Set the delegate in order to use textView(_:shouldInteractWithURL:inRange)
        textView.delegate = self
    }

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {

        // **Perform sign in action here**

        return false
    }
}
Jarvis The Avenger

Instead of Label you can use textview to open View Controller or make substring clickable

  1. create attribute for string which you want to make clickable

    let linkAttributes = [
        NSLinkAttributeName: NSURL(string: "https://www.apple.com")!,
        NSForegroundColorAttributeName: UIColor.blue
        ] as [String : Any]
    
  2. Make your string attributed string

    let attributedString = NSMutableAttributedString(string:"My name is Jarvis")
    attributedString.setAttributes(linkAttributes, range: NSMakeRange(5, 10))
    

    you can give your custom range here.

  3. Add Attributed text to your textview

    YourTextView.attributedText = attributedString 
    
  4. Then implement following delegate method of textview to implement interaction for Url

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
    // here write your code of navigation 
    return false 
    }
    
  5. If you want to do it with label,click here (How to make a clickable link in an NSAttributedString for a)

Language update based on @Lindsey Scott answer :)

Swift 4

class ViewController: UIViewController, UITextViewDelegate {

    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let text = NSMutableAttributedString(string: "Already have an account? ")
        text.addAttribute(NSAttributedStringKey.font,
                          value: UIFont.systemFont(ofSize: 12),
                          range: NSRange(location: 0, length: text.length))

        let interactableText = NSMutableAttributedString(string: "Sign in!")
        interactableText.addAttribute(NSAttributedStringKey.font,
                                      value: UIFont.systemFont(ofSize: 12),
                                      range: NSRange(location: 0, length: interactableText.length))

        // Adding the link interaction to the interactable text
        interactableText.addAttribute(NSAttributedStringKey.link,
                                      value: "SignInPseudoLink",
                                      range: NSRange(location: 0, length: interactableText.length))

        // Adding it all together
        text.append(interactableText)

        // Set the text view to contain the attributed text
        textView.attributedText = text

        // Disable editing, but enable selectable so that the link can be selected
        textView.isEditable = false
        textView.isSelectable = true
        textView.delegate = self
    }

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {

        //Code to the respective action

        return false
    }
}

You can add a tap gesture recognizer's to your label/view, or you can embed a link with a custom URL protocol into your attributed string, use a UITextView, and turn on link detection. You would then need to implement the UITextView delegate method for responding to links.

EDIT:

I have a demo project called DatesInSwift (link) on Github that implements clickable links in a UITextView. Take a look at the UITextView delegate method textView(_:shouldInteractWithURL:inRange) in ViewController.swift. That's the method that tells the text view that it should respond to the URL.

Then you have to implement a UIApplicationDelegate method to handle the URL. The sample app uses application(_:openURL:sourceApplication:annotation), which was deprecated in iOS 9. For new development you should use application(_:openURL:options:) instead.

You will also need to add a CFBundleURLTypes / CFBundleURLSchemes entry to your info.plist to register a custom URL scheme (like myompany.myapp.loginURL) in order for clicking on an embedded URL to invoke your app.

You need to Use UITextView

class ViewController: UIViewController, UIGestureRecognizerDelegate {

@IBOutlet weak var textView: UITextView!

override func viewDidLoad() {
    super.viewDidLoad()
let attribute:NSAttributedString = NSAttributedString(string: "Already have an account? Sign in!", attributes: ["Tag" : true])
    textView.attributedText = attribute

    let tap = UITapGestureRecognizer(target: self, action: #selector(self.textTapped(_:)))
    tap.delegate = self
    textView.userInteractionEnabled = true
    textView.addGestureRecognizer(tap)

}

func textTapped(recognizer:UITapGestureRecognizer) {
    let textView:UITextView = recognizer.view as! UITextView

    // Location of the tap in text-container coordinates
    let layoutManager = textView.layoutManager
    var location:CGPoint = recognizer.locationInView(textView)

    location.x -= textView.textContainerInset.left
    location.y -= textView.textContainerInset.top

    var distance:CGFloat?
    // Find the character that's been tapped on
    let characterIndex = layoutManager.characterIndexForPoint(location, inTextContainer: textView.textContainer, fractionOfDistanceBetweenInsertionPoints: &distance!)
    if characterIndex < textView.textStorage.length{
        var range:NSRange?
        let value = textView.attributedText.attribute("Tag", atIndex: characterIndex, effectiveRange: &range!)
        if value {
           // add your code here
        }
    }
}
}
Vishal Sonawane

You can apply tapGesture to the label.

Create tap gesture recognizer:

let tapGesture = UITapGestureRecognizer(target: self, action: "YOUR_METHOD:")

Add gesture recognizer to label:

YOUR_LABEL.addGestureRecognizer(tapGesture)

Perform your tasks in this method:

func YOUR_METHOD(sender:UITapGestureRecognizer){
    // Perform your operations here.
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!