ProblemaCreazione di un editor di testo per iOS 7
ho bisogno di capire come funziona TextKit e come posso usarlo per costruire un editor di testo. Ho bisogno di capire come disegnare SOLO il testo visibile che l'utente finale interagisce o determinare come farei per applicare pigramente gli attributi al testo visibile solo senza applicare attributi all'intero intervallo di testo modificato nel metodo processEditing.
Sfondo
iOS 7 è uscito con TextKit. Ho un tokenizer e codice che implementa completamente TextKit (fai riferimento al progetto TextKitDemo di Apple - un collegamento è fornito di seguito) ... e funziona. Tuttavia, è VERAMENTE lento. Poiché il testo viene analizzato da NSTextStorage, è necessario colorare TUTTA la gamma del testo modificato, nel metodo processEditing, sullo stesso thread. Offload del lavoro su una discussione non aiuta. È semplicemente troppo lento. Sono arrivato al punto in cui posso re-attribuire solo gli intervalli modificati, ma se l'intervallo è troppo grande il processo sarà lento. In alcune condizioni l'intero documento potrebbe essere invalidato dopo che è stata apportata una modifica.
Ecco alcune idee che ho. Per favore fatemi sapere se qualcuno di questi funzionerà o forse mi spingerà nella giusta direzione.
1) NSTextContainers multipli
Leggendo la documentazione risulta che posso aggiungere più NSTextContainers all'interno di un NSLayoutManager. Presumo che in questo modo dovrei essere in grado di definire non solo il numero di righe che possono essere disegnate in NSTextContainer, ma dovrei anche essere in grado di sapere quale NSTextContainer è visibile all'utente finale. So che se seguirò questa strada avrò bisogno di investire molto tempo solo per vedere se è fattibile. I test iniziali suggeriscono che è necessario un solo NSTextContainer. Quindi dovrei sottoclasse NSLayout o creare un wrapper in cui il gestore del layout determini quale testo debba entrare in quale contenitore di testo. Che schifo. Inoltre, non ho idea di come TextKit mi faccia sapere che è ora di disegnare un particolare NSTextContainer ... forse non è così che funziona!
2) invalidando Intervalli w/NSLayoutManager
Annullamento della LayoutManager utilizzando l'invalidateLayoutForCharacterRange: actualCharacterRange :. Ma cosa fa effettivamente questo e come scaricherà la fase di attribuzione del testo? Quando mi fa sapere che un particolare testo deve essere evidenziato? Inoltre, vedo che NSLayoutManager disegnerà pigramente glifi ... come? quando? Come mi aiuta? Come posso sfruttare questa chiamata in modo da poter attribuire la stringa di accompagnamento prima che il testo venga effettivamente pubblicato?
3) Over-riding del NSLayoutManager drawGlyphsForGlyphRange: atPoint: metodo.
Davvero non voglio farlo. Detto questo, in Mac OS X, NSAttributedStrings ha questo concetto di attributi temporanei in cui le informazioni di stile vengono utilizzate solo per la presentazione. Questo accelera il processo di evidenziazione GRANDE! Il problema è che non esiste nel framework TextKit di iOS 7 (o è lì e io non ne so nulla). Credo che superando questo metodo mi darà lo stesso tipo di velocità che otterresti usando gli attributi temporanei ... potrei rispondere a tutte le domande di layout, colore e formattazione in questo metodo senza mai toccare il NSTextStorage attribuito stringa. L'unico problema è che non so come questo metodo funzioni in relazione agli altri metodi forniti nella classe NSLayoutManager. Mantiene lo stato della larghezza e dell'altezza? Modifica la dimensione del NSTextContainer quando è troppo piccolo? Inoltre, disegna solo glifi per i caratteri che sono stati aggiunti nel buffer di testo. Non rielabora l'intero schermo. solo una piccola parte di esso ... e va benissimo.Ho alcune idee su come potrei lavorare con questo ... ma non ho alcun desiderio di impaginare i glifi. Questo è MODO troppo lavoro e non ho trovato un buon esempio che faccia questo.
Apprezzerei molto l'aiuto che hai da offrire.
Come ringraziamento, sto elenca tutti i quadri e dei riferimenti che ho usato nel corso degli ultimi anni, che mi hanno aiutato ad arrivare dove sono ora, nella speranza che essi sono utili a voi.
Sintassi quadri che evidenziano:
- http://colorer.sourceforge.net/
- https://github.com/MikeJ1971/Glint (Non supporta le stringhe, commenti, ecc)
- https://projects.gnome.org/gtksourceview/features.html (Fornisce un lib decente per la generazione di token Funziona con GTK, ma potrebbe essere potenzialmente. riscritto per un gestore di layout diverso)
- http://parsekit.com/ (buon parser, tuttavia, è necessario avvolgere l'API per creare una macchina a stati quando è necessario riparare intervalli)
- http://svn.gna.org/viewcvs/etoile/trunk/Etoile/Languages/LanguageKit/
- https://github.com/CodaFi/IDEKit (INCREDIBILE lavoro. C'è un sacco di buone idee in questo codice. Il mio problema è che non ho assolutamente idea di come ripari le gamme, o anche se lo faccia)
- http://www.crimsoneditor.com/ (Un vecchio editor di codice di Windows. Ha un ottimo tokenizer - anche se un po 'difficile da leggere. . utilizzare espressioni regex detto questo, ho basato la mia logica pegno fuori di questo codice ed è molto più veloce rispetto a qualsiasi dei quadri di cui sopra)
Risorse:
- 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/ (demo di Apple)
- http://cocoadev.com/ImplementSyntaxHighlighting (assicuratevi di leggere tutti gli articoli per bambini. Grandi cose)
La maggior parte di queste strutture è la stessa. Non tengono conto del cambio di contesto (o del wrapper per fornire il contesto) per gli intervalli o non riparano gli intervalli di contesto mentre un utente modifica il testo (come stringhe, commenti su più righe, ecc.). L'ultimo requisito è MOLTO importante. Perché se un tokenizzatore non è in grado di determinare quali intervalli sono interessati da una modifica, si finirà per dover analizzare e attribuire nuovamente l'intera stringa. L'unica eccezione a questo è il Crimson Editor. Il problema con questo tokenizer è che non salva stato al momento della tokenizzazione. Al momento del disegno, l'algoritmo utilizza i token per determinare lo stato del disegno. Inizia dalla parte superiore del documento, fino a raggiungere l'intervallo di testo visibile. Inutile dire che l'ho ottimizzato mettendo in cache lo stato del documento in alcune parti del documento.
L'altro problema è che i framework non seguono lo stesso pattern MVC di Apple, il che è normale. I framework che hanno un editor di lavoro completo usano tutti gli hook, forniti dall'API su cui sono costruiti (es. GTK, Windows, ecc.), Che fornisce loro informazioni su dove e quando disegnare su quale parte dello schermo. Nel mio caso, TextKit sembra richiedere l'attribuzione dell'intero intervallo modificato in processEditing.
Forse le mie osservazioni sono errate. (Spero che lo siano !!) Forse, ParseKit per esempio, funzionerà per quello che mi serve e semplicemente non capisco come usarlo. Se è così, per favore fatemelo sapere! E grazie ancora!
Se qualcuno tenta di implementare i suggerimenti di cui sopra mi farà sapere come è andata? Mi piacerebbe sentire le tue scoperte! Grazie! – PeqNP
Ho dimenticato di aggiungere una cosa. Ho anche provato a sovrascrivere gli attributi NSLayoutManagerAtIndex: effectiveRange :. Presumo che questo restituisca un NSDictionary con coppie chiave/valore costituite da NSForegroundColorAttributeName/UIColor, ecc. Tuttavia, ogni volta che tento di restituire un dizionario _basic_ con questa coppia chiave/valore, il programma si blocca ... ma, questo potrebbe essere il luogo in cui potrei, potenzialmente, fornire pigramente gli attributi ... questo presuppone che gli attributi vengano interrogati pigramente. Posso solo supporre che avrei bisogno di invalidare l'intervallo di testo che è cambiato in modo che anche questo funzioni. – PeqNP
Penso che potrei averlo; se riesco a determinare l'intervallo di testo visibile all'utente, potrei applicare SOLO attributi a quell'intervallo in processEditing e contrassegnare gli intervalli invalidati, prima e dopo il testo visibile, con un attributo personalizzato (o un elenco di NSRanges, che mai). Quindi scaricherò il lavoro rimanente, solo per il testo invalidato, in un processo separato. – PeqNP