質問するログイン新規登録

回答編集履歴

1

修正

2017/01/15 05:48

投稿

_Kentarou
_Kentarou

スコア8490

answer CHANGED
@@ -1,3 +1,115 @@
1
1
  以下のサイトは`Swift2`ではありますがやりたいことと同じだと思います、参考になるのではないでしょうか。
2
2
 
3
- [ルビを振る](http://qiita.com/woxtu/items/284369fd2654edac2248)
3
+ [ルビを振る](http://qiita.com/woxtu/items/284369fd2654edac2248)
4
+
5
+ `Swift3`で動かしてみました。
6
+
7
+ ```swift
8
+ import UIKit
9
+
10
+ extension String {
11
+ func find(pattern: String) -> NSTextCheckingResult? {
12
+ do {
13
+ let re = try NSRegularExpression(pattern: pattern, options: [])
14
+ return re.firstMatch(
15
+ in: self,
16
+ options: [],
17
+ range: NSMakeRange(0, self.utf16.count))
18
+ } catch {
19
+ return nil
20
+ }
21
+ }
22
+
23
+ func replace(pattern: String, template: String) -> String {
24
+ do {
25
+ let re = try NSRegularExpression(pattern: pattern, options: [])
26
+ return re.stringByReplacingMatches(
27
+ in: self,
28
+ options: [],
29
+ range: NSMakeRange(0, self.utf16.count),
30
+ withTemplate: template)
31
+ } catch {
32
+ return self
33
+ }
34
+ }
35
+ }
36
+
37
+ class View: UIView {
38
+
39
+ override func draw(_ rect: CGRect) {
40
+ let text = [
41
+ "「まさか、|後罪《クライム》の|触媒《カタリスト》を〈|讃来歌《オラトリオ》〉無しで?」",
42
+ "教師たちの狼狽した声が次々と上がる。",
43
+ "……なんでだろう。何を驚いているんだろう。",
44
+ "ただ普通に、この|触媒《カタリスト》を使って|名詠門《チャネル》を開かせただけなのに。",
45
+ "そう言えば、何を|詠《よ》ぼう。",
46
+ "自分の一番好きな花でいいかな。",
47
+ "どんな宝石より素敵な、わたしの大好きな緋色の花。",
48
+ "――『|Keinez《赤》』――",
49
+ "そして、少女の口ずさんだその後に――",
50
+ ]
51
+ .joined(separator: "\n")
52
+
53
+ let attributed =
54
+ text
55
+ .replace(pattern: "(|.+?《.+?》)", template: ",$1,")
56
+ .components(separatedBy: ",")
57
+ .map { x -> NSAttributedString in
58
+ if let pair = x.find(pattern: "|(.+?)《(.+?)》") {
59
+ let string = (x as NSString).substring(with: pair.rangeAt(1))
60
+ let ruby = (x as NSString).substring(with: pair.rangeAt(2))
61
+
62
+ var text: [Unmanaged<CFString>?] = [Unmanaged<CFString>.passRetained(ruby as CFString) as Unmanaged<CFString>, .none, .none, .none]
63
+
64
+ let annotation = CTRubyAnnotationCreate(.auto, .auto, 0.5, &text[0]!)
65
+
66
+ return NSAttributedString(
67
+ string: string,
68
+ attributes: [kCTRubyAnnotationAttributeName as String: annotation])
69
+ } else {
70
+ return NSAttributedString(string: x, attributes: nil)
71
+ }
72
+ }
73
+ .reduce(NSMutableAttributedString()) { $0.append($1); return $0 }
74
+
75
+ var height = 28.0
76
+ let settings = [
77
+ CTParagraphStyleSetting(
78
+ spec: .minimumLineHeight,
79
+ valueSize: Int(MemoryLayout.size(ofValue: height)),
80
+ value: &height)
81
+ ]
82
+ let style = CTParagraphStyleCreate(settings, Int(settings.count))
83
+
84
+ attributed.addAttributes([
85
+ NSFontAttributeName: UIFont(name: "HiraMinProN-W3", size: 14.0)!,
86
+ NSVerticalGlyphFormAttributeName: true,
87
+ kCTParagraphStyleAttributeName as String: style,
88
+ ],
89
+ range: NSMakeRange(0, attributed.length))
90
+
91
+ let context = UIGraphicsGetCurrentContext()
92
+
93
+ context!.setFillColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
94
+ context!.addRect(rect)
95
+ context?.fillPath()
96
+
97
+ context!.rotate(by: CGFloat(M_PI_2))
98
+ context!.translateBy(x: 30.0, y: 35.0)
99
+ context!.scaleBy(x: 1.0, y: -1.0)
100
+
101
+ let framesetter = CTFramesetterCreateWithAttributedString(attributed)
102
+ let path = CGPath(rect: CGRect(x: 0.0, y: 0.0, width: rect.height, height: rect.width), transform: nil)
103
+ let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)
104
+ CTFrameDraw(frame, context!)
105
+ }
106
+ }
107
+
108
+ class ViewController: UIViewController {
109
+ override func loadView() {
110
+ super.loadView()
111
+
112
+ self.view = View()
113
+ }
114
+ }
115
+ ```