检测UILabel的水龙头,并启用自动缩小到最小字体大小

问题描述 投票:1回答:1

我正在使用下面修改的UITapGestureRecognizer,以便其他人可以复制并粘贴以查看与我相同的输出。

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 mutableAttribString = NSMutableAttributedString(attributedString: label.attributedText!)
        //mutableAttribString.addAttributes([NSAttributedString.Key.font: label.font!], range: NSRange(location: 0, length: label.attributedText!.length))

        let textStorage = NSTextStorage(attributedString: label.attributedText!)
        //let textStorage = NSTextStorage(attributedString: mutableAttribString)

        // 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
        print("LabelSize=",labelSize)

        textContainer.size = labelSize
        print("TextContainerSize=",textContainer.size)

        // Find the tapped character location and compare it to the specified range
        let locationOfTouchInLabel = self.location(in: label)
        print("LocationOfTouchInLabel=",locationOfTouchInLabel)

        let textBoundingBox = layoutManager.usedRect(for: textContainer)
        print("TextBoundingBox=",textBoundingBox)
        //let textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                              //(labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
        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)
        print("textContainerOffset",textContainerOffset)

        //let locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
                                                        // locationOfTouchInLabel.y - textContainerOffset.y);
        let locationOfTouchInTextContainer = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x, y: locationOfTouchInLabel.y - textContainerOffset.y)
        print("LocationOfTouchInTextContainer",locationOfTouchInTextContainer)

        let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        print("IndexOfCharacter=",indexOfCharacter)

        print("TargetRange=",targetRange)
        return NSLocationInRange(indexOfCharacter, targetRange)
    }

}

我设置了标签,以便像其他答案所说的那样检测点击次数:

formulaLabel.addGestureRecognizer(UITapGestureRecognizer(target:self, action: #selector(tapLabel(gesture:))))

已设置为归因。

如果很重要,我有以下代码可以对文本进行动画处理。

func doFormulaAnimation(){
        //animTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true, block: {_ in
            //Draw correct formula based on mode.

        var formula = ""
        var highlight_ranges:[NSRange] = []

        if(stateController?.tdfvariables.ebrtMode == true){
            formulaLabel.numberOfLines = 1
            formula = "BED = N * d * [ RBE + ( d / (α/β) ) ]"

            self.formulaLabel.attributedText = NSMutableAttributedString(string: formula, attributes: [ NSAttributedString.Key.foregroundColor: UIColor.label ])

            if(self.dosePerFractionSelected==true){
                highlight_ranges.append(NSRange(location: 10, length: 1))
                highlight_ranges.append(NSRange(location: 24, length: 1))
            }

            if(self.alphaBetaSelected==true){
                highlight_ranges.append(NSRange(location: 29, length: 3))
            }

            if(self.totalDoseSelected==true){
                highlight_ranges.append(NSRange(location: 6, length: 5))
            }

            if(self.numFractionsSelected==true){
                highlight_ranges.append(NSRange(location: 6, length: 1))
            }
        }

        if(stateController?.tdfvariables.ldrMode == true){
            formulaLabel.numberOfLines = 3
            formula = "BED = R * T * [RBE + (( g * R * T) / (α/β) ) ]\ng = ( 2 / μT ) * ( 1 - ( ( 1 - exp(-μT) / μT ) )\nμ = 0.693 / Thalf repair"
        }

        if(stateController?.tdfvariables.permMode == true){
            formulaLabel.numberOfLines = 2
            formula = "BED = ( R0 / L ) * [ RBE + ( R0 / ( ( u + L) * (α/β) ) ) ]\n"
        }

        UIView.transition(with: self.formulaLabel, duration: 0.5, options: .transitionCrossDissolve, animations: {
                let colorAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.label ]
                let attributedTextFormula = NSMutableAttributedString(string: formula, attributes: colorAttribute)

                let paragraphStyle = NSMutableParagraphStyle()
                paragraphStyle.lineSpacing = 6
                paragraphStyle.lineBreakMode = .byTruncatingTail
                //paragraphStyle.alignment = .center

                attributedTextFormula.addAttribute(
                    .paragraphStyle,
                    value: paragraphStyle,
                    range: NSRange(location: 0, length: attributedTextFormula.length
                ))


                self.formulaLabel.attributedText = attributedTextFormula
                //
            }, completion: { finished in
                print("finished first transition")

                UIView.transition(with: self.formulaLabel, duration: 0.5, options: .transitionCrossDissolve, animations: {
                    let colorAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.label ]
                    let attributedTextFormula = NSMutableAttributedString(string: formula, attributes: colorAttribute)
                    for range in highlight_ranges {
                        attributedTextFormula.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red, range: range)
                    }

                    let paragraphStyle = NSMutableParagraphStyle()
                    paragraphStyle.lineSpacing = 6
                    paragraphStyle.lineBreakMode = .byTruncatingTail
                    //paragraphStyle.alignment = .center

                    attributedTextFormula.addAttribute(
                        .paragraphStyle,
                        value: paragraphStyle,
                        range: NSRange(location: 0, length: attributedTextFormula.length
                    ))

                    self.formulaLabel.attributedText = attributedTextFormula
                    //self.formulaLabel.addInterlineSpacing(spacingValue: 1)
                }, completion: { finished in
                    print("finished second transition")
                })

        })
    }

[上面的代码演示了我如何相应地创建NSMutableString并相应地设置段落样式和行间距(我预感这可能是问题所在,但不确定如何进行测试等等)...

最后我有了我的水龙头标签功能

 @IBAction func tapLabel(gesture: UITapGestureRecognizer) {
        guard let text = formulaLabel.attributedText?.string else {
            return
        }

        let AB_Range = text.range(of: "(α/β)")

        //let AB_Range = NSRange(location: 29, length: 3)
        if gesture.didTapAttributedTextInLabel(label: formulaLabel, inRange: NSRange(AB_Range!, in: text)) {
           print("Tapped a/b")
        } else {
           print("Tapped none")
        }
    }

目前,它没有轻敲正确的位置,但是在很大的程度上偏离了。在调试后,很明显为什么它不起作用,但是我不确定如何修复代码或哪里出错了。

[当我像应按A / B那样单击时,我应该将此作为调试信息。

LabelSize= (315.0, 43.0)
TextContainerSize= (315.0, 43.0)
LocationOfTouchInLabel= (266.0, 28.0)
TextBoundingBox= (0.0, 0.0, 185.373046875, 13.8)
textContainerOffset (64.8134765625, 14.6)
LocationOfTouchInTextContainer (201.1865234375, 13.4)
IndexOfCharacter= 36
TargetRange= {28, 5}
Tapped none

它计算文本边界框或textcontaineroffset或touchintextcontainer的位置的部分是最有可能的错误点,但我不确定是哪一个,因为这很难理解。

我可以告诉它它不能正常工作,因为在我的字符串中,它不在结尾处,并且无论单击什么位置,它总是显示indexofcharacter = 36,这意味着它不能使用我上面提到的变量之一正确地计算出东西。

如果他们知道为什么这样不起作用,可以提供任何帮助。

为了让您知道文本的外观,我在下面向您展示。我的最终目标是做到这一点,这样我就可以单击公式中的各个部分以显示值,因此可以说可单击的链接。

enter image description here

更新::

我忘了提到我在更新UITapGestureRecognizer并添加以下行时:

let mutableAttribString = NSMutableAttributedString(attributedString: label.attributedText!)
        mutableAttribString.addAttributes([NSAttributedString.Key.font: label.font!], range: NSRange(location: 0, length: label.attributedText!.length))

并将其设置为文本存储,let textStorage = NSTextStorage(attributedString: mutableAttribString)我似乎确实看到数字有所改进,但仍遥遥无期。

LabelSize= (315.0, 43.0)
TextContainerSize= (315.0, 43.0)
LocationOfTouchInLabel= (269.0, 25.5)
TextBoundingBox= (7.505859375, 0.0, 299.98828125, 42.9609375)
textContainerOffset (0.0, 0.01953125)
LocationOfTouchInTextContainer (269.0, 25.48046875)
IndexOfCharacter= 17
TargetRange= {28, 5}
Tapped none

您将注意到textboundingbox至少与标签大小更相似。我在某处读到一个问题,如果您使用的是不同的字体,可能就是这样,这就是为什么我尝试添加该字体以确保其正常工作的原因。

同样有趣的是,将其添加到UITapGestureRecognizer似乎也有帮助:

let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 6
        paragraphStyle.lineBreakMode = .byTruncatingTail
        //paragraphStyle.alignment = .center

    mutableAttribString.addAttribute(
        .paragraphStyle,
        value: paragraphStyle,
        range: NSRange(location: 0, length: mutableAttribString.length
    ))

[我注意到这样做时,文本边界框正确显示了0,0,而不是7.50

LabelSize= (315.0, 43.0)
TextContainerSize= (315.0, 43.0)
LocationOfTouchInLabel= (262.5, 31.0)
TextBoundingBox= (0.0, 0.0, 299.98828125, 42.9609375)
textContainerOffset (7.505859375, 0.01953125)
LocationOfTouchInTextContainer (254.994140625, 30.98046875)
IndexOfCharacter= 17
TargetRange= {28, 5}
Tapped none

**主要更新*****

好消息!事实证明,font fix

是该修复程序的一部分,但是由于我具有使用最小字体大小启用的自动收缩和最大字体大小,因此它从未正确计算! 当我设置为固定字体大小时,一切正常!

问题现在如何在启用自动收缩功能的情况下起作用?

请注意,您必须将大小设置为非常大的值才能证明其有效,例如我将我的尺寸设置为55,以便它相应地自动收缩,然后您会看到错误,如果默认大小较小,那么它似乎可以正常工作,这告诉我错误与大小最初可能很大有关?

enter image description here

我正在使用下面修改的UITapGestureRecognizer,以便其他人可以复制并粘贴以查看与我相同的输出。扩展名UITapGestureRecognizer {func didTapAttributedTextInLabel(...

uilabel multiline swift5 autoshrink
1个回答
0
投票

所以我终于找到了可以接受的答案。

© www.soinside.com 2019 - 2024. All rights reserved.