forked from organicmaps/organicmaps
[MAPSME-6015] [ios] Fixed expandable text view size estimation.
This commit is contained in:
parent
a551065e59
commit
6a17546685
4 changed files with 42 additions and 44 deletions
|
@ -3,18 +3,28 @@ import UIKit
|
|||
extension String {
|
||||
func size(width: CGFloat, font: UIFont, maxNumberOfLines: Int = 0) -> CGSize {
|
||||
if isEmpty {
|
||||
return CGSize(width: width, height: 0)
|
||||
return CGSize.zero
|
||||
}
|
||||
|
||||
let maximumHeight = maxNumberOfLines == 0 ? CGFloat.greatestFiniteMagnitude : font.lineHeight * CGFloat(maxNumberOfLines + 1)
|
||||
let lineHeight = font.lineHeight
|
||||
let maximumHeight = maxNumberOfLines == 0 ? CGFloat.greatestFiniteMagnitude : lineHeight * CGFloat(maxNumberOfLines + 1)
|
||||
let constraintSize = CGSize(width: width, height: maximumHeight)
|
||||
let options: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading]
|
||||
let attributes = [NSAttributedStringKey.font: font]
|
||||
let rect = (self as NSString).boundingRect(with: constraintSize, options: options, attributes: attributes, context: nil)
|
||||
var numberOfLines = ceil(ceil(rect.height) / font.lineHeight)
|
||||
let options: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading, .truncatesLastVisibleLine]
|
||||
let paragraph = NSMutableParagraphStyle()
|
||||
paragraph.lineBreakMode = .byWordWrapping
|
||||
paragraph.alignment = .natural
|
||||
let attributes = [
|
||||
NSAttributedStringKey.font: font,
|
||||
NSAttributedStringKey.paragraphStyle: paragraph,
|
||||
]
|
||||
var rect = (self as NSString).boundingRect(with: constraintSize, options: options, attributes: attributes, context: nil)
|
||||
var numberOfLines = ceil(rect.height / lineHeight)
|
||||
if maxNumberOfLines != 0 {
|
||||
if width - rect.width < font.ascender {
|
||||
rect.size.width = width - font.ascender
|
||||
numberOfLines += 1
|
||||
}
|
||||
numberOfLines = min(numberOfLines, CGFloat(maxNumberOfLines))
|
||||
}
|
||||
return CGSize(width: ceil(rect.width), height: ceil(numberOfLines * font.lineHeight))
|
||||
return CGSize(width: ceil(rect.width), height: ceil(numberOfLines * lineHeight))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,17 +75,16 @@ import UIKit
|
|||
}
|
||||
}
|
||||
|
||||
private func createTextLayer() -> CALayer {
|
||||
private func createTextLayer() {
|
||||
self.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
|
||||
|
||||
var truncate = false
|
||||
let size: CGSize
|
||||
|
||||
let container = CALayer()
|
||||
container.anchorPoint = CGPoint()
|
||||
container.contentsScale = UIScreen.main.scale
|
||||
|
||||
let fullSize = text.size(width: frame.width, font: textFont, maxNumberOfLines: 0)
|
||||
if isCompact {
|
||||
size = text.size(width: frame.width, font: textFont, maxNumberOfLines: numberOfCompactLines)
|
||||
let fullSize = text.size(width: frame.width, font: textFont, maxNumberOfLines: 0)
|
||||
if size.height < fullSize.height {
|
||||
truncate = size.height < fullSize.height
|
||||
if truncate {
|
||||
let expandSize = expandText.size(width: frame.width, font: textFont, maxNumberOfLines: 1)
|
||||
let layer = CATextLayer()
|
||||
layer.position = CGPoint(x: 0, y: size.height)
|
||||
|
@ -97,10 +96,10 @@ import UIKit
|
|||
layer.foregroundColor = expandTextColor?.cgColor
|
||||
layer.contentsScale = UIScreen.main.scale
|
||||
|
||||
container.addSublayer(layer)
|
||||
self.layer.addSublayer(layer)
|
||||
}
|
||||
} else {
|
||||
size = text.size(width: frame.width, font: textFont, maxNumberOfLines: 0)
|
||||
size = fullSize
|
||||
}
|
||||
|
||||
let layer = CATextLayer()
|
||||
|
@ -108,21 +107,13 @@ import UIKit
|
|||
layer.anchorPoint = CGPoint()
|
||||
layer.string = text
|
||||
layer.isWrapped = true
|
||||
layer.truncationMode = kCATruncationEnd
|
||||
layer.truncationMode = truncate ? kCATruncationEnd : kCATruncationNone
|
||||
layer.font = CGFont(textFont.fontName as CFString)
|
||||
layer.fontSize = textFont.pointSize
|
||||
layer.foregroundColor = textColor?.cgColor
|
||||
layer.contentsScale = UIScreen.main.scale
|
||||
|
||||
container.addSublayer(layer)
|
||||
|
||||
var containerSize = CGSize()
|
||||
container.sublayers?.forEach { layer in
|
||||
containerSize.width = max(containerSize.width, layer.frame.maxX)
|
||||
containerSize.height = max(containerSize.height, layer.frame.maxY)
|
||||
}
|
||||
container.frame.size = containerSize
|
||||
return container
|
||||
self.layer.addSublayer(layer)
|
||||
}
|
||||
|
||||
public override func awakeFromNib() {
|
||||
|
@ -152,30 +143,27 @@ import UIKit
|
|||
update()
|
||||
}
|
||||
|
||||
private var viewSize = CGSize()
|
||||
private func updateImpl() {
|
||||
let sublayer = createTextLayer()
|
||||
layer.sublayers = [sublayer]
|
||||
private var scheduledUpdate: DispatchWorkItem?
|
||||
|
||||
viewSize = sublayer.bounds.size
|
||||
private func updateImpl() {
|
||||
createTextLayer()
|
||||
|
||||
invalidateIntrinsicContentSize()
|
||||
onUpdate?()
|
||||
}
|
||||
|
||||
@objc private func doUpdate() {
|
||||
DispatchQueue.main.async {
|
||||
self.updateImpl()
|
||||
}
|
||||
}
|
||||
|
||||
func update() {
|
||||
let sel = #selector(doUpdate)
|
||||
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: sel, object: nil)
|
||||
perform(sel, with: nil, afterDelay: 1 / 120)
|
||||
scheduledUpdate?.cancel()
|
||||
scheduledUpdate = DispatchWorkItem { [weak self] in self?.updateImpl() }
|
||||
DispatchQueue.main.async(execute: scheduledUpdate!)
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
var viewSize = CGSize()
|
||||
layer.sublayers?.forEach { layer in
|
||||
viewSize.width = max(viewSize.width, layer.frame.maxX)
|
||||
viewSize.height = max(viewSize.height, layer.frame.maxY)
|
||||
}
|
||||
return viewSize
|
||||
}
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ import UIKit
|
|||
}
|
||||
}
|
||||
|
||||
var scheduledUpdate: DispatchWorkItem?
|
||||
private var scheduledUpdate: DispatchWorkItem?
|
||||
|
||||
var settings = RatingSummaryViewSettings() {
|
||||
didSet {
|
||||
|
|
|
@ -309,7 +309,7 @@ import UIKit
|
|||
|
||||
private var viewSize = CGSize()
|
||||
|
||||
var scheduledUpdate: DispatchWorkItem?
|
||||
private var scheduledUpdate: DispatchWorkItem?
|
||||
|
||||
func updateImpl() {
|
||||
let layers = createLayers()
|
||||
|
|
Loading…
Add table
Reference in a new issue