是的,这是可能的,尽管一开始很难弄清楚。我将更进一步,向您展示如何点击文本中的任何区域。
使用此方法,您可以拥有 UI 标签:
- 多行友好
- 自动收缩友好
- 可点击友好(是的,甚至是单个字符)
- 斯威夫特 5
第 1 步:
使 UILabel 具有“Truncate Tail”的换行符属性并设置最小字体比例。
如果您不熟悉字体比例,请记住以下规则:
minimumFontSize/defaultFontSize = fontscale
在我的例子中,我希望 7.2 成为最小字体大小,而我的起始字体大小是 36。因此,7.2 / 36 = 0.2
第 2 步:
如果您不关心标签的可点击性,而只是想要一个有效的多行标签,那么您就完成了!
但是,如果您希望 标签可点击,请继续阅读...
添加我创建的以下扩展
extension UILabel {
func setOptimalFontSize(maxFontSize:CGFloat,text:String){
let width = self.bounds.size.width
var font_size:CGFloat = maxFontSize //Set the maximum font size.
var stringSize = NSString(string: text).size(withAttributes: [.font : self.font.withSize(font_size)])
while(stringSize.width > width){
font_size = font_size - 1
stringSize = NSString(string: text).size(withAttributes: [.font : self.font.withSize(font_size)])
}
self.font = self.font.withSize(font_size)//Forcefully change font to match what it would be graphically.
}
}
这样使用(只需将<Label> 替换为您的实际标签名称):
<Label>.setOptimalFontSize(maxFontSize: 36.0, text: formula)
这个扩展是必需的,因为自动收缩在标签自动收缩后不会改变标签的'font'属性,所以你必须通过与使用 . size(withAttributes) 函数,它模拟特定字体的大小。
这是必要的,因为检测标签点击位置的解决方案需要知道确切的字体大小。
第 3 步:
添加以下扩展:
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 paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 6
paragraphStyle.lineBreakMode = .byTruncatingTail
paragraphStyle.alignment = .center
mutableAttribString.addAttributes([.paragraphStyle: paragraphStyle], range: NSMakeRange(0, mutableAttribString.string.count))
let textStorage = NSTextStorage(attributedString: mutableAttribString)
// Configure textContainer
textContainer.lineFragmentPadding = 0.0
textContainer.lineBreakMode = label.lineBreakMode
textContainer.maximumNumberOfLines = label.numberOfLines
// Configure layoutManager and textStorage
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
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 = 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)
//let locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
// locationOfTouchInLabel.y - textContainerOffset.y);
let locationOfTouchInTextContainer = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x, y: locationOfTouchInLabel.y - textContainerOffset.y)
let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
print("IndexOfCharacter=",indexOfCharacter)
print("TargetRange=",targetRange)
return NSLocationInRange(indexOfCharacter, targetRange)
}
}
您需要针对特定的多行情况修改此扩展。在我的例子中,你会注意到我使用了段落样式。
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 6
paragraphStyle.lineBreakMode = .byTruncatingTail
paragraphStyle.alignment = .center
mutableAttribString.addAttributes([.paragraphStyle: paragraphStyle], range: NSMakeRange(0, mutableAttribString.string.count))
确保在扩展程序中将此更改为您实际使用的行距,以便一切计算正确。
第 4 步:
将gestureRecognizer添加到viewDidLoad中的标签或您认为合适的位置(只需再次将<Label>替换为您的标签名称:
<Label>.addGestureRecognizer(UITapGestureRecognizer(target:self, action: #selector(tapLabel(gesture:))))
这是我的 tapLabel 函数的简化示例(只需将 <Label> 替换为您的 UILabel 名称):
@IBAction func tapLabel(gesture: UITapGestureRecognizer) {
guard let text = <Label>.attributedText?.string else {
return
}
let click_range = text.range(of: "(α/β)")
if gesture.didTapAttributedTextInLabel(label: <Label>, inRange: NSRange(click_range!, in: text)) {
print("Tapped a/b")
}else {
print("Tapped none")
}
}
在我的示例中只是一个注释,我的字符串是BED = N * d * [ RBE + ( d / (α/β) ) ],所以在这种情况下我只是得到了α/β 的范围。您可以在字符串中添加“\n”以添加换行符和您想要的任何文本,然后测试它以在下一行找到一个字符串,它仍然会找到它并正确检测到点击!
就是这样!你完成了。享受多行 可点击标签。