自定义UITableViewCell与核心文本

在@yaslam的帮助下,我在Core Text中创建了一个UILabel,使用CTRubyAnnotation以水平和垂直的方式显示日语文本和Furigana。 不幸的是我有一个问题。 我需要在自定义单元格中使用此标签,我需要单元格根据文本动态调整单元格的高度。 但是不行。 细胞不会膨胀

你可以帮我吗?

非常感谢你

这是代码

import UIKit protocol SimpleVerticalGlyphViewProtocol { } extension SimpleVerticalGlyphViewProtocol { func drawContext(_ attributed:NSMutableAttributedString, textDrawRect:CGRect, isVertical:Bool) { guard let context = UIGraphicsGetCurrentContext() else { return } var path:CGPath if isVertical { context.rotate(by: .pi / 2) context.scaleBy(x: 1.0, y: -1.0) path = CGPath(rect: CGRect(x: textDrawRect.origin.y, y: textDrawRect.origin.x, width: textDrawRect.height, height: textDrawRect.width), transform: nil) } else { context.textMatrix = CGAffineTransform.identity context.translateBy(x: 0, y: textDrawRect.height) context.scaleBy(x: 1.0, y: -1.0) path = CGPath(rect: textDrawRect, transform: nil) } let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) CTFrameDraw(frame, context) } } class CustomLabel: UILabel, SimpleVerticalGlyphViewProtocol { /* // Only override draw() if you perform custom drawing. // An empty implementation adversely affects performance during animation. override func draw(_ rect: CGRect) { // Drawing code } */ override func drawText(in rect: CGRect) { let attributed = NSMutableAttributedString(attributedString: self.attributedText!) let isVertical = false // if Vertical Glyph, true. attributed.addAttributes([NSAttributedStringKey.verticalGlyphForm: isVertical], range: NSMakeRange(0, attributed.length)) attributed.addAttribute(NSAttributedStringKey.font, value: UIFont(name: "Hiragino Mincho ProN", size: 27)!, range: NSMakeRange(0, attributed.length)) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineHeightMultiple = 2 paragraphStyle.lineSpacing = 4 attributed.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, (attributed.length))) drawContext(attributed, textDrawRect: rect, isVertical: isVertical) } } 

TableView类

 import UIKit class TableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() // Uncomment the following line to preserve selection between presentations // self.clearsSelectionOnViewWillAppear = false // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 1 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) let label = cell.viewWithTag(10) as! CustomLabel let attributedText = Utility.sharedInstance.furigana(String: "|銀行《ぎんこう》と|郵便局《ゆうびんきょく》の|間《あいだ》の|道《みち》をまっすぐ|行《い》くと、|学校《がっこう》の|前《まえ》に|出《で》ます。") label.attributedText = attributedText return cell } override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableViewAutomaticDimension //return 70 } 

这是结果:

没有字体属性。文本分为两行,但第二行是剪辑。您可以查看是否将单元格的高度设置为70或更高

使用CoreText,视图的高度不会自动确定。 计算CoreText的绘图高度并将其设置为Cell中UIView的高度。 在故事板中为UITableView进行以下设置。
*检查行高自动
*检查自动估算

对于程序,它如下。

 tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = UITableViewAutomaticDimension 

用于计算CoreText绘图高度的示例代码。 我不知道它是否是计算高度的最佳代码。 示例代码相当邋is所以请实际重构它。

 import UIKit class CoreTextWithTableViewController: UITableViewController { var texts = [String]() override func viewDidLoad() { super.viewDidLoad() // tableView.rowHeight = UITableViewAutomaticDimension // or check Automatic of Row Height in storyboard // tableView.estimatedRowHeight = UITableViewAutomaticDimension // or check Automatic of Estimate in storyboard let text = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。さらにこれからはどちらのデバイスにも、ゲームやアプリケーションの|拡張現実《かくちょうげんじつ》のための驚くような|可能性《かのうせい》が広がります。iOS 11を|搭載《とうさい》するiPhoneとiPadは、間違いなくこれまでで最もパワフルで、最もパーソナルで、最も賢いデバイスです。" let text2 = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。" for _ in 0...20 { texts.append(text) texts.append(text2) } NotificationCenter.default.addObserver(self, selector: #selector(changeDirection(notification:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return texts.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCellWithCoreText let text = texts[indexPath.row] cell.coreTextView.text = text let height = cell.coreTextView.heightOfCoreText() cell.heightOfCoreTextView.constant = height // Execute redraw cell.coreTextView.setNeedsDisplay() return cell } } extension CoreTextWithTableViewController { @objc func changeDirection(notification: NSNotification){ tableView.reloadData() } } class CustomCellWithCoreText: UITableViewCell { @IBOutlet weak var coreTextView: CustomViewWithCoreText! @IBOutlet weak var heightOfCoreTextView: NSLayoutConstraint! } class CustomViewWithCoreText: UIView, SimpleVerticalGlyphViewProtocol { var text: String = "" lazy var attributed: NSMutableAttributedString = text.attributedStringWithRuby() var height = CGFloat() override func draw(_ rect: CGRect) { let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: height) drawContext(attributed, textDrawRect: textDrawRect, isVertical: false) } /// get Height of CoreText Draw Rect func heightOfCoreText() -> CGFloat { // initialize height and attributed height = CGFloat() attributed = text.attributedStringWithRuby() // MEMO: height = CGFloat.greatestFiniteMagnitude let textDrawRect = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let path = CGPath(rect: textDrawRect, transform: nil) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) let anyArray: [AnyObject] = CTFrameGetLines(frame) as [AnyObject] let lines = anyArray as! [CTLine] for line in lines { var ascent = CGFloat() var descent = CGFloat() var leading = CGFloat() CTLineGetTypographicBounds(line, &ascent, &descent, &leading) height += ceil(ascent + descent + leading) } return height } } なりimport UIKit class CoreTextWithTableViewController: UITableViewController { var texts = [String]() override func viewDidLoad() { super.viewDidLoad() // tableView.rowHeight = UITableViewAutomaticDimension // or check Automatic of Row Height in storyboard // tableView.estimatedRowHeight = UITableViewAutomaticDimension // or check Automatic of Estimate in storyboard let text = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。さらにこれからはどちらのデバイスにも、ゲームやアプリケーションの|拡張現実《かくちょうげんじつ》のための驚くような|可能性《かのうせい》が広がります。iOS 11を|搭載《とうさい》するiPhoneとiPadは、間違いなくこれまでで最もパワフルで、最もパーソナルで、最も賢いデバイスです。" let text2 = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。" for _ in 0...20 { texts.append(text) texts.append(text2) } NotificationCenter.default.addObserver(self, selector: #selector(changeDirection(notification:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return texts.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCellWithCoreText let text = texts[indexPath.row] cell.coreTextView.text = text let height = cell.coreTextView.heightOfCoreText() cell.heightOfCoreTextView.constant = height // Execute redraw cell.coreTextView.setNeedsDisplay() return cell } } extension CoreTextWithTableViewController { @objc func changeDirection(notification: NSNotification){ tableView.reloadData() } } class CustomCellWithCoreText: UITableViewCell { @IBOutlet weak var coreTextView: CustomViewWithCoreText! @IBOutlet weak var heightOfCoreTextView: NSLayoutConstraint! } class CustomViewWithCoreText: UIView, SimpleVerticalGlyphViewProtocol { var text: String = "" lazy var attributed: NSMutableAttributedString = text.attributedStringWithRuby() var height = CGFloat() override func draw(_ rect: CGRect) { let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: height) drawContext(attributed, textDrawRect: textDrawRect, isVertical: false) } /// get Height of CoreText Draw Rect func heightOfCoreText() -> CGFloat { // initialize height and attributed height = CGFloat() attributed = text.attributedStringWithRuby() // MEMO: height = CGFloat.greatestFiniteMagnitude let textDrawRect = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let path = CGPath(rect: textDrawRect, transform: nil) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) let anyArray: [AnyObject] = CTFrameGetLines(frame) as [AnyObject] let lines = anyArray as! [CTLine] for line in lines { var ascent = CGFloat() var descent = CGFloat() var leading = CGFloat() CTLineGetTypographicBounds(line, &ascent, &descent, &leading) height += ceil(ascent + descent + leading) } return height } }の|能力import UIKit class CoreTextWithTableViewController: UITableViewController { var texts = [String]() override func viewDidLoad() { super.viewDidLoad() // tableView.rowHeight = UITableViewAutomaticDimension // or check Automatic of Row Height in storyboard // tableView.estimatedRowHeight = UITableViewAutomaticDimension // or check Automatic of Estimate in storyboard let text = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。さらにこれからはどちらのデバイスにも、ゲームやアプリケーションの|拡張現実《かくちょうげんじつ》のための驚くような|可能性《かのうせい》が広がります。iOS 11を|搭載《とうさい》するiPhoneとiPadは、間違いなくこれまでで最もパワフルで、最もパーソナルで、最も賢いデバイスです。" let text2 = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。" for _ in 0...20 { texts.append(text) texts.append(text2) } NotificationCenter.default.addObserver(self, selector: #selector(changeDirection(notification:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return texts.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCellWithCoreText let text = texts[indexPath.row] cell.coreTextView.text = text let height = cell.coreTextView.heightOfCoreText() cell.heightOfCoreTextView.constant = height // Execute redraw cell.coreTextView.setNeedsDisplay() return cell } } extension CoreTextWithTableViewController { @objc func changeDirection(notification: NSNotification){ tableView.reloadData() } } class CustomCellWithCoreText: UITableViewCell { @IBOutlet weak var coreTextView: CustomViewWithCoreText! @IBOutlet weak var heightOfCoreTextView: NSLayoutConstraint! } class CustomViewWithCoreText: UIView, SimpleVerticalGlyphViewProtocol { var text: String = "" lazy var attributed: NSMutableAttributedString = text.attributedStringWithRuby() var height = CGFloat() override func draw(_ rect: CGRect) { let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: height) drawContext(attributed, textDrawRect: textDrawRect, isVertical: false) } /// get Height of CoreText Draw Rect func heightOfCoreText() -> CGFloat { // initialize height and attributed height = CGFloat() attributed = text.attributedStringWithRuby() // MEMO: height = CGFloat.greatestFiniteMagnitude let textDrawRect = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let path = CGPath(rect: textDrawRect, transform: nil) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) let anyArray: [AnyObject] = CTFrameGetLines(frame) as [AnyObject] let lines = anyArray as! [CTLine] for line in lines { var ascent = CGFloat() var descent = CGFloat() var leading = CGFloat() CTLineGetTypographicBounds(line, &ascent, &descent, &leading) height += ceil(ascent + descent + leading) } return height } }らにこれからはどちらのデバイスにもimport UIKit class CoreTextWithTableViewController: UITableViewController { var texts = [String]() override func viewDidLoad() { super.viewDidLoad() // tableView.rowHeight = UITableViewAutomaticDimension // or check Automatic of Row Height in storyboard // tableView.estimatedRowHeight = UITableViewAutomaticDimension // or check Automatic of Estimate in storyboard let text = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。さらにこれからはどちらのデバイスにも、ゲームやアプリケーションの|拡張現実《かくちょうげんじつ》のための驚くような|可能性《かのうせい》が広がります。iOS 11を|搭載《とうさい》するiPhoneとiPadは、間違いなくこれまでで最もパワフルで、最もパーソナルで、最も賢いデバイスです。" let text2 = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。" for _ in 0...20 { texts.append(text) texts.append(text2) } NotificationCenter.default.addObserver(self, selector: #selector(changeDirection(notification:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return texts.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCellWithCoreText let text = texts[indexPath.row] cell.coreTextView.text = text let height = cell.coreTextView.heightOfCoreText() cell.heightOfCoreTextView.constant = height // Execute redraw cell.coreTextView.setNeedsDisplay() return cell } } extension CoreTextWithTableViewController { @objc func changeDirection(notification: NSNotification){ tableView.reloadData() } } class CustomCellWithCoreText: UITableViewCell { @IBOutlet weak var coreTextView: CustomViewWithCoreText! @IBOutlet weak var heightOfCoreTextView: NSLayoutConstraint! } class CustomViewWithCoreText: UIView, SimpleVerticalGlyphViewProtocol { var text: String = "" lazy var attributed: NSMutableAttributedString = text.attributedStringWithRuby() var height = CGFloat() override func draw(_ rect: CGRect) { let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: height) drawContext(attributed, textDrawRect: textDrawRect, isVertical: false) } /// get Height of CoreText Draw Rect func heightOfCoreText() -> CGFloat { // initialize height and attributed height = CGFloat() attributed = text.attributedStringWithRuby() // MEMO: height = CGFloat.greatestFiniteMagnitude let textDrawRect = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let path = CGPath(rect: textDrawRect, transform: nil) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) let anyArray: [AnyObject] = CTFrameGetLines(frame) as [AnyObject] let lines = anyArray as! [CTLine] for line in lines { var ascent = CGFloat() var descent = CGFloat() var leading = CGFloat() CTLineGetTypographicBounds(line, &ascent, &descent, &leading) height += ceil(ascent + descent + leading) } return height } }ーションの| import UIKit class CoreTextWithTableViewController: UITableViewController { var texts = [String]() override func viewDidLoad() { super.viewDidLoad() // tableView.rowHeight = UITableViewAutomaticDimension // or check Automatic of Row Height in storyboard // tableView.estimatedRowHeight = UITableViewAutomaticDimension // or check Automatic of Estimate in storyboard let text = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。さらにこれからはどちらのデバイスにも、ゲームやアプリケーションの|拡張現実《かくちょうげんじつ》のための驚くような|可能性《かのうせい》が広がります。iOS 11を|搭載《とうさい》するiPhoneとiPadは、間違いなくこれまでで最もパワフルで、最もパーソナルで、最も賢いデバイスです。" let text2 = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。" for _ in 0...20 { texts.append(text) texts.append(text2) } NotificationCenter.default.addObserver(self, selector: #selector(changeDirection(notification:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return texts.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCellWithCoreText let text = texts[indexPath.row] cell.coreTextView.text = text let height = cell.coreTextView.heightOfCoreText() cell.heightOfCoreTextView.constant = height // Execute redraw cell.coreTextView.setNeedsDisplay() return cell } } extension CoreTextWithTableViewController { @objc func changeDirection(notification: NSNotification){ tableView.reloadData() } } class CustomCellWithCoreText: UITableViewCell { @IBOutlet weak var coreTextView: CustomViewWithCoreText! @IBOutlet weak var heightOfCoreTextView: NSLayoutConstraint! } class CustomViewWithCoreText: UIView, SimpleVerticalGlyphViewProtocol { var text: String = "" lazy var attributed: NSMutableAttributedString = text.attributedStringWithRuby() var height = CGFloat() override func draw(_ rect: CGRect) { let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: height) drawContext(attributed, textDrawRect: textDrawRect, isVertical: false) } /// get Height of CoreText Draw Rect func heightOfCoreText() -> CGFloat { // initialize height and attributed height = CGFloat() attributed = text.attributedStringWithRuby() // MEMO: height = CGFloat.greatestFiniteMagnitude let textDrawRect = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let path = CGPath(rect: textDrawRect, transform: nil) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) let anyArray: [AnyObject] = CTFrameGetLines(frame) as [AnyObject] let lines = anyArray as! [CTLine] for line in lines { var ascent = CGFloat() var descent = CGFloat() var leading = CGFloat() CTLineGetTypographicBounds(line, &ascent, &descent, &leading) height += ceil(ascent + descent + leading) } return height } }import UIKit class CoreTextWithTableViewController: UITableViewController { var texts = [String]() override func viewDidLoad() { super.viewDidLoad() // tableView.rowHeight = UITableViewAutomaticDimension // or check Automatic of Row Height in storyboard // tableView.estimatedRowHeight = UITableViewAutomaticDimension // or check Automatic of Estimate in storyboard let text = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。さらにこれからはどちらのデバイスにも、ゲームやアプリケーションの|拡張現実《かくちょうげんじつ》のための驚くような|可能性《かのうせい》が広がります。iOS 11を|搭載《とうさい》するiPhoneとiPadは、間違いなくこれまでで最もパワフルで、最もパーソナルで、最も賢いデバイスです。" let text2 = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。" for _ in 0...20 { texts.append(text) texts.append(text2) } NotificationCenter.default.addObserver(self, selector: #selector(changeDirection(notification:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return texts.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCellWithCoreText let text = texts[indexPath.row] cell.coreTextView.text = text let height = cell.coreTextView.heightOfCoreText() cell.heightOfCoreTextView.constant = height // Execute redraw cell.coreTextView.setNeedsDisplay() return cell } } extension CoreTextWithTableViewController { @objc func changeDirection(notification: NSNotification){ tableView.reloadData() } } class CustomCellWithCoreText: UITableViewCell { @IBOutlet weak var coreTextView: CustomViewWithCoreText! @IBOutlet weak var heightOfCoreTextView: NSLayoutConstraint! } class CustomViewWithCoreText: UIView, SimpleVerticalGlyphViewProtocol { var text: String = "" lazy var attributed: NSMutableAttributedString = text.attributedStringWithRuby() var height = CGFloat() override func draw(_ rect: CGRect) { let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: height) drawContext(attributed, textDrawRect: textDrawRect, isVertical: false) } /// get Height of CoreText Draw Rect func heightOfCoreText() -> CGFloat { // initialize height and attributed height = CGFloat() attributed = text.attributedStringWithRuby() // MEMO: height = CGFloat.greatestFiniteMagnitude let textDrawRect = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let path = CGPath(rect: textDrawRect, transform: nil) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) let anyArray: [AnyObject] = CTFrameGetLines(frame) as [AnyObject] let lines = anyArray as! [CTLine] for line in lines { var ascent = CGFloat() var descent = CGFloat() var leading = CGFloat() CTLineGetTypographicBounds(line, &ascent, &descent, &leading) height += ceil(ascent + descent + leading) } return height } } なりimport UIKit class CoreTextWithTableViewController: UITableViewController { var texts = [String]() override func viewDidLoad() { super.viewDidLoad() // tableView.rowHeight = UITableViewAutomaticDimension // or check Automatic of Row Height in storyboard // tableView.estimatedRowHeight = UITableViewAutomaticDimension // or check Automatic of Estimate in storyboard let text = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。さらにこれからはどちらのデバイスにも、ゲームやアプリケーションの|拡張現実《かくちょうげんじつ》のための驚くような|可能性《かのうせい》が広がります。iOS 11を|搭載《とうさい》するiPhoneとiPadは、間違いなくこれまでで最もパワフルで、最もパーソナルで、最も賢いデバイスです。" let text2 = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。" for _ in 0...20 { texts.append(text) texts.append(text2) } NotificationCenter.default.addObserver(self, selector: #selector(changeDirection(notification:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return texts.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCellWithCoreText let text = texts[indexPath.row] cell.coreTextView.text = text let height = cell.coreTextView.heightOfCoreText() cell.heightOfCoreTextView.constant = height // Execute redraw cell.coreTextView.setNeedsDisplay() return cell } } extension CoreTextWithTableViewController { @objc func changeDirection(notification: NSNotification){ tableView.reloadData() } } class CustomCellWithCoreText: UITableViewCell { @IBOutlet weak var coreTextView: CustomViewWithCoreText! @IBOutlet weak var heightOfCoreTextView: NSLayoutConstraint! } class CustomViewWithCoreText: UIView, SimpleVerticalGlyphViewProtocol { var text: String = "" lazy var attributed: NSMutableAttributedString = text.attributedStringWithRuby() var height = CGFloat() override func draw(_ rect: CGRect) { let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: height) drawContext(attributed, textDrawRect: textDrawRect, isVertical: false) } /// get Height of CoreText Draw Rect func heightOfCoreText() -> CGFloat { // initialize height and attributed height = CGFloat() attributed = text.attributedStringWithRuby() // MEMO: height = CGFloat.greatestFiniteMagnitude let textDrawRect = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let path = CGPath(rect: textDrawRect, transform: nil) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) let anyArray: [AnyObject] = CTFrameGetLines(frame) as [AnyObject] let lines = anyArray as! [CTLine] for line in lines { var ascent = CGFloat() var descent = CGFloat() var leading = CGFloat() CTLineGetTypographicBounds(line, &ascent, &descent, &leading) height += ceil(ascent + descent + leading) } return height } }の|能力 import UIKit class CoreTextWithTableViewController: UITableViewController { var texts = [String]() override func viewDidLoad() { super.viewDidLoad() // tableView.rowHeight = UITableViewAutomaticDimension // or check Automatic of Row Height in storyboard // tableView.estimatedRowHeight = UITableViewAutomaticDimension // or check Automatic of Estimate in storyboard let text = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。さらにこれからはどちらのデバイスにも、ゲームやアプリケーションの|拡張現実《かくちょうげんじつ》のための驚くような|可能性《かのうせい》が広がります。iOS 11を|搭載《とうさい》するiPhoneとiPadは、間違いなくこれまでで最もパワフルで、最もパーソナルで、最も賢いデバイスです。" let text2 = "すでに|世界《せかい》で最も|先進的《せんしんてき》なモバイルオペレーティングシステムであるiOSに、iOS 11が新あらたな|基準《きじゅん》を打ち立てます。iPhoneは今まで以上に優れたものになり、iPadはかつてないほどの|能力《のうりょく》を手に入れます。" for _ in 0...20 { texts.append(text) texts.append(text2) } NotificationCenter.default.addObserver(self, selector: #selector(changeDirection(notification:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return texts.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCellWithCoreText let text = texts[indexPath.row] cell.coreTextView.text = text let height = cell.coreTextView.heightOfCoreText() cell.heightOfCoreTextView.constant = height // Execute redraw cell.coreTextView.setNeedsDisplay() return cell } } extension CoreTextWithTableViewController { @objc func changeDirection(notification: NSNotification){ tableView.reloadData() } } class CustomCellWithCoreText: UITableViewCell { @IBOutlet weak var coreTextView: CustomViewWithCoreText! @IBOutlet weak var heightOfCoreTextView: NSLayoutConstraint! } class CustomViewWithCoreText: UIView, SimpleVerticalGlyphViewProtocol { var text: String = "" lazy var attributed: NSMutableAttributedString = text.attributedStringWithRuby() var height = CGFloat() override func draw(_ rect: CGRect) { let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: height) drawContext(attributed, textDrawRect: textDrawRect, isVertical: false) } /// get Height of CoreText Draw Rect func heightOfCoreText() -> CGFloat { // initialize height and attributed height = CGFloat() attributed = text.attributedStringWithRuby() // MEMO: height = CGFloat.greatestFiniteMagnitude let textDrawRect = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let path = CGPath(rect: textDrawRect, transform: nil) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) let anyArray: [AnyObject] = CTFrameGetLines(frame) as [AnyObject] let lines = anyArray as! [CTLine] for line in lines { var ascent = CGFloat() var descent = CGFloat() var leading = CGFloat() CTLineGetTypographicBounds(line, &ascent, &descent, &leading) height += ceil(ascent + descent + leading) } return height } } 

样本图像
旋转tableView

似乎CTParagraphStyle的设置值未反映在CTLineGetTypographicBounds获得的高度中。 相反,使用CTFramesetterSuggestFrameSizeWithConstraints工作。

 func heightOfCoreText() -> CGFloat { // initialize height and attributed height = CGFloat() attributed = text.attributedStringWithRuby() // MEMO: height = CGFloat.greatestFiniteMagnitude let textDrawRect = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, attributed.length), nil, textDrawRect.size, nil) height = frameSize.height return height } 

minimumLineSpacing = 10.0
lineHeightMultiple = 1.5

使用CTFramesetterSuggestFrameSizeWithConstraints