2013-06-13 8 views
5

Ho una vista personalizzata che ho imparato rapidamente a non eseguire allocazioni di oggetti e spostato tutte le mie allocazioni Paint in un metodo diverso, bene.Evitare allocazioni di oggetti in onDraw() (StaticLayout)?

Ho tuttavia bisogno di utilizzare uno StaticLayout per un testo che ha applicato alcune "cose" utilizzabili.

layoutBpm = new StaticLayout(bpmValue, 
      textPaintBPM, arcRadius, Layout.Alignment.ALIGN_NORMAL, 0, 1, 
      false); 

    layoutBpm.draw(canvas); 

Mi sembrava ragionevole avere in onDraw, ma ovviamente mi avverto di evitarlo. Per me è importante fare tutto il possibile per evitare problemi di prestazioni, quindi cerco di farlo correttamente.

Non riesco a trovare alcuna documentazione che possa capire che spiega quali sono effettivamente alcuni dei parametri di StaticLayout (float spacingmult? Float spacingadd?), Ma il terzo lì penso sia la larghezza massima per il testo StaticLayout che posso ottenere solo da onMeasure in relazione alle dimensioni della mia tela. Questo mi lascia desiderare di mettere il compito su onMeasure o suDraw, nessuno dei quali sembra che io sia destinato a fare. Va bene inserire l'assegnazione di StaticLayout in onDraw o esiste un modo migliore per farlo?

Spero che questo abbia senso, sono molto nuovo a questo. Grazie per tutto l'aiuto.

(edit:? Presumo mettere questo incarico in un metodo e chiamando da OnDraw/onMeasure è solo di essere stupido e si fermerà Eclipse avvertendomi ma abituato effettivamente aiutare)

risposta

5

La ragione per l'avvertimento è perché, molto spesso, non è necessario ricreare un oggetto più volte in un'operazione di disegno. onDraw() potrebbe essere chiamato centinaia di volte rispetto ad altri metodi in un View. Nella maggior parte dei casi, gli oggetti ricreati vengono ricreati con i parametri esatti. Altre volte, è semplicemente meno sovraccarico modificare lo stato di un oggetto piuttosto che creare un nuovo oggetto.

Nel caso di uno StaticLayout, è necessario crearne uno nuovo quando il testo cambia o quando si regola il riempimento, la spaziatura o la larghezza massima. Se il testo cambia spesso, si consiglia di prendere in considerazione DynamicLayout che si rimisurerà ogni volta. I costi di rimisurazione sono più onerosi rispetto alla creazione di un nuovo oggetto, ma non è possibile che si verifichi più spesso delle chiamate onDraw().

Se il testo non cambia spesso e DEVI assolutamente utilizzare uno StaticLayout, puoi farcela con qualcosa come questa struttura.

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); 
} 

Fondamentalmente, si crea un nuovo layout solo quando qualcosa cambia. Altrimenti riutilizzi solo l'ultimo oggetto che hai creato.

EDIT:

Un modo per saltare un passaggio di misurazione è chiamare View#measure sulla visualizzazione appena ridimensionata stessa. Quindi il tuo metodo createLayout() sarebbe qualcosa del genere.

private void createLayout() { 
     myLayout = new StaticLayout(textSource, textPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 0, 1, false); 
     int textWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth, MeasureSpec.AT_MOST); 
     int textHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.AT_MOST); 
     myLayout.measure(textWidthSpec, textHeightSpec); 
     forceLayout(); 
    } 

Fondamentalmente ciò che fa è indicare al layout il massimo che la vista può essere. Si misurerà da solo ed è bambini. ForceLayout() sarà invocato sul genitore (la tua vista personalizzata) che ridisegnerà gli altri contenuti in base alle nuove misurazioni.

Devo notare che non l'ho mai fatto con uno StaticLayout, quindi non ho idea di cosa succederà. Sembra che questo tipo di misurazione possa essere già gestito quando viene creata la vista, ma forse no.

Spero che questo aiuti.

+0

Grazie, questo mi ha dato un modo leggermente nuovo di guardare le cose. L'unico problema che sto avendo implementando quanto sopra è che il 'textPaint' si basa su' onMeasure() 'già chiamato (il testo è ridimensionato in base alle dimensioni del canvas) e lo stesso vale per' textWidth' (che determina quando il testo verrà avvolto), quindi non posso creare 'createLayout()' nel costruttore per la prima visualizzazione. Posso metterlo in 'onMeasure()' che immagino non venga chiamato così spesso però? – Anthony

+0

Il testo effettivamente cambia molto, la vista su cui sto lavorando è in realtà una SeekBar circolare che ho creato e lo StaticLayout è usato per il testo nel mezzo che si riferisce all'avanzamento della SeekBar. Come tale quando trascini il dito attorno al cerchio il valore cambia costantemente. Ho pensato che anche se il valore cambia molto, la lunghezza è sempre riempita a tre cifre, quindi il layout non avrebbe mai bisogno di adattarsi alle dimensioni e quindi StaticLayout sarebbe ok. Posso trovare così poca documentazione su layout statico/dinamico, quindi non sono sicuro se questo è corretto. Qualsiasi aiuto nuovamente apprezzato. – Anthony

+0

Quindi alla fine (penso), ho finito per sostituire 'onMeasure()' con 'onSizeChanged()' dato che le mie esigenze di layout sono semplici e inserendo la chiamata iniziale a 'createLayout()' invece di 'onMeasure()'. Lint sembra non occuparsi dell'allocazione degli oggetti in 'onSizeChanged()' per qualche motivo, ma non li usa in 'onMeasure()'. Immagino che entrambi questi metodi siano chiamati la stessa quantità di volte, quindi non ho idea del perché va bene in uno e non nell'altro, ma a parte ciò, sembra a posto. La mia preoccupazione principale era ottenere l'allocazione da 'onDraw()' che ho fatto. Grazie ancora. – Anthony

Problemi correlati