【发布时间】:2020-08-22 09:13:59
【问题描述】:
我正在使用我修改的以下 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
它计算 textbounding box 或 textcontaineroffset 或 locationoftouchintextcontainer 的部分很可能是错误点,但我不确定是哪一个,因为这很难理解。
我可以说它工作不正常,因为在我的字符串中它没有接近结尾,无论我在哪里点击它,它总是说 indexofcharacter=36,这意味着它没有用我上面提到的变量之一正确计算某些东西.
如果他们知道为什么这不起作用,我们将不胜感激。
为了让您了解文本现在的外观,我将在下面向您展示。我的最终目标是做到这一点,以便我可以单击公式中的部分以显示值,因此您可以说可点击的链接。
更新::
我忘了提到当我更新 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
**主要更新*****
好消息!事实证明,字体修复是修复的一部分,但是因为我启用了 autoshrink 并启用了最小字体大小和最大字体大小,所以它从未正确计算! 当我设置为固定字体大小时,一切正常!
现在的问题是如何使其在启用自动收缩的情况下工作?请注意,您必须将大小设置为非常大的值才能证明这有效,例如我将我的设置为 55,因此它会相应地自动收缩并且然后你会看到错误,如果默认大小更小,那么它似乎工作正常,这告诉我错误可能与最初的大小非常大有关?
【问题讨论】:
标签: uilabel multiline swift5 autoshrink