Пользовательский UITableViewCell с основным текстом

Используя @yaslam, я создал в Core Text UILabel, который отображает японский текст как в горизонтальном, так и в вертикальном направлении с помощью Furigana с использованием CTRubyAnnotation. К сожалению, у меня проблема. Мне нужно использовать эту метку внутри пользовательской ячейки, и мне нужно, чтобы ячейка динамически изменяла высоту ячейки на основе текста. но не работает клетка не расширяется

Вы можете мне помочь?

большое спасибо

Вот код

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 или более

1 ответ

Решение

Используя CoreText, высота просмотра не определяется автоматически. Рассчитайте высоту рисования CoreText и установите его в высоту UIView в ячейке. Сделайте следующие настройки для UITableView в раскадровке.
* Автоматическая проверка высоты строки
* Проверка Автоматическая Оценка

Для программ это выглядит следующим образом.

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = UITableViewAutomaticDimension

Пример кода для расчета высоты рисования CoreText. Я не знаю, является ли это оптимальный код для расчета высоты. Пример кода довольно неаккуратный, поэтому, пожалуйста, сделайте его рефакторинг.

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
}

imumLineSpacing = 10,0
lineHeightMultiple = 1,5

использовать CTFramesetterSuggestFrameSizeWithConstraints

Другие вопросы по тегам