UPDATE: finally I’ve found a solution but I’ve had to use Core Text and not Text Kit.
and this is the what I’ve done, but I’ve 2 problem:
1)I would like that the text use break line mode if the text is going out of the context. how can I do it?
2) I’m creating an uiview that show asian text (preferably japanese) with phonetic guide (in japanese: furigana). but when the app go in landscape, the view, because there are constrains fits to superview but the text is stretched. How can I solve the problem?
this is code:
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 GQAsianTextView: UIView {
var text:String = ""
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 =
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: UIFont(name: "DFKyoKaSho-W4-WIN-RKSJ-H", size: 20.0)!,
NSVerticalGlyphFormAttributeName: false,
kCTParagraphStyleAttributeName as String: style,
],
range: NSMakeRange(0, attributed.length))
case .vertical:
attributed.addAttributes([
NSFontAttributeName: UIFont(name: "DFKyoKaSho-W4-WIN-RKSJ-H", size: 20.0)!,
NSVerticalGlyphFormAttributeName: true,
kCTParagraphStyleAttributeName as String: style,
],
range: NSMakeRange(0, attributed.length))
}
/*
attributed.addAttributes([
NSFontAttributeName: UIFont(name: "DFKyoKaSho-W4-WIN-RKSJ-H", size: 20.0)!,
NSVerticalGlyphFormAttributeName: true,
kCTParagraphStyleAttributeName as String: style,
],
range: NSMakeRange(0, attributed.length))
*/
let context = UIGraphicsGetCurrentContext()
//context!.setFillColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
context!.setFillColor(red: 0.984, green: 0.922, blue: 0.69, alpha: 1.0)
context!.addRect(rect)
context?.fillPath()
switch orientation! {
case .horizontal:
context!.translateBy(x: 30.0, y: 420.0)
context!.scaleBy(x: 1.0, y: -1.0)
case .vertical:
context!.rotate(by: CGFloat(M_PI_2))
context!.translateBy(x: 30.0, y: 35.0)
context!.scaleBy(x: 1.0, y: -1.0)
}
let framesetter = CTFramesetterCreateWithAttributedString(attributed)
let path = CGPath(rect: CGRect(x: 0.0, y: 0.0, width: rect.height, height: rect.width), transform: nil)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)
CTFrameDraw(frame, context!)
}
}
in MyViewController
let asianText = GQAsianTextView(frame: CGRect(x: 0, y: 64, width: 420, height: 400))
asianText.text = [
"「まさか、|後罪《クライム》の|触媒《カタリスト》を〈|讃来歌《オラトリオ》〉無しで?」",
"|教師《きょうし》たちの狼狽した声が次々と上がる。",
"……なんでだろう。何を驚いているんだろう。",
"ただ普通に、この|触媒《カタリスト》を使って|名詠門《チャネル》を開かせただけなのに。",
"そう言えば、何を|詠《よ》ぼう。",
"自分の一番好きな花でいいかな。",
"どんな宝石より素敵な、わたしの大好きな緋色の花。",
"――『|Keinez《赤》』――",
"そして、少女の口ずさんだその後に――",
]
.joined(separator: "\n")
asianText.orientation = textOrientation.vertical
asianText.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(asianText)
let viewDictionary = ["asianLabel":asianText]
let asianText_POS_H = NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[asianLabel]-8-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary)
let asianText_POS_V = NSLayoutConstraint.constraints(withVisualFormat: "V:|-64-[asianLabel]-8-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary)
self.view.addConstraints(asianText_POS_H)
self.view.addConstraints(asianText_POS_V)
These are the problems: stretched character and no breaking line mode
Can you help me?
thank you very much