hi guys,
I’ve implemented a label that does his work but with problems:
- when the text is long the context isn’t calculate well: it more big. it doesn’t fit to text
- is need to call a method to calculate the hight of label to show text
- in console came out some error about the constraints around of label
here is the code:
import UIKit
public enum TextOrientation{
case vertical
case horizontal
}
class RubyLabel: UILabel {
var orientation:TextOrientation = .horizontal
lazy var attributed: NSMutableAttributedString = Utility.furigana(String: self.text!)
var height = CGFloat()
func heightOfCoreText() -> CGFloat {
// initialize height and attributed
height = CGFloat()
attributed = Utility.furigana(String: self.text!)
attributed.addAttributes([NSAttributedString.Key.font:self.font], range:NSMakeRange(0, attributed.length))
if orientation == .vertical {
attributed.addAttribute(NSAttributedString.Key.verticalGlyphForm, value: true, range: NSMakeRange(0, attributed.length))
}
// 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
}
override func drawText(in rect: CGRect) {
attributed.addAttributes([NSAttributedString.Key.font:self.font], range:NSMakeRange(0, attributed.length))
attributed.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.black , range: NSMakeRange(0, attributed.length))
if self.textAlignment == .center {
var alignment = CTTextAlignment.center
let alignmentSetting = [CTParagraphStyleSetting(spec: .alignment, valueSize: MemoryLayout.size(ofValue: alignment), value: &alignment)]
let paragraphStyle = CTParagraphStyleCreate(alignmentSetting, 1)
CFAttributedStringSetAttribute(attributed, CFRangeMake(0, CFAttributedStringGetLength(attributed)), kCTParagraphStyleAttributeName, paragraphStyle)
}
if orientation == .vertical {
attributed.addAttribute(NSAttributedString.Key.verticalGlyphForm, value: true, range: NSMakeRange(0, attributed.length))
let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: rect.size.height)
drawContext(attributed, textDrawRect: textDrawRect, isVertical: true)
}else{
attributed.addAttribute(NSAttributedString.Key.verticalGlyphForm, value: false, range: NSMakeRange(0, attributed.length))
let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: height)
drawContext(attributed, textDrawRect: textDrawRect, isVertical: false)
}
self.backgroundColor = Style.white
//let textDrawRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: height , height:rect.size.width)
// drawContext(attributed, textDrawRect: textDrawRect, isVertical: vertical!)
}
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 func furigana(String:String) -> NSMutableAttributedString {
let attributed =
String
.replace(pattern: "(|.+?《.+?》)", template: ",$1,")
.components(separatedBy: ",")
.map { x -> NSAttributedString in
if let pair = x.find(pattern: "|(.+?)《(.+?)》") {
let string = (x as NSString).substring(with: pair.range(at: 1))
let ruby = (x as NSString).substring(with: pair.range(at: 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 NSAttributedString.Key: annotation])
} else {
return NSAttributedString(string: x, attributes: nil)
}
}
.reduce(NSMutableAttributedString()) { $0.append($1); return $0 }
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineHeightMultiple = 1.0
paragraphStyle.minimumLineHeight = 5.0
return attributed
}
as you can see, the screenshot show that the label is highter than the text.
Can you help me to fix these problems?