Жест касания только для определенных диапазонов c UILabel в Swift не работает, если базовая строка содержит двойные кавычки - PullRequest
0 голосов
/ 11 марта 2020

Я сделал реализацию в this в моем ios app.but, когда базовый текст, заданный как, guard let text = self.lblTermsAndConditions.text else { return } содержит двойные кавычки c 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    }

расширение в нижней части viewcontroller

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

Это печатает 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
    }
}

}

1 Ответ

0 голосов
/ 11 марта 2020

Добавьте эту строку в 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, тогда вот в чем проблема.

...