我找到了一个可接受的(如果不是完美的)通过子类化包装的解决方案NSTextStorage
。
在将文本添加到文档末尾时,无论是粘贴还是键入,它的行为都完全符合预期。它在删除或替换文本时也会起作用。唯一有点奇怪的地方是在已经满行的中间插入文本时。这将在插入的文本之前导致换行。它工作正常,但这意味着继续在该位置键入会创建许多短行。
例如,下面的文本在 20 列处换行。原始文本是x
,插入文本是o
。插入的文本从第二行的第 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];
}