From 6a17546685d1137419d490c9638955e29b089722 Mon Sep 17 00:00:00 2001 From: Ilya Grechuhin Date: Tue, 12 Dec 2017 10:50:40 +0300 Subject: [PATCH] [MAPSME-6015] [ios] Fixed expandable text view size estimation. --- .../Maps/Categories/String+BoundingRect.swift | 26 ++++++--- .../ExpandableTextView.swift | 56 ++++++++----------- .../RatingSummaryView/RatingSummaryView.swift | 2 +- .../Components/RatingView/RatingView.swift | 2 +- 4 files changed, 42 insertions(+), 44 deletions(-) diff --git a/iphone/Maps/Categories/String+BoundingRect.swift b/iphone/Maps/Categories/String+BoundingRect.swift index ef9f0336a0..3a0225d056 100644 --- a/iphone/Maps/Categories/String+BoundingRect.swift +++ b/iphone/Maps/Categories/String+BoundingRect.swift @@ -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)) } } diff --git a/iphone/Maps/Classes/Components/ExpandableTextView/ExpandableTextView.swift b/iphone/Maps/Classes/Components/ExpandableTextView/ExpandableTextView.swift index 86795ba75d..76846b9957 100644 --- a/iphone/Maps/Classes/Components/ExpandableTextView/ExpandableTextView.swift +++ b/iphone/Maps/Classes/Components/ExpandableTextView/ExpandableTextView.swift @@ -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 } diff --git a/iphone/Maps/Classes/Components/RatingSummaryView/RatingSummaryView.swift b/iphone/Maps/Classes/Components/RatingSummaryView/RatingSummaryView.swift index 6e0faf36bb..a6dff3f67e 100644 --- a/iphone/Maps/Classes/Components/RatingSummaryView/RatingSummaryView.swift +++ b/iphone/Maps/Classes/Components/RatingSummaryView/RatingSummaryView.swift @@ -183,7 +183,7 @@ import UIKit } } - var scheduledUpdate: DispatchWorkItem? + private var scheduledUpdate: DispatchWorkItem? var settings = RatingSummaryViewSettings() { didSet { diff --git a/iphone/Maps/Classes/Components/RatingView/RatingView.swift b/iphone/Maps/Classes/Components/RatingView/RatingView.swift index 52957fff2e..48f676872e 100644 --- a/iphone/Maps/Classes/Components/RatingView/RatingView.swift +++ b/iphone/Maps/Classes/Components/RatingView/RatingView.swift @@ -309,7 +309,7 @@ import UIKit private var viewSize = CGSize() - var scheduledUpdate: DispatchWorkItem? + private var scheduledUpdate: DispatchWorkItem? func updateImpl() { let layers = createLayers()