問題
TextKit がどのように機能し、それを使用してテキスト エディターを作成する方法を理解する必要があります。エンドユーザーが操作する可視テキストのみを描画する方法を理解するか、processEditing メソッドで変更されたテキスト範囲全体に属性を適用せずに、可視テキストのみに属性を遅延適用する方法を決定する必要があります。
バックグラウンド
iOS 7 は TextKit とともに登場しました。私は、TextKit を完全に実装するトークナイザーとコードを持っています (Apple の TextKitDemo プロジェクトを参照してください。リンクは以下に示されています)...そして動作します。しかし、それは本当に遅いです。NSTextStorage によってテキストが解析されると、同じスレッドの processEditing メソッドで、編集されたテキストの範囲全体を色付けする必要があります。スレッドへの作業のオフロードは役に立ちません。それは単に遅すぎる。変更された範囲のみを再帰属できるようになりましたが、範囲が大きすぎるとプロセスが遅くなります。状況によっては、変更が行われた後にドキュメント全体が無効になる可能性があります。
ここに私が持っているいくつかのアイデアがあります。これらのいずれかが機能するかどうか、または正しい方向に私を微調整するかどうかを教えてください.
1) 複数の NSTextContainer
ドキュメントを読むと、NSLayoutManager 内に複数の NSTextContainers を追加できるようです。これを行うことで、NSTextContainer に描画できる行数を定義できるだけでなく、どの NSTextContainer がエンドユーザーに表示されるかを知ることもできるはずです。このルートに行く場合、それが実現可能かどうかを確認するためだけに多くの時間を投資する必要があることを私は知っています. 最初のテストでは、必要な NSTextContainer は 1 つだけであることが示唆されています。したがって、NSLayout をサブクラス化するか、レイアウト マネージャーがどのテキストをどのテキスト コンテナーに入れるかを決定するラッパーを作成する必要があります。うん。また、特定の NSTextContainer を描画する時が来たことを TextKit がどのように知らせてくれるのかわかりません。
2) NSLayoutManager を使用した範囲の無効化
invalidateLayoutForCharacterRange:actualCharacterRange: を使用して、layoutManager を無効にします。しかし、これは実際に何をし、どのようにテキスト帰属フェーズをオフロードするのでしょうか? 特定のテキストを強調表示する必要があることはいつ通知されますか? また、NSLayoutManager が遅延してグリフを描画することがわかります...どのように? いつ?これはどのように役立ちますか? 実際にテキストをレイアウトする前にバッキング文字列に属性を付けることができるように、この呼び出しを利用するにはどうすればよいですか?
3) NSLayoutManager drawGlyphsForGlyphRange:atPoint: メソッドをオーバーライドします。
私は本当にこれをしたくありません。そうは言っても、Mac OS X では、NSAttributedStrings には、スタイル情報が表示のみに使用される一時的な属性という概念があります。これにより、強調表示のプロセスが大幅に高速化されます。問題は、iOS 7 TextKit フレームワークに存在しないことです (または、そこにあり、私はそれについて知りません)。このメソッドをオーバーライドすることで、一時的な属性を使用して得られるのと同じタイプの速度が得られると信じています... NSTextStorage 属性に触れることなく、このメソッドですべてのレイアウト、色、および書式設定の質問に答えることができるためです。ストリング。唯一の問題は、このメソッドが NSLayoutManager クラスで提供されている他のメソッドに関連してどのように機能するかわかりません。幅と高さの状態を保持していますか?小さすぎる場合、NSTextContainer のサイズを変更しますか? また、テキスト バッファーに追加された文字のグリフのみを描画します。画面全体を再描画しません。ごく一部にすぎません...それで問題ありません。これをどのように扱うかについていくつかのアイデアがあります...しかし、グリフをレイアウトしたいという気持ちは本当にありません。これは大変な作業であり、これを行う良い例は見つかりませんでした。
私はあなたが提供しなければならない助けを大いに感謝します.
感謝の気持ちを込めて、ここ数年で使用したすべてのフレームワークとリファレンスをリストします。それらがあなたの役に立てば幸いです。
構文強調表示フレームワーク:
- http://colorer.sourceforge.net/
- https://github.com/MikeJ1971/Glint (文字列、コメントなどには対応していません)
- https://projects.gnome.org/gtksourceview/features.html (トークン生成用の適切なライブラリを提供します。GTK で動作しますが、別のレイアウト マネージャー用に書き直される可能性があります)
- http://parsekit.com/ (優れたパーサー。ただし、範囲を修復する必要がある場合は、API をラップしてステート マシンを作成する必要があります)
- http://svn.gna.org/viewcvs/etoile/trunk/Etoile/Languages/LanguageKit/
- https://github.com/CodaFi/IDEKit (素晴らしい仕事です。このコードにはたくさんの良いアイデアがあります。私の問題は、範囲を修復する方法がまったくわからないことです)
- http://www.crimsoneditor.com/ (古い Windows コード エディター。非常に優れたトークナイザーを備えています。少し読みにくいですが、正規表現は使用していません。上記のどのフレームワークよりもはるかに高速です)
資力:
- http://cocoafactory.com/blog/2012/10/29/how-to-use-custom-nsattributedstring-attributes/
- https://github.com/objcio/issue-5-textkit
- http://alexgorbatchev.com/SyntaxHighlighter/
- http://docs.xamarin.com/samples/TextKitDemo/ (Apple のデモ)
- http://cocoadev.com/ImplementSyntaxHighlighting (必ずすべての子記事を読んでください。すばらしい内容です)
これらのフレームワークのほとんどは同じです。範囲のコンテキスト切り替えを考慮しない (またはコンテキストを提供するためにラッパーを作成する必要がある) か、ユーザーがテキスト (文字列、複数行のコメントなど) を変更してもコンテキスト範囲を修復しません。最後の要件は非常に重要です。トークナイザーが変更の影響を受ける範囲を特定できない場合、文字列全体を再度解析して属性を付与する必要があるためです。これに対する唯一の例外は、Crimson Editor です。このトークナイザーの問題は、トークン化時に状態を保存しないことです。描画時に、アルゴリズムはトークンを使用して描画の状態を判断します。ドキュメントの先頭から始まり、テキストの表示範囲に到達するまで。言うまでもなく、
もう 1 つの問題は、フレームワークが Apple と同じ MVC パターンに従っていないことです。これは当然のことです。完全に機能するエディターを持つフレームワークはすべて、フレームワークが構築されている API (つまり、GTK、Windows など) によって提供されるフックを使用します。これにより、画面のどこにいつ描画するかに関する情報が提供されます。私の場合、TextKit では、変更された範囲全体を processEditing に帰属させる必要があるようです。
多分私の観察は間違っています。(そうであることを願っています!!)おそらく、たとえばParseKitは、私が必要としている目的で機能しますが、その使用方法がわかりません。もしそうなら、私に知らせてください!そして、ありがとう!