2017-12-04 13 views
0

Mit Hilfe von @yaslam habe ich in Core Text ein UILabel erstellt, das japanischen Text in horizontaler und vertikaler Richtung mit Furigana unter Verwendung von CTRubyAnnotation zeigt. Leider habe ich ein Problem. Ich muss dieses Label in einer benutzerdefinierten Zelle verwenden, und ich brauche, dass die Zelle die Höhe der Zelle basierend auf Text dynamisch ändert. aber arbeite nicht. die Zelle erweitert nichtBenutzerdefiniertes UITableViewCell mit Kerntext

Können Sie mir helfen?

Vielen Dank

Hier Code ist

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 Klasse

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 
} 

dies ist das Ergebnis:

without font attribute. The text is in two lines but the second is clipping. You can see if set the height of cell to 70 or more

Antwort

0

Mit CoreText wird die Höhe der Ansicht nicht automatisch bestimmt. Berechnen Sie die Zeichenhöhe von CoreText und setzen Sie sie auf die Höhe von UIView in Zelle. Nehmen Sie die folgenden Einstellungen für UITableView im Storyboard vor.
* Preis Automatische von Zeilenhöhe
* Preis Automatische von Estimate

Für Programme, ist es wie folgt.

Beispielcode zum Berechnen der Zeichnungshöhe von CoreText. Ich weiß nicht, ob es der optimale Code für die Berechnung der Höhe ist. Beispielcode ist ziemlich schlampig, bitte refactor es tatsächlich.

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

sample image
rotate tableView

Es scheint, dass der Einstellwert von CTParagraphStyle nicht in der Höhe, die durch CTLineGetTypographicBounds erhalten reflektiert wird. Stattdessen funktioniert die Verwendung von 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

use CTFramesetterSuggestFrameSizeWithConstraints

+0

Vielen Dank für diese Antwort. es ist toll, aber es gibt nur das letzte Problem: wenn man das Gerät im Querformat dreht, wird die Saite gestreckt. Ich habe versucht, ersetzen die uiview mit uilabel und die Methode zeichnen (in :) mit drawText (in :). Arbeitet, aber die Zelle wird nicht skaliert, da sich die Einschränkungen nicht ändern. Wie kann ich dieses letzte Problem beheben? –

+0

@GabrieleQuatela Es tut mir leid, es gab ein Problem im Code, wenn die Anzahl der Daten oder rotierende Ansicht erhöht wurde. Es musste neu gezeichnet werden, wenn die Zelle erneut verwendet oder die Ansicht gedreht wurde. Daher habe ich setNeedsDisplay() hinzugefügt. Wenn sich die Ansicht dreht, rufen Sie tableView.ReloadData() auf. Dies ruft "cellForRowAt indexPath" auf und führt setNeedsDisplay() erneut aus. – yaslam

+0

vielen Dank für Ihre Hilfe. Ich habe das Problem an meine Situation angepasst und es funktioniert. Jetzt habe ich ein Problem mit dem NSMutableParagraphStyle.Wenn ich zB lineHeightMultiple = 1.1 einstelle, wird die Höhe nicht gut berechnet. und Sie können nur eine Zeile sehen. aber vielleicht liegt es daran, dass ich nicht weiß, wie es funktioniert. aber es ist ok. –

Verwandte Themen