サブクラス化によるラッピングの完全ではないにしても、許容できる解決策を見つけましたNSTextStorage
。
貼り付けでも入力でも、ドキュメントの最後にテキストを追加すると、完全に期待どおりに動作します。また、テキストを削除または置換するときにも動作します。少し奇妙なのは、すでにいっぱいになっている行の途中にテキストを挿入するときだけです。これにより、挿入されたテキストの直前で折り返しが発生します。正常に機能しますが、その位置で入力を続けると、多数の短い行が作成されることを意味します。
たとえば、以下のテキストは20列で折り返されます。元のテキストはx
、、挿入されたテキストはo
です。挿入されたテキストは、2行目の8文字目から始まります。
xxxxxxxxxxxxxxxxxxxx
xxxxxxx
ooooooo
ooooooo
oooooooxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
以下のコード:
- (void)breakLinesInArray:(NSMutableArray *)lines atLength:(NSUInteger)length
charsPreceding:(NSUInteger)preceding charsFollowing:(NSUInteger)following
{
NSUInteger line = 0;
while (line < [lines count]) {
NSUInteger maxLineLength = length;
if (line == 0) {
maxLineLength = length - preceding;
} else if (line == [lines count] - 1) {
maxLineLength = length - following;
}
NSString *original = [lines objectAtIndex:line];
if (maxLineLength > 0 && [original length] > maxLineLength) {
NSString *first = [original substringToIndex:maxLineLength];
NSString *second = [original substringFromIndex:maxLineLength];
[lines replaceObjectAtIndex:line withObject:first];
[lines insertObject:second atIndex:line + 1];
}
++line;
}
}
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str
{
static const NSUInteger kMaxLineLength = 20;
NSString *text = [text_ string];
NSUInteger firstLineStart = 0;
NSUInteger lastLineEnd = 0;
NSMutableArray *lines = [NSMutableArray arrayWithArray:[str componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]];
[text getLineStart:&firstLineStart end:nil contentsEnd:&lastLineEnd forRange:range];
NSUInteger firstLineStartFragmentLength = range.location - firstLineStart;
NSUInteger lastLineEndFragmentLength = lastLineEnd - (range.location + range.length);
[self breakLinesInArray:lines atLength:kMaxLineLength charsPreceding:firstLineStartFragmentLength charsFollowing:lastLineEndFragmentLength];
NSString *newString = [lines componentsJoinedByString:@"\n"];
NSInteger changeInLength = [newString length] - range.length;
NSInteger newLastLineLength = firstLineStartFragmentLength + lastLineEndFragmentLength + changeInLength;
if ((firstLineStartFragmentLength || lastLineEndFragmentLength) && newLastLineLength > (NSInteger)kMaxLineLength) {
newString = [@"\n" stringByAppendingString:newString];
++changeInLength;
}
[text_ replaceCharactersInRange:range withString:newString];
[self edited:NSTextStorageEditedCharacters range:range changeInLength:changeInLength];
}