Peq*_*qNP 15 syntax-highlighting objective-c ios parsekit textkit
问题
我需要了解TextKit的工作原理以及如何使用它来构建文本编辑器.我需要弄清楚如何仅绘制最终用户与之交互的可见文本,或者确定如何在不将属性应用于processEditing方法中的整个更改范围的文本的情况下懒惰地将属性应用于可见文本.
背景
iOS 7推出了TextKit.我有一个完全实现TextKit的tokenizer和代码(参考Apple的TextKitDemo项目 - 下面提供了一个链接)......它的工作原理.但是,它真的很慢.在通过NSTextStorage解析文本时,它要求您在processEditing方法中在同一线程上着色已编辑文本的ENTIRE范围.将工作卸载到线程没有帮助.这太慢了.我到了可以仅重新定义修改范围的点,但是如果范围太大,则过程将变慢.在某些情况下,整个文档可能会在更改后失效.
以下是我的一些想法.如果其中任何一个有用,或者可能在正确的方向上推动我,请告诉我.
1)多个NSTextContainers
阅读文档似乎我可以在NSLayoutManager中添加多个NSTextContainer.我假设通过这样做我不仅可以定义可以在NSTextContainer中绘制的行数,而且我还应该能够知道哪个NSTextContainer对最终用户可见.我知道,如果我走这条路,我需要投入大量时间才能看出它是否可行.初步测试表明您只需要一个NSTextContainer.所以我必须子类化NSLayout或创建一个包装器,布局管理器确定哪个文本进入哪个文本容器.呸.此外,我不知道TextKit如何让我知道是时候绘制一个特定的NSTextContainer ...也许这不是它的工作方式!
2)使用NSLayoutManager使范围无效
使用invalidateLayoutForCharacterRange:actualCharacterRange:使layoutManager无效.但这实际上做了什么以及如何卸载文本归属阶段?什么时候让我知道需要突出显示特定文本?另外,我看到NSLayoutManager会懒洋洋地绘制字形......怎么样?什么时候?这对我有什么帮助?如何点击此调用以便在实际布置文本之前我可以将支持字符串归属?
3)覆盖NSLayoutManager drawGlyphsForGlyphRange:atPoint:方法.
我真的不想这样做.话虽这么说,在Mac OS X中,NSAttributedStrings具有临时属性的概念,其中样式信息仅用于表示.这加快了突出显示的过程!问题是,它在iOS 7 TextKit框架中不存在(或者它就在那里,我只是不知道它).我相信通过覆盖这种方法,它会给我与使用临时属性所获得的相同类型的速度......因为我可以回答此方法中的所有布局,颜色和格式问题,而无需触及NSTextStorage归因串.唯一的问题是,我不知道这个方法如何与NSLayoutManager类中提供的其他方法相关.它是否保持宽度和高度的状态?当它太小时,它是否会修改NSTextContainer的大小?此外,它仅为已在文本缓冲区中添加的字符绘制字形.它不会重新绘制整个屏幕.它只是它的一小部分......而且非常好.我有一些关于如何使用它的想法...但我真的不想布置字形.这是太多的工作,我没有找到一个很好的例子来做到这一点.
非常感谢您提供的任何帮助.
谢谢你,我列出了过去几年我用过的所有框架和参考资料,这些框架和参考资料帮助我到达了现在的位置,希望它们对你有所帮助.
突出显示框架的语法:
资源:
大多数这些框架都是相同的.它们要么不考虑上下文切换(或者你必须编写包装器以提供上下文),要么它们不修复上下文范围,因为用户修改了文本(例如字符串,多行注释等).最后一项要求非常重要.因为如果标记生成器无法确定哪些范围受更改影响,则最终必须再次解析并归因整个字符串.唯一的例外是Crimson Editor.此标记化程序的问题是它在标记化时不保存状态.在绘制时,算法使用标记来确定绘图的状态.它从文档的顶部开始,直到达到可见的文本范围.不用说,
另一个问题是框架不遵循与Apple相同的MVC模式 - 这是预期的.具有完整工作编辑器的框架都使用由它们构建的API(即GTK,Windows等)提供的钩子,这些钩子为它们提供了绘制到屏幕的哪个部分的位置和时间的信息.在我的例子中,TextKit似乎要求您在processEditing中归因整个更改的范围.
也许我的观察是错误的.(我希望它们是!!)也许,ParseKit,例如,将适用于我需要它做什么,我只是不明白如何使用它.如果是这样,请告诉我!再次感谢!
我想到了.我没有使用上面的任何建议.话虽这么说,我现在得到的表现简直令人难以置信.请记住YMMV.标记和缓存关于字符串的元数据的方式可能与我不同.但是,我能够输入一个1400行的PHP文件,任何一个更改完成只需0.015秒.简直不可思议.
这是我采取的方法:
我的UIViewController是UITextViewDelegate和UIScrollViewDelegate的委托.
当调用UITextViewDelegate.textViewDidChange:时,我确定最终用户当前可以看到哪个文本范围.我通过使用现有的子类UITextView并将此方法添加到其中来完成此操作:
- (NSRange)visibleRangeOfText
{
CGRect bounds = self.bounds;
UITextPosition *start = [self characterRangeAtPoint:bounds.origin].start;
UITextPosition *end = [self characterRangeAtPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))].end;
return NSMakeRange([self offsetFromPosition:self.beginningOfDocument toPosition:start],
[self offsetFromPosition:start toPosition:end]);
}
Run Code Online (Sandbox Code Playgroud)
之后,我将范围传递给子类NSTextStorage对象,然后它将执行魔术以确定需要突出显示哪些行.
UIScollViewDelegate方法调用也是如此.根据查看视图的哪个部分,我将可见范围传递给我的子类NSTextStorage调用,并确定这些行是否已被归因等.
我意识到我要离开很多读者.我最终使用了我目前拥有的东西,并稍微调整了一下以使用上述实现.
我想分享一些我在实现这个时发现有趣的发现:
1)如果您试图突出显示光标所在的当前行上方的任何文本,您可能会看到光标在视图中"跳跃",然后回到原来的位置.我几乎肯定这是由NSTextStorage.processEditing方法调用引起的.我能够把它带到系统只突出被修改的行的地方......所以这个问题现在已经消失了.
2)最初我这样做是为了防止光标跳转:
NSRange selectedRange = [textView selectedTextRange];
[textView setScrollEnabled:NO];
NSRange visibleRange = [textView visibleRangeOfText];
[textStorage applyAttributesToRange:visibleRange];
[textView setScrollEnabled:YES];
Run Code Online (Sandbox Code Playgroud)
它工作...但[textView setScrollEnabled:NO]调用对性能造成了巨大的打击.单独使用该命令花了将近3/4秒来完成1400行文件.我不确定是什么导致它变慢但我认为值得一提.
归档时间: |
|
查看次数: |
2826 次 |
最近记录: |