NSAttributedString click event in UILabel using swift

前端 未结 7 1892
感情败类
感情败类 2020-12-29 13:49

Suppose I have an AttributedString : \"Already have an account? Sign in!\". I am placing this String in UILabel. Now when a user clicks on \"Sign in!\", current viewControl

相关标签:
7条回答
  • 2020-12-29 14:19

    Swift 4.2 and Xcode 11 Using TextView it's much easy

    func setupContactUsInTextView() {
        let text = NSMutableAttributedString(string: "Contact us at email ")
        text.addAttribute(NSAttributedStringKey.font,
                          value: UIFont.systemFont(ofSize: 17),
                          range: NSRange(location: 0, length: text.length))
    
        let interactableText = NSMutableAttributedString(string: "contact@abc.com")
        interactableText.addAttribute(NSAttributedStringKey.font,
                                      value: UIFont.systemFont(ofSize: 17),
                                      range: NSRange(location: 0, length: interactableText.length))
    
    
        interactableText.addAttribute(NSAttributedStringKey.link,
                                      value: "contact@abc.com",
                                      range: NSRange(location: 0, length: interactableText.length))
    
    
        text.append(interactableText)
    
    
        contactUsTextView.attributedText = text
        contactUsTextView.textAlignment = .center
        contactUsTextView.isEditable = false
        contactUsTextView.isSelectable = true
        contactUsTextView.delegate = self
    }
    
    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
        print("open website here...")
        return false
    }
    
    0 讨论(0)
  • 2020-12-29 14:24

    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
            }
        }
    }
    }
    
    0 讨论(0)
  • 2020-12-29 14:27

    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
        }
    }
    
    0 讨论(0)
  • 2020-12-29 14:27

    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.

    0 讨论(0)
  • 2020-12-29 14:29

    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)

    0 讨论(0)
  • 2020-12-29 14:32

    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
        }
    }
    
    0 讨论(0)
提交回复
热议问题