如何使 NSAttributedString 链接可点击

发布于 2025-01-17 12:02:05 字数 1035 浏览 1 评论 0原文

我需要将数字显示为来自字符串输入(包含字母和数字)的可点击链接,点击该号码后,它应该打开一个 iOS 呼叫拨号器并拨打该号码。

下面是我目前所尝试的,为了使号码看起来像一个可点击的号码,并将所有文本保留为正常的默认文本,下面有黑色的 formattedText var 已被定义,

var formattedText: NSAttributedString{
let message = "Hey you can dial up {88 22 333} number for further assistance"
let linkRange = (message as NSString).range(of: fetchNumber) //fetchNumber method returns the content residing inside flower braces..

guard linkRange.location != NSNotFound else {return nil}
let finalString = NSMutableAttributedString(string: message, attributes:[.font: UIFont.scaledFont(from: .baseText16), foregroundColor: .black])
finalString.addAttributes([.foregroundColor: .blue], range: linkRange) 
return finalString 
}

上述函数的输出是:嘿,你可以拨号 < code>88 22 333 号码以获得进一步帮助

并使号码可点击,我尝试使用此属性文本输入到 UITextView 并启用 dataDetectorType 属性,但它对我不起作用:( 有没有什么办法可以让 UILabel 本身或任何类型的 UIKit 元素实现这一点,提前感谢任何建议,谢谢

我尝试使用此属性文本输入到 UITextView 并启用 dataDetectorType 属性,但它对我不起作用:( 有没有什么办法可以让 UILabel 本身或任何类型的 UIKit 元素实现这一点,任何建议都非常感谢,谢谢

I have a requirement to display the numbers as clickable link from a string input(contains alphabets and numerals) and on tap of that number it should open an iOS call dialler and should dials that number.

Below is what I have tried at the moment, to make the number to look like a tappable one and rest all text as normal default text with black color below formattedText var has been defined,

var formattedText: NSAttributedString{
let message = "Hey you can dial up {88 22 333} number for further assistance"
let linkRange = (message as NSString).range(of: fetchNumber) //fetchNumber method returns the content residing inside flower braces..

guard linkRange.location != NSNotFound else {return nil}
let finalString = NSMutableAttributedString(string: message, attributes:[.font: UIFont.scaledFont(from: .baseText16), foregroundColor: .black])
finalString.addAttributes([.foregroundColor: .blue], range: linkRange) 
return finalString 
}

output of above function is: Hey you can dial up 88 22 333 number for further assistance

and to make the number tappable I have tried using this attributed text input to UITextView with dataDetectorType property enabled but it is not working for me :(
Is there any way to make it happen with UILabel itself or any sort of UIKit elements, any suggestions is much appreciated in advance, thanks

I have tried using this attributed text input to UITextView with dataDetectorType property enabled but it is not working for me :(
Is there any way to make it happen with UILabel itself or any sort of UIKit elements, any suggestions is much appreciated in advance, thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

稀香 2025-01-24 12:02:05

首先,您需要在全球声明手机号码。

var mobileNo = "88 22 333"

为文本设置属性字符串,并创建可敲击标签。

func setupLabel() {
    
    let fullString = "Hey you can dial up " + mobileNo + " number for further assistance"
    let strNSString: NSString = fullString as NSString
    let rangeNumber = (strNSString).range(of: mobileNo)
    let attribute = NSMutableAttributedString.init(string: fullString)
    attribute.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.lightGray , range: rangeNumber)
    attribute.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 16), range: rangeNumber)
    lblNumber.attributedText = attribute
    
    //Tap Gesture
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(lblNumberTapped))
    lblNumber.addGestureRecognizer(tapGesture)
    lblNumber.isUserInteractionEnabled = true
}

之后,声明龙头手势的方法。

//MARK: - TapGesture Click events
@objc func lblNumberTapped(_ gesture: UITapGestureRecognizer) {
    self.view.endEditing(true)
    
    let text = self.lblNumber.text ?? ""
    let recoverMobileNumber = (text as NSString).range(of: mobileNo)

    if gesture.didTapAttributedTextInLabel(label: lblNumber, inRange: recoverMobileNumber) {
        if let callUrl = URL(string: "tel://\(mobileNo)"), UIApplication.shared.canOpenURL(callUrl) {
             UIApplication.shared.open(callUrl)
        }

    }
    

}

您需要uitapgestureRecognize伸展来检测点击事件。

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
    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 textBoundingBox = layoutManager.boundingRect(forGlyphRange: targetRange, in: 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)
}
}

First of all you need to declare mobile number globally.

var mobileNo = "88 22 333"

Set attributed string for your text and create tappable label.

func setupLabel() {
    
    let fullString = "Hey you can dial up " + mobileNo + " number for further assistance"
    let strNSString: NSString = fullString as NSString
    let rangeNumber = (strNSString).range(of: mobileNo)
    let attribute = NSMutableAttributedString.init(string: fullString)
    attribute.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.lightGray , range: rangeNumber)
    attribute.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 16), range: rangeNumber)
    lblNumber.attributedText = attribute
    
    //Tap Gesture
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(lblNumberTapped))
    lblNumber.addGestureRecognizer(tapGesture)
    lblNumber.isUserInteractionEnabled = true
}

After that declare method of tap gesture.

//MARK: - TapGesture Click events
@objc func lblNumberTapped(_ gesture: UITapGestureRecognizer) {
    self.view.endEditing(true)
    
    let text = self.lblNumber.text ?? ""
    let recoverMobileNumber = (text as NSString).range(of: mobileNo)

    if gesture.didTapAttributedTextInLabel(label: lblNumber, inRange: recoverMobileNumber) {
        if let callUrl = URL(string: "tel://\(mobileNo)"), UIApplication.shared.canOpenURL(callUrl) {
             UIApplication.shared.open(callUrl)
        }

    }
    

}

You need UITapGestureRecognizer extension for detect tap events.

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
    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 textBoundingBox = layoutManager.boundingRect(forGlyphRange: targetRange, in: 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)
}
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文