Drawing Multiline Text Problem, get only first line

Hi everyones,

I’ve subclass uiLabel class to create a label that show japanese text with furigana in both horizontal and vertical way. It’s work. but because I need this label in some point of my app, I’ve used inside a custom tableviewcell.

Everything work but there is only one problem: multiline. I don’t know why but the label show only the first line. numberOfLines = 0;

and I ve not set come constraints about the height of label.

Can you help me to understand how to fix it?

thank you

this is the code of label

import UIKit
extension String {
func find(pattern: String) -> NSTextCheckingResult? {
    do {
        let re = try NSRegularExpression(pattern: pattern, options: [])
        return re.firstMatch(
            in: self,
            options: [],
            range: NSMakeRange(0, self.utf16.count))
    } catch {
        return nil
    }
}

func replace(pattern: String, template: String) -> String {
    do {
        let re = try NSRegularExpression(pattern: pattern, options: [])
        return re.stringByReplacingMatches(
            in: self,
            options: [],
            range: NSMakeRange(0, self.utf16.count),
            withTemplate: template)
    } catch {
        return self
    }
}
}

enum textOrientation {
case horizontal
case vertical

}


class GQAsianTextLabel: UILabel {

var orientation:textOrientation!
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
    let attributed =
        self.text?
            .replace(pattern: "(|.+?《.+?》)", template: ",$1,")
            .components(separatedBy: ",")
            .map { x -> NSAttributedString in
                if let pair = x.find(pattern: "|(.+?)《(.+?)》") {
                    let string = (x as NSString).substring(with: pair.rangeAt(1))
                    let ruby = (x as NSString).substring(with: pair.rangeAt(2))
                    
                    var text: [Unmanaged<CFString>?] = [Unmanaged<CFString>.passRetained(ruby as CFString) as Unmanaged<CFString>, .none, .none, .none]
                    
                    let annotation = CTRubyAnnotationCreate(CTRubyAlignment.auto, CTRubyOverhang.auto, 0.5, &text[0]!)
                    
                    return NSAttributedString(
                        string: string,
                        attributes: [kCTRubyAnnotationAttributeName as String: annotation])
                } else {
                    return NSAttributedString(string: x, attributes: nil)
                }
            }
            .reduce(NSMutableAttributedString()) { $0?.append($1); return $0 }
    
    var height = 28.0
    let settings = [
        CTParagraphStyleSetting(
            spec: .minimumLineHeight,
            valueSize: Int(MemoryLayout.size(ofValue: height)),
            value: &height)
    ]
    let style = CTParagraphStyleCreate(settings, Int(settings.count))
    
    
    switch orientation! {
    case .horizontal:
        attributed?.addAttributes([
            NSFontAttributeName: self.font,
            NSVerticalGlyphFormAttributeName: false,
            kCTParagraphStyleAttributeName as String: style,
            ],
                                  range: NSMakeRange(0, (attributed?.length)!))
    case .vertical:
        attributed?.addAttributes([
            NSFontAttributeName: self.font,
            NSVerticalGlyphFormAttributeName: true,
            kCTParagraphStyleAttributeName as String: style,
            ],
                                  range: NSMakeRange(0, (attributed?.length)!))
    }
    
    
    // Initialize a graphics context in iOS.
    let context = UIGraphicsGetCurrentContext()
    
    let bounds:CGRect
    
    // Set the text matrix.
    context!.textMatrix = CGAffineTransform.identity;
    
    // Flip the context coordinates, in iOS only.
    switch orientation! {
    case .horizontal:
        context!.translateBy(x: 0, y: 0);
        context!.scaleBy(x: 1.0, y: -1.0);
        //bounds = CGRect(x: 0, y: 0, width: rect.size.width, height: -rect.size.height)
        bounds = CGRect(x: 0, y: 0, width: rect.size.width, height: -self.bounds.size.height)
        
        print(NSStringFromCGRect(bounds))
    case .vertical:
        context!.rotate(by: CGFloat(M_PI_2))
        context!.translateBy(x: 0, y: 5);
        context!.scaleBy(x: 1.0, y: -1.0);
        bounds = CGRect(x: 0, y: 0, width: rect.size.height, height: rect.size.width)
        
    }
    
    // Create a path which bounds the area where you will be drawing text.
    // The path need not be rectangular.
    
    let path = CGMutablePath()
    
    // In this simple example, initialize a rectangular path.
    //let bounds = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: -(rect.size.height * 2))
    path.addRect(bounds)
    
    
    // Create the framesetter with the attributed string.
    let framesetter = CTFramesetterCreateWithAttributedString(attributed!)
    
    // Create a frame.
    let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, (attributed?.length)!), path, nil)
    // Draw the specified frame in the given context.
    CTFrameDraw(frame, context!);
}

}

@rufy. Thanks very much for your question, and my apologies for the delayed response. In all honesty, such detailed technical questions are very hard to debug on this forum, which is why it may take so long for you to get an answer. Having said that, I would strongly recommend you use www.stackoverflow.com, and ask you to post your question verbatim there. I can almost guarantee you that you will get a solid answer within 24 hours :slight_smile:

I hope this helps!

All the best!