CFAttributedStringRefの一文字一文字にルビを振りたい
現状下記のような感じでtextにfuriganaをルビとして振るクラスを実装しているのですがtextに長文を代入するとルビが全体に設置されてしまい段落が変わるとうまく表示されません。
一単語、もしくは一文字一文字にルビを設定するにはどんな方法があるでしょうか?
#import "RubyAnnotationLabel.h"
#import <CoreText/CoreText.h>
@interface RubyAnnotationLabel ()
@property (nonatomic, strong) NSString *text;
@property (nonatomic, strong) NSString *furigana;
@end
@implementation RubyAnnotationLabel {
CTTypesetterRef _typesetter;
NSMutableArray *_lines;
NSInteger _textlocation;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);
transform = CGAffineTransformTranslate(transform, 0, - self.bounds.size.height);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(ctx, CGAffineTransformIdentity);
CGContextTranslateCTM(ctx, 0, ([self bounds]).size.height );
CGContextScaleCTM(ctx, 1.0, -1.0);
_typesetter = CTTypesetterCreateWithAttributedString([self attributedStringRef]);
CTTypesetterRef _typesetternoattr = CTTypesetterCreateWithAttributedString(CFAttributedStringCreate(NULL, (CFStringRef)self.text, NULL));
NSInteger location = 0;
NSInteger length = self.text.length;
while (location < length){
CFIndex count = CTTypesetterSuggestLineBreak(_typesetternoattr, location, self.frame.size.width);
[_lines addObject:[NSValue valueWithRange:NSMakeRange(location, count)]];
location += count;
}
NSInteger limit = _lines.count;
NSInteger x = 0;
NSInteger y = 0;
for (int i = 0; i < limit; i++) {
// 指定位置をベースライン[*1]として描画が開始されるので、1行目は文字サイズ分、
// 2行目以降は行送り分、yの開始位置を移動します。
if(i == 0){
y += self.frame.size.height - 13;
}else{
y -= 15;
}
// 改行位置の取得
NSRange r = [[_lines objectAtIndex:i] rangeValue];
// 描画開始位置を設定。offsetで行頭約物の位置を修正。
CGContextSetTextPosition(context, x, y);
// typesetterから行を生成
CTLineRef ctline = CTTypesetterCreateLine(_typesetter, CFRangeMake(r.location, r.length));
// 描画
CTLineDraw(ctline, context);
// CTLineRefのリリース
CFRelease(ctline);
}
}
// =============================================================================
#pragma mark - Private
// create CFAttributedStringRef
- (CFAttributedStringRef)attributedStringRef {
_lines = [[NSMutableArray alloc] init];
// Ruby Annotation
CFStringRef furiganaRef[kCTRubyPositionCount] = {
(__bridge CFStringRef) self.furigana, NULL, NULL, NULL
};
CTRubyAnnotationRef ruby = CTRubyAnnotationCreate(kCTRubyAlignmentAuto, kCTRubyOverhangAuto, 0.5, furiganaRef);
// Font
CTFontRef font = CTFontCreateWithName(CFSTR("HiraKakuProN-W6"), 10, NULL);
CFStringRef keys[] = { kCTFontAttributeName, kCTRubyAnnotationAttributeName};
CFTypeRef values[] = { font, ruby};
CFDictionaryRef attr = CFDictionaryCreate(NULL,
(const void **)&keys,
(const void **)&values,
sizeof(keys) / sizeof(keys[0]),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFAttributedStringRef attributes = CFAttributedStringCreate(NULL, (__bridge CFStringRef)self.text, attr);
CFRelease(attr);
return attributes;
}
// =============================================================================
#pragma mark - Public
- (void)setText:(NSString *)text withFurigana:(NSString *)furigana {
self.text = text;
self.furigana = furigana;
[self setNeedsDisplay];
}
@end