2013-06-13 14 views
5

Ich habe eine benutzerdefinierte Ansicht, die ich schnell gelernt habe, keine Objektzuordnungen vorzunehmen und alle meine Paint-Zuordnungen in eine andere Methode verschoben, in Ordnung.Vermeidung von Objektzuordnungen in onDraw() (StaticLayout)?

Ich muss ein StaticLayout jedoch für etwas Text verwenden, der etwas spannbares 'Zeug' hatte.

Dies erschien mir sinnvoll, um onDraw zu haben, aber ich werde natürlich gewarnt, dies zu vermeiden. Es ist mir wichtig, dass ich alles in meiner Macht Stehende tue, um Leistungsprobleme zu vermeiden, also versuche ich, dies richtig zu machen.

Ich kann keine Dokumentation finden, die ich verstehen kann, die erklärt, was einige der Parameter zu StaticLayout tatsächlich tun (float spacingmult? Float spacingadd?), Aber die dritte dort denke ich ist maximale Breite für den StaticLayout-Text was ich von onMeasure nur in Bezug auf meine Leinwandgröße bekommen kann. Das lässt mich den Auftrag in onMeasure oder onDraw setzen, von denen es nicht scheint, dass ich es tun soll. Ist es in Ordnung, die StaticLayout-Zuweisung in onDraw zu platzieren, oder gibt es dafür einen besseren Weg?

Hoffe das macht Sinn, ich bin sehr neu dazu. Danke für jede Hilfe.

(edit: Ich gehe davon aus setze diese Aufgabe bei einem Verfahren und Aufruf von OnDraw/onMeasure ist einfach albern und wird von Eclipse mir Warnung stoppen, aber werden nicht wirklich helfen)

Antwort

5

Der Grund für die Warnung, weil, sehr Oftmals müssen Sie ein Objekt nicht mehrmals in einer Zeichenoperation neu erstellen. onDraw() konnte im Vergleich zu anderen Methoden in einem View Hunderte Male aufgerufen werden. Meistens werden die Objekte, die neu erstellt werden, mit den genauen Parametern neu erstellt. In anderen Fällen ist es einfach weniger Aufwand, den Status eines Objekts zu ändern, als ein neues Objekt zu erstellen.

Im Fall von StaticLayout müssen Sie nur einen neuen erstellen, wenn sich der Text ändert oder wenn Sie den Abstand, den Abstand oder die maximale Breite anpassen. Wenn sich der Text häufig ändert, möchten Sie vielleicht DynamicLayout in Erwägung ziehen, die sich jedes Mal neu messen wird. Das erneute Messen kostet mehr Overhead als das Erstellen eines neuen Objekts, aber es passiert nicht, dass es öfter passiert als onDraw() Anrufe.

Wenn sich der Text nicht oft ändert und Sie unbedingt ein StaticLayout verwenden müssen, dann können Sie mit dieser Struktur aufwarten.

StaticLayout myLayout; 
String textSource = defaultSource; 
Paint textPaint = defaultPaint; 
int textWidth = defaultWidth; 

public CustomView(Context ctx) { 
    super(ctx); 
    createLayout(); 
} 

public void setText(String text) { 
    textSource = text; 
    createLayout(); 
} 

public void setWidth(int width) { 
    textWidth = width; 
    createLayout(); 
} 

@Override 
public void onDraw(Canvas canvas) { 
    myLayout.draw(canvas); 
} 

private void createLayout() { 
    myLayout = new StaticLayout(textSource, textPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 0, 1, false); 
} 

Grundsätzlich erstellen Sie nur ein neues Layout, wenn sich etwas ändert. Andernfalls verwenden Sie einfach das letzte Objekt, das Sie erstellt haben.

EDIT:

Eine Möglichkeit, eine Maßübergabe zu überspringen ist selbst View#measure auf der neu Größe verändert Ansicht aufzurufen. So wäre Ihre createLayout() Methode so etwas.

Im Grunde sagt das, was das Layout das Maximum der Ansicht sein kann. Es wird sich messen und es sind Kinder. Das forceLayout() wird auf dem übergeordneten Element (Ihrer benutzerdefinierten Ansicht) aufgerufen, das die anderen Inhalte basierend auf den neuen Messungen neu einrichtet.

Ich sollte beachten, dass ich dies nie mit einem StaticLayout getan habe, also habe ich keine Ahnung, was passieren wird. Es scheint, als ob diese Art der Messung bereits beim Erstellen der Ansicht behandelt wird, aber möglicherweise nicht.

Ich hoffe, das hilft.

+0

Danke, das gab mir eine etwas neue Sichtweise. Das einzige Problem, das ich oben implementieren muss, ist, dass 'textPaint' auf' onMeasure() 'basiert, der bereits aufgerufen wird (der Text wird entsprechend der Canvas-Größe skaliert), ebenso wie die' textWidth' (die festlegt, wann der Text umläuft), so kann ich createLayout() 'im Konstruktor für die erste Betrachtung nicht tun. Ich kann es in 'onMeasure()' setzen, von dem ich anschaue, dass es nicht so oft genannt wird? – Anthony

+0

Der Text ändert tatsächlich eine Menge, die Ansicht, an der ich arbeite, ist eigentlich eine kreisförmige SeekBar, die ich gemacht habe, und das StaticLayout wird für Text in der Mitte verwendet, der sich auf den Fortschritt der SeekBar bezieht. Wenn Sie also Ihren Finger über den Kreis ziehen, ändert sich der Wert ständig. Ich dachte, obwohl der Wert sich sehr ändert, wird die Länge immer auf drei Stellen aufgefüllt, so dass das Layout niemals in der Größe angepasst werden müsste und daher StaticLayout in Ordnung wäre. Ich kann so wenig Dokumentation über statische/dynamische Layouts finden, also bin ich mir nicht sicher, ob das korrekt ist. Jede Hilfe wieder geschätzt. – Anthony

+0

Endlich (glaube ich) habe ich 'onMeasure()' durch 'onSizeChanged()' ersetzt, da meine Layout-Anforderungen einfach sind und der erste Aufruf von 'createLayout()' anstelle von 'onMeasure()' gesetzt wird. Lint scheint die Objektzuweisung in 'onSizeChanged()' aus irgendeinem Grund nicht zu stören, mag sie aber in 'onMeasure()' nicht. Ich würde mir vorstellen, dass diese beiden Methoden die gleiche Anzahl von Malen genannt werden, also keine Ahnung, warum es in einem gut ist und nicht in dem anderen, aber wie auch immer, es scheint in Ordnung zu sein. Mein Hauptanliegen war die Zuweisung von 'onDraw()', was ich getan habe. Danke noch einmal. – Anthony