2009-05-10 20 views
3

Ich erstelle einen Syntax-Highlighter für das iPhone und um Text mit mehreren Formaten anzuzeigen, habe ich UIView unterklassifiziert und die drawRect:-Methode so geändert, dass jede Zeile mit der richtigen Syntax angezeigt wird Hervorhebung (Hervorhebung erfolgt früher mit RegEx, Text wird mit CGContextShowTextAtPoint() Zeile für Zeile gezeichnet). Alles funktioniert gut, ich speichere jede Textzeile als NSString in einem NSMutableArray, ich handle mit der Tastatur über ein verstecktes UITextField und seine Delegate-Methoden, der Cursor ist ein blinkender CALayer, der mit Berührungen verschoben werden kann und ich habe eine benutzerdefinierte Bildlaufansicht das Scrollen behandelt. Ich habe jedoch zwei Probleme, die ich kann meinen Kopf nicht scheinen um zu wickeln:Erstellen einer benutzerdefinierten Textzeichnungsansicht

  1. Zeilenumbruch, gerade jetzt der Text gerade hält das linke Ende des Bildschirms abgehend. Um die Dinge schnell zu halten, zeichne ich nur die Teile der Ansicht neu, die sich geändert haben (normalerweise nur die zu bearbeitende Zeile, manchmal aber auch die darunter liegenden Zeilen, z. B. wenn Sie auf die Hälfte des Dokuments zurück drücken) mit setNeedsDisplayInRect:. Dies erschwert das Umbrechen von Wörtern, da Sie dann mehr als eine Zeile auf dem Bildschirm zeichnen müssen, obwohl es immer noch nur ein Objekt im Array ist.

  2. UIViews haben eine maximale Inhaltsgröße von 1024x1024, was etwa 64 Zeilen entspricht. Ich brauche die Fähigkeit, mehr als das anzuzeigen. Ich denke darüber nach, mehrere CALayer hintereinander zu verwenden, aber ich habe Probleme beim Zeichnen von Inhalt auf die Ebenen (unter Verwendung von drawLayer:inContext: und drawInContext:).

Also meine Fragen sind:

  • Hat jemand irgendwelche haben, auch allgemeine, Vorschläge, wie eine dieser beiden Punkte zu erreichen. Oder,
  • Hat jemand bereits eine benutzerdefinierte Text-Zeichnung-Ansicht geschrieben, die diese Dinge behandelt, die ich stattdessen verwenden könnte.

Danke,

Kyle

EDIT: Das Scrollen Problem ziemlich gelöst, aber ich immer noch Probleme mit word-wrap bin. Mein Problem ist, dass alles Zeile für Zeile erledigt wird: Die Ansicht wird jeweils um eine Zeile aktualisiert, der Text wird als ein Array von Zeilen gespeichert, der Textmarker markiert jeweils eine Zeile usw. und hat einen einzelnen Index im Array (eins Textzeile) nehmen mehrere Zeilen auf dem Bildschirm auf, wirft einige Probleme auf, zum Beispiel musste ich meinen eigenen beweglichen Cursor implementieren und wenn Sie den Cursor bewegen, muss er in der Lage sein, eine Displayzeile zu drehen (gefunden durch Teilen von touch.x mit Zeilenhöhe) in eine Textzeile (ein Index im Array). Irgendwelche Ideen?

Antwort

0

Es kann am besten sein, Ihren Text innerhalb eines CATiledLayers zu zeichnen, der in Ihrem UIView gehostet wird, um die 1024x1024 Texturgrößenbeschränkung zu umgehen (die auf allen vorhandenen Geräten tatsächlich 2048x2048 beträgt). Als Beispiel für eine Textzeichnung in einem CALayer verweise ich Sie auf die CPTextLayer Klasse innerhalb des Core Plot Frameworks. Diese Ebene (die von der CPLayer-Klasse innerhalb desselben Frameworks erbt) erstellt plattformübergreifendes (Mac und iPhone) Text-Rendering in einem CALayer. Sie können es möglicherweise erweitern, um als CATiledLayer für längere Textblöcke zu arbeiten.

Eine Sache zu beachten ist, dass plattformspezifische DrawAtPoint: Methoden in diesem Layer anstelle der CGContextShowTextAtPoint() - Funktion verwandt werden, die Sie verwenden. Der Grund dafür ist, dass CGContextShowTextAtPoint() nur mit ASCII-Text funktioniert, was bedeutet, dass Sie damit kein Unicode-Text-Rendering durchführen können.Es gibt ein Beispiel für die Verwendung von CGContextShowTextAtPoint() zum Zeichnen von Text innerhalb eines Abschnitts # define'd out am Ende der Methode renderAsVectorInContext:.

+0

Danke für Ihre Antwort, wissen Sie, ob drawAtPoint: ist deutlich langsamer als CGContextShowTextAtPoint()? Ich nehme an, es ist, weil Obj-C-Funktionen im Allgemeinen langsamer als C-Funktionen sind, aber das ist nicht immer der Fall. – Kyle

+0

Tatsächlich ist der Aufwand beim Aufruf von Obj-C-Methoden gegenüber C-Funktionen minimal, also würde ich mir darüber keine Sorgen machen. Allerdings sind diese Routinen viel langsamer, weil sie auf dem iPhone Webkit verwenden, um das Textlayout auszuführen. Ob dies zu einem Problem für Sie wird, hängt davon ab, wie oft Sie den Text erneut rendern. Ich benutze es überall in Pi Cubed, die sehr gute Renderleistung hat: http://www.sunsetlakesoftware.com/picubed. –

+0

Nur für zukünftige Referenz habe ich einen einfachen Benchmark, der DrawAtPoint mit CGContextShowTextAtPoint verglichen. Ich zeichnete 36 Zeichenketten 1000 mal an zufälligen y-Stellen über den Bildschirm und hier ist, was ich bekam (auf einem 1g iPod touch): CGContextShowTextAtPoint - 99 Refreshes/Sek., DrawAtPoint - 75 Refreshes/Sek. Die CG-Methode ist also deutlich schneller. – Kyle

1

Sie sollen zunächst einige Zeit zu verstehen verbringen, wie dieses Problem auf Mac gelöst wurde:

http://developer.apple.com/documentation/Cocoa/Conceptual/TextArchitecture/Tasks/AssembleSysByHand.html

http://developer.apple.com/documentation/Cocoa/Conceptual/TextLayout/TextLayout.html

Insbesondere Sie mit der Linie Fragment Generation vertraut machen sollten, was das Problem ist, du versuchst, nach einem Wortumbruch zu suchen, und du solltest die Glyphengenerierung verstehen, um guten Text zu machen. Sie müssen natürlich nicht die ganze Flexibilität von NSTypesetter oder NSLayoutManager implementieren, aber das Textsystem auf dem Mac ist unglaublich mächtig, und Sie sollten von seinem Beispiel lernen. Das Implementieren von etwas, das NSAttributedString für iPhone ähnlich ist, kann für Sie wertvoll sein und Ihre Leistung verbessern.

Es sei denn, Sie bewegen Dinge viel (für die dies am besten in einem UIScrollView funktionieren würde), ich denke nicht, dass Sie CALayers hier verwenden sollten. Das scheint für das Problem übertrieben zu sein und könnte sich sogar negativ auf die bereits von UIScrollView bereitgestellten Optimierungen auswirken. Wenn Leistungsprobleme auftreten, stellen Sie zunächst sicher, dass Sie keine unnötigen Berechnungen in Ihrem drawRect ausführen:

+0

Danke Rob, ich werde mir diese Dokumente ansehen. Der einzige Grund, warum ich zu CALayers ging, war, die 1024 (oder 2048) Pixel-Höhenbegrenzung für Ansichten zu umgehen. Ich würde mehrere Ebenen verwenden, um dies zu erweitern. – Kyle

+0

In Bezug auf die Höhe der Ansicht, anstatt die gesamte Ansicht (essen eine willkürliche Menge an Speicher), würde ich 5-7 Ansichten, die jeweils die Größe eines Bildschirms und stapeln sie in einem UIScrollView. Während der Benutzer scrollt, tauscht man die unteren nach oben oder umgekehrt. Dies ist sehr ähnlich zu einem UITableView, und Sie sollten in Betracht ziehen, dies nur als UITableView zu implementieren, damit Sie alle seine Anzeigeoptimierungen erhalten. Das Problem mit UITableView besteht darin, dass es keine Möglichkeit gibt, einzelne Zellen als fehlerhaft zu markieren. Daher müssen Sie die Daten erneut laden, wenn sich etwas ändert. Nicht gut, wenn das editierbar ist. –

+0

Ich plante so etwas und verwendete die delegierten Methoden von scroll views, um mehr Text zu zeichnen. In diesem Fall wären Layer besser als Views, weil sie leichter sind oder der Unterschied vernachlässigbar ist. Es ist editierbar, Tabellenansichten sind also nicht verfügbar. – Kyle

1

Überprüfen Sie TTSstyledText in Three20 library. Ich bin mir nicht sicher, wie gut es Ihren Zielen entspricht, könnte Ihnen aber als Beispiel dienen. (Die Bibliothek selbst ist ein bisschen aufgebläht, aber ist eine wunderbare Quelle zu betrachten.)

+0

+1 für Three20. Josh ist ein Dämon. Diese Codebasis ist ein Wunderwerk, das man sich ansehen und einen Albtraum finden kann. :) – Genericrich

Verwandte Themen