[MAPSME-6015] [ios] Fixed expandable text view size estimation.

This commit is contained in:
Ilya Grechuhin 2017-12-12 10:50:40 +03:00
parent a551065e59
commit 6a17546685
4 changed files with 42 additions and 44 deletions

View file

@ -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))
}
}

View file

@ -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
}

View file

@ -183,7 +183,7 @@ import UIKit
}
}
var scheduledUpdate: DispatchWorkItem?
private var scheduledUpdate: DispatchWorkItem?
var settings = RatingSummaryViewSettings() {
didSet {

View file

@ -309,7 +309,7 @@ import UIKit
private var viewSize = CGSize()
var scheduledUpdate: DispatchWorkItem?
private var scheduledUpdate: DispatchWorkItem?
func updateImpl() {
let layers = createLayers()