我正在尝试创建一个行为类似于一系列打字机页面的NSTextView - 每个页面都有固定数量的行和列可用。
底层表示理想地匹配显示,而显示又匹配文件格式。页面以换页符'\f'
结尾。例如,两个4x4页面在保存时看起来像这样(字符之间的空格以便于阅读):
T H I S \n
P A G E \n
I S \n
F U L L \n
\f
N O T \n
T H I S \n
O N E \n
\n
\f
需要注意的一些事项:
我尝试了一些方法,比如将文本转换为NSArray
行并在每个textDidChange
通知上拆分长行,然后将文本设置为连接行,但这样做效率很低,如果键入发生在除文档末尾之外的任何地方,则丢失光标位置。
最后,我认为我希望这个行为是一个填充了空白的大页面,并且只能在覆盖模式下进行打字,但会在行尾包装。我不知道从哪里开始这种方法。有什么建议吗?
答案 0 :(得分:0)
通过子类化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];
}