当基本字符串包含双引号时,仅针对 Swift 中 UILabel 的特定范围的点击手势不起作用

Posted

技术标签:

【中文标题】当基本字符串包含双引号时,仅针对 Swift 中 UILabel 的特定范围的点击手势不起作用【英文标题】:Tap gesture only for specific ranges of a UILabel in Swift not working when the base string contains double quotation 【发布时间】:2020-03-11 11:30:09 【问题描述】:

我在我的 ios 应用程序中在 this 中进行了实现。但是当给出的基本文本时,guard let text = self.lblTermsAndConditions.text else return 包含双引号 func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool 返回 false。

例如,当 lblTermsAndConditions 给出的文本是,点击“注册”,即表示我同意条款和条件以及隐私政策 和 privacyPolicyRange = 条款和条件和隐私政策 didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool 返回 false。

我的代码

@IBOutlet weak var privacyPolicyLabel: HuqLabel!
    didSet
        privacyPolicyLabel.text = "By clicking \"Signup\",I agree to the Terms and Conditions & Privacy Policy"
    


override func viewDidLoad() 
    super.viewDidLoad()
    self.privacyPolicyLabel.isUserInteractionEnabled = true
    let tapgesture = UITapGestureRecognizer(target: self, action: #selector(tappedOnLabel(_ :)))
    tapgesture.numberOfTapsRequired = 1
    tapgesture.numberOfTouchesRequired = 1
    self.privacyPolicyLabel.addGestureRecognizer(tapgesture)
    self.privacyPolicyLabel.isUserInteractionEnabled = true    

视图控制器底部的扩展

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
    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(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)

我就是这样用的

guard let text = self.privacyPolicyLabel.text else  return 
    let privacyPolicyRange = (text as NSString).range(of: "Terms and Conditions & Privacy Policy")
    if gesture.didTapAttributedTextInLabel(label: self.privacyPolicyLabel, inRange: privacyPolicyRange) 
        print("clicked on terms and conditions")
    else
       print("false")
    

这打印错误。 我该如何解决这个问题?

编辑:

我的自定义标签

    import UIKit

class HuqLabel: UILabel 

    private var attributes = HuqStringAttributes.attributes(for: .bigTitle)

    private var typograpyStyle: HuqTypographyStyle!

    override init(frame: CGRect) 
        super.init(frame: frame)
        configure()
    

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
        configure()
    

    private func configure() 
        adjustsFontForContentSizeCategory = true
        numberOfLines = 0
    

    // Must be called after setting the attributed text
    func setNumberOfLines(_ numOfLines: Int, breakMode: NSLineBreakMode = .byTruncatingTail) 
        numberOfLines = numOfLines
        lineBreakMode = breakMode
    

    func setText(_ text: String) 
        self.text = text
        setLetterSpacing()
    

    func set(_ text: String = "", typographyStyle: HuqTypographyStyle, alignment: NSTextAlignment = .left) 
        typograpyStyle = typographyStyle
        self.text = text
        accessibilityLabel = text

        self.attributes = HuqStringAttributes.attributes(for: typographyStyle, alignment: alignment)

        setLetterSpacing()
    

    func setAttributesForStrikeThrough(_ text: String, typographyStyle: HuqTypographyStyle, alignment: NSTextAlignment = .left) 
        self.text = text
        accessibilityLabel = text

        self.attributes = HuqStringAttributes.attributes(for: typographyStyle, alignment: alignment)

        let attributedString = NSMutableAttributedString(string: text, attributes: self.attributes)
        attributedString.addAttribute(NSAttributedString.Key.kern, value: letterSpacingForTypographyStyle(for: typographyStyle), range: NSRange(location: 0, length: text.count))
        attributedString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: 1, range: NSMakeRange(0, attributedString.length))

        attributedText = attributedString
    

    func setLetterSpacing() 
        let attributedString = NSMutableAttributedString(string: self.text ?? "", attributes: self.attributes)
        attributedString.addAttribute(NSAttributedString.Key.kern, value: letterSpacingForTypographyStyle(for: typograpyStyle), range: NSRange(location: 0, length: self.text?.count ?? 0))

        attributedText = attributedString
    

    private func letterSpacingForTypographyStyle(for typographyStyle: HuqTypographyStyle) -> CGFloat 
        switch typographyStyle 

        case .bigTitle, .title, .bodyLight, .bodyWhite, .caption, .bodyBoldWhite, .bodyBoldBlue, .bodyBalck, .bodySmall, .titleBlue, .captionBlack, .bigTitleOrange, .captionMediumBlue:

            return 0
        
    

    func setText(_ text: String,
                 withBoldTextSections boldSections: [String], font: UIFont = FontFamily.Ubuntu.bold.font(size: 16),color:UIColor = ColorName.brownGrey.color) 

        let attributes = HuqStringAttributes.attributes(for: .bodyLight, alignment: .center)

        let attributedFullString = NSMutableAttributedString(string: text,
                                                             attributes: attributes)

        boldSections.forEach  section in
            let rangeOfSection = attributedFullString.mutableString.range(of: section)
            attributedFullString.addAttributes([
                NSAttributedString.Key.foregroundColor: color,
                NSAttributedString.Key.font:font], range: rangeOfSection)
        

        attributedText = attributedFullString
    

-

    import Foundation

enum HuqTypographyStyle 
    case bigTitle
    case bigTitleOrange
    case title
    case titleBlue
    case bodyLight
    case bodyWhite
    case bodyBalck
    case caption
    case captionBlack
    case bodyBoldBlue
    case bodyBoldWhite
    case bodySmall
    case captionMediumBlue

-

import Foundation
import UIKit

struct HuqFonts 

static func font(for typographyStyle: HuqTypographyStyle) -> UIFont 

    switch typographyStyle 

    case .bigTitle, .bigTitleOrange:
        return ubuntuMedium(size: 30)
    case .title, .titleBlue:
        return ubuntuMedium(size: 18)
    case .bodyLight, .bodyBalck:
        return ubuntuRegular(size: 16)
    case .bodyWhite:
        return ubuntuRegular(size: 14)
    case .caption, .captionBlack:
        return ubuntuRegular(size: 12)
    case .bodyBoldBlue, .bodyBoldWhite:
        return ubuntuBold(size: 16)
    case .bodySmall:
        return ubuntuRegular(size: 10)
    case .captionMediumBlue:
        return ubuntuMedium(size: 12)
    


private static func ubuntuMedium(size: CGFloat) -> UIFont 
    return FontFamily.Ubuntu.medium.font(size: size)


private static func ubuntuRegular(size: CGFloat) -> UIFont 
    return FontFamily.Ubuntu.regular.font(size: size)


private static func ubuntuBold(size: CGFloat) -> UIFont 
    return FontFamily.Ubuntu.bold.font(size: size)





import UIKit

struct HuqStringAttributes 

static func attributes(for typographyStyle: HuqTypographyStyle,
                       alignment: NSTextAlignment = .left) -> [NSAttributedString.Key: Any] 

    var attributes: [NSAttributedString.Key: Any] = [:]

    attributes[.font] = HuqFonts.font(for: typographyStyle).scaled
    attributes[.foregroundColor] = colorsForTypographyStyles(for: typographyStyle).color

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = alignment

    attributes[.paragraphStyle] = paragraphStyle

    return attributes


private static func colorsForTypographyStyles(for typographyStyle: HuqTypographyStyle) -> ColorName 

    switch typographyStyle 
    case .bigTitle, .title, .bodyBalck, .captionBlack:
        return ColorName.black
    case .bodyLight ,.caption, .bodySmall:
        return ColorName.brownGrey
    case .bodyWhite, .bodyBoldWhite:
        return ColorName.white
    case .bodyBoldBlue, .titleBlue, .captionMediumBlue:
        return ColorName.turquoiseBlue
    case .bigTitleOrange:
        return ColorName.bloodOrange
    

【问题讨论】:

不要仅仅链接到您的代码基于...编辑您的问题并包含您正在使用的实际代码。 @DonMag 现在检查。 您的文本是否包含多行? 没有字符串中的引号可以工作吗? 是的。它没有引号@DonMag 【参考方案1】:

viewDidLoad()中添加这一行:

self.privacyPolicyLabel.lineBreakMode = .byWordWrapping

快速测试似乎可以解决问题。


编辑

试试这个。它使用标准的UILabel - 全部通过代码,没有@IBOutlet 连接 - 所以只需将视图控制器的自定义类分配给LabelLinkViewController。它还使用您在问题中发布的 UITapGestureRecognizer 扩展名。

class LabelLinkViewController: UIViewController 

    var privacyPolicyLabel: UILabel = 
        let v = UILabel()
        v.numberOfLines = 0
        return v
    ()

    override func viewDidLoad() 
        super.viewDidLoad()

        privacyPolicyLabel.translatesAutoresizingMaskIntoConstraints = false
        privacyPolicyLabel.backgroundColor = .yellow

        view.addSubview(privacyPolicyLabel)

        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            privacyPolicyLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            privacyPolicyLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0),
            privacyPolicyLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -60.0),
        ])

        self.privacyPolicyLabel.lineBreakMode = .byWordWrapping
        self.privacyPolicyLabel.isUserInteractionEnabled = true
        let tapgesture = UITapGestureRecognizer(target: self, action: #selector(tappedOnLabel(_ :)))
        tapgesture.numberOfTapsRequired = 1
        tapgesture.numberOfTouchesRequired = 1
        self.privacyPolicyLabel.addGestureRecognizer(tapgesture)
        self.privacyPolicyLabel.isUserInteractionEnabled = true

        self.privacyPolicyLabel.text = "By clicking \"Signup\", I agree to the Terms and Conditions & Privacy Policy"
        //self.privacyPolicyLabel.text = "By clicking Signup, I agree to the Terms and Conditions & Privacy Policy"

    

    //MARK:- tappedOnLabel
    @objc func tappedOnLabel(_ gesture: UITapGestureRecognizer) 

        guard let text = self.privacyPolicyLabel.text else  return 
        let privacyPolicyRange = (text as NSString).range(of: "Terms and Conditions & Privacy Policy")
        if gesture.didTapAttributedTextInLabel(label: self.privacyPolicyLabel, inRange: privacyPolicyRange) 
            print("clicked on terms and conditions")
        else
            print("false")
        

    


如果这对您有用,但在您使用 HuqLabel 类时它确实不起作用,那么这就是问题所在。

【讨论】:

是的,这对我有用。不过,我使用了UILabel,因为您没有发布任何有关您的HugLabel 课程的信息。也许这就是问题的一部分? 是的。我正在使用自定义 UILabel。我将其添加到问题中。 未解析的标识符HuqStringAttributes和未声明的类型HuqTypographyStyle @KrishanMadushanka - 在运行您的代码时仍然遇到问题(其他未声明的标识符等等)。在我编辑的答案中尝试示例。如果这可行,但仍然无法与您的 HuqLabel 一起使用,那么看看您是否可以编写一个完整的示例来运行,我们将看看我们是否可以找到并解决问题。

以上是关于当基本字符串包含双引号时,仅针对 Swift 中 UILabel 的特定范围的点击手势不起作用的主要内容,如果未能解决你的问题,请参考以下文章

当字符串在双引号内有单引号时,如何在Javascript中将此字符串转换为JSON对象

JavaScript字符串单引号和双引号的使用

JavaScript字符串单引号和双引号的使用

检查字符串是不是包含破折号并在单词中添加双引号

浮点值返回swift中[String:AnyObject]的双引号

第二章