使用 Swift 的 UILabel 中的 NSAttributedString 单击事件

NSAttributedString click event in UILabel using Swift

假设我有一个 AttributedString:“已有帐户?请登录!”。

我将这个字符串放在 UILabel 中。现在,当用户点击“登录!”时,当前 viewController 应该转到另一个 viewController 或者在点击登录时调用某些函数。

任何代码或建议都可以。

您可以将 tapGesture 应用于标签。

创建点击手势识别器:

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

向标签添加手势识别器:

YOUR_LABEL.addGestureRecognizer(tapGesture)

用这种方法执行你的任务:

func YOUR_METHOD(sender:UITapGestureRecognizer){
    // Perform your operations here.
}

您需要使用 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
            }
        }
    }
}

您可以将点击手势识别器添加到您的 label/view,或者您可以将带有自定义 URL 协议的 link 嵌入到您的属性字符串中,使用 UITextView,然后打开关于 link 检测。然后,您需要实现 UITextView 委托方法来响应 links.

我在 GitHub 上有一个名为 DatesInSwift (link) 的演示项目,它在 UITextView 中实现了可点击的 link。看一下 ViewController.swift 中的 UITextView 委托方法 textView(_:shouldInteractWithURL:inRange)。这是告诉文本视图它应该响应 URL.

的方法

然后你必须实现一个 UIApplicationDelegate 方法来处理 URL。示例应用程序使用 application(_:openURL:sourceApplication:annotation),已在 iOS 9 中弃用。对于新开发,您应该改用 application(_:openURL:options:)

您还需要将 CFBundleURLTypes / CFBundleURLSchemes 条目添加到您的 info.plist 以注册自定义 URL 方案(如 myompany.myapp.loginURL)单击嵌入式 URL 以调用您的应用程序的顺序。

如某些答案所述,无需使用单独的手势识别器。相反,您可以结合使用属性文本和 UITextViewDelegatetextView:shouldInteractWithURL:inRange:interaction: 方法来实现此目的,例如:

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
    }
}

您可以使用文本视图代替标签来打开视图控制器或使子字符串可点击。

  1. 为要使其可点击的字符串创建一个属性

    let linkAttributes = [
        NSLinkAttributeName: NSURL(string: "https://www.apple.com")!,
        NSForegroundColorAttributeName: UIColor.blue
        ] as [String : Any]
    
  2. 使您的字符串成为属性字符串

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

    您可以在此处提供您的自定义范围。

  3. 属性文本添加到您的文本视图

    YourTextView.attributedText = attributedString
    
  4. 然后实现下面的textview的delegate方法实现一个URL

    的交互
    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
        // Here write your code of navigation
        return false
    }
    
  5. 如果你想用标签做,点击查看How can I make a clickable link in an NSAttributedString?.

语言更新基于回答:)

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
    }
}

Swift 4.2 和 Xcode 11

使用 TextView 更容易:

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
}