Chinese character sizes not calculated correctly in NSLayoutManager's usedRect(for:) method when using San Francisco font
Originator: | jcrowley | ||
Number: | rdar://43337516 | Date Originated: | 8/15/2018 |
Status: | Open | Resolved: | |
Product: | UIKit | Product Version: | |
Classification: | Bug | Reproducible: | Always |
Area: UIKit Summary: There's a problem in `NSLayoutManager`'s `usedRect(for:)` when trying to calculate an `NSAttributedString` with Chinese characters in the San Francisco font. It doesn't calculate the appropriate height. The issue doesn't appear to be present when using other fonts (though I haven't tested exhaustively). Steps to Reproduce: In the following Playground: //======= import UIKit import PlaygroundSupport class MyViewController : UIViewController { override func loadView() { let view = UIView() view.backgroundColor = .white let string = "这首诗并不是苏轼的名篇,但是初读便被最后一句吸引了。对仗工整,却不失灵动。“殷勤”二字用得别有趣味,又新巧。揣摩起诗人的心绪,是闲适中带着点轻快。“又得浮生一日凉”,能抛弃这对“浮生”的万千想象,尽情享受一日的欢喜,一日的凉爽,便自得其乐,心满意足。" let textView = UITextView() textView.frame = CGRect(x: 0, y: 200, width: 300, height: getHeight(forString: string, width: 300)) textView.attributedText = attributedString(string) view.addSubview(textView) self.view = view } func getHeight(forString string: String, width: CGFloat) -> CGFloat { let textContainer = NSTextContainer(size: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)) textContainer.lineFragmentPadding = 0 let textStorage = NSTextStorage(attributedString: attributedString(string)) let layoutManager = NSLayoutManager() layoutManager.addTextContainer(textContainer) textStorage.addLayoutManager(layoutManager) let rect = layoutManager.usedRect(for: textContainer) let height = ceil(rect.height) return height } func attributedString(_ string: String) -> NSAttributedString { let mutableAttributedString = NSMutableAttributedString(string: string, attributes: [NSAttributedStringKey.foregroundColor: UIColor.gray, NSAttributedStringKey.font: UIFont(name: "Helvetica Neue", size: 20.0)]) return mutableAttributedString } } // Present the view controller in the Live View window PlaygroundPage.current.liveView = MyViewController() //======= 1) View the output. The `UITextView` appears correctly, displaying all text in the string. 2) Change the `attributedString(_ :)` method to: func attributedString(_ string: String) -> NSAttributedString { let mutableAttributedString = NSMutableAttributedString(string: string, attributes: [NSAttributedStringKey.foregroundColor: UIColor.gray, NSAttributedStringKey.font: UIFont.systemFont(ofSize: 20.0)]) return mutableAttributedString } 3) View the output. The `UITextView` is cut off at the bottom. Expected Results: Text is properly measured and the resulting rect displays all text. Actual Results: Text is improperly measured, resulting in an inaccurate rect that clips the text. Version/Build: Version 9.4 (9F1027a) Configuration: N/A
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!