How to calculate the size sample solution of text using Swift
- 2020-05-30 21:10:16
- OfStack
preface
For the grammar of swift, which is still in the groping stage, many people are not familiar with it. This paper mainly introduces the relevant content of computing size by Swift, which can be Shared for your reference and learning.
iOS 11 was used to limit the width and height of the calculated string size
UILabel的textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect
Method, thread safety was not considered at the time (low exploded), Xcode did not prompt, used several versions, fortunately 1 straight no problem.
Post the method (I won't explain why I chose this method at that time) :
func textSize(font: UIFont, constrainedSize: CGSize, lineSpacing: CGFloat?, lines: Int) -> CGSize {
if self.isEmpty || lines < 0 {
return CGSize.zero
}
let attributedString = NSMutableAttributedString(string: self)
let range = NSRange(location: 0, length: attributedString.length)
attributedString.addAttributes([NSFontAttributeName: font], range: range)
if lineSpacing != nil {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byTruncatingTail
paragraphStyle.lineSpacing = lineSpacing!
attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: range)
}
let calculatedLabel = UILabel()
calculatedLabel.font = font
calculatedLabel.attributedText = attributedString
calculatedLabel.numberOfLines = lines
let rect = calculatedLabel.textRect(forBounds: CGRect(x: 0, y: 0, width: constrainedSize.width, height: constrainedSize.height), limitedToNumberOfLines: lines)
return rect.size
}
I recently upgraded Xcode 9 to warn me at run time
let calculatedLabel = UILabel()
Only when the main thread was executed did I realize the seriousness of the problem and immediately modified it:
extension String {
func boundingRect(with constrainedSize: CGSize, font: UIFont, lineSpacing: CGFloat? = nil) -> CGSize {
let attritube = NSMutableAttributedString(string: self)
let range = NSRange(location: 0, length: attritube.length)
attritube.addAttributes([NSAttributedStringKey.font: font], range: range)
if lineSpacing != nil {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = lineSpacing!
attritube.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: range)
}
let rect = attritube.boundingRect(with: constrainedSize, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
var size = rect.size
if let currentLineSpacing = lineSpacing {
// The height of the text minus the height of the font is less than or equal to the line spacing 1 line
let spacing = size.height - font.lineHeight
if spacing <= currentLineSpacing && spacing > 0 {
size = CGSize(width: size.width, height: font.lineHeight)
}
}
return size
}
func boundingRect(with constrainedSize: CGSize, font: UIFont, lineSpacing: CGFloat? = nil, lines: Int) -> CGSize {
if lines < 0 {
return .zero
}
let size = boundingRect(with: constrainedSize, font: font, lineSpacing: lineSpacing)
if lines == 0 {
return size
}
let currentLineSpacing = (lineSpacing == nil) ? (font.lineHeight - font.pointSize) : lineSpacing!
let maximumHeight = font.lineHeight*CGFloat(lines) + currentLineSpacing*CGFloat(lines - 1)
if size.height >= maximumHeight {
return CGSize(width: size.width, height: maximumHeight)
}
return size
}
}
Parameter interpretation
Note: the code version is Swift 4.0
The two methods above substitute names: method 1 and method 2, respectively.
Method 1: limit the width and height, set the line spacing, and calculate accurately
Method 2: more row restriction than method 1.
Extended methods in conjunction with UILabel:
extension UILabel {
// Set up the `numberOfLines = 0` The reason:
// With method `func boundingRect(with constrainedSize: CGSize, font: UIFont, lineSpacing: CGFloat? = nil, lines: Int) -> CGSize` Use, can be a good solution to the normal display can not limit the number of lines;
// If it is label Set a limit on the number of rows (greater than 0 ), using the above calculation (with line spacing), and the actual number of lines in the string is greater than the limit number, the height will be label Cannot display properly.
func setText(with normalString: String, lineSpacing: CGFloat?, frame: CGRect) {
self.frame = frame
self.numberOfLines = 0
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byTruncatingTail
if lineSpacing != nil {
if (frame.height - font.lineHeight) <= lineSpacing! {
paragraphStyle.lineSpacing = 0
} else {
paragraphStyle.lineSpacing = lineSpacing!
}
}
let attributedString = NSMutableAttributedString(string: normalString)
let range = NSRange(location: 0, length: attributedString.length)
attributedString.addAttributes([NSAttributedStringKey.font: font], range: range)
attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: range)
self.attributedText = attributedString
}
}
Thank you in this hamster: iOS spaced visitors and https: / / github com/zhengwenming/WeChat
conclusion