it-swarm.it

Modo autorevole per ignorare onMeasure ()?

Qual è il modo corretto di ignorare onMeasure ()? Ho visto vari approcci. Ad esempio, Sviluppo Android professionale utilizza MeasureSpec per calcolare le dimensioni, quindi termina con una chiamata a setMeasuredDimension (). Per esempio:

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
}

D'altra parte, come per questo post , il modo "corretto" è usare MeasureSpec, chiamare setMeasuredDimensions (), seguito da una chiamata a setLayoutParams () e terminare con una chiamata a super. onMeasure (). Per esempio:

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

Quindi qual è la strada giusta? Nessuno dei due approcci ha funzionato al 100% per me. 

Immagino davvero che cosa sto chiedendo è qualcuno sa di un tutorial che spiega onMeasure (), layout, dimensioni delle viste dei bambini, ecc? 

87
U Avalos

Le altre soluzioni non sono complete. Possono funzionare in alcuni casi e sono un buon punto di partenza, ma potrebbero non essere garantiti per funzionare. 

Quando viene chiamato onMeasure, potresti avere o meno il diritto di modificare le dimensioni. I valori passati a onMeasure (widthMeasureSpec, heightMeasureSpec) contengono informazioni su ciò che la visualizzazione figlio può fare. Attualmente ci sono tre valori:

  1. MeasureSpec.UNSPECIFIED - Puoi essere grande quanto vuoi
  2. MeasureSpec.AT_MOST - Grande quanto vuoi (fino alla dimensione della specifica), Questo è parentWidth nel tuo esempio.
  3. MeasureSpec.EXACTLY - Nessuna scelta. Il genitore ha scelto.

Questo è fatto in modo che Android possa fare più passaggi per trovare la taglia giusta per ogni oggetto, vedi qui per maggiori dettagli.

Se non segui queste regole, il tuo approccio non è garantito per funzionare.

Ad esempio, se si desidera verificare se è possibile modificare le dimensioni, è possibile fare quanto segue:

final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;

Usando queste informazioni saprai se puoi modificare i valori come nel tuo codice. O se ti viene richiesto di fare qualcosa di diverso. Un modo rapido e semplice per risolvere la dimensione desiderata è utilizzare uno dei seguenti metodi:

int resolveSizeAndState (int size, int measureSpec, int childMeasuredState)

int resolveSize (int size, int measureSpec)

Mentre il primo è disponibile solo su Honeycomb, il secondo è disponibile su tutte le versioni.

Nota: è possibile che resizeWidth o resizeHeight siano sempre false. Ho trovato questo caso, se stavo richiedendo MATCH_PARENT. Sono stato in grado di risolvere questo problema richiedendo WRAP_CONTENT sul mio layout principale e poi durante la fase di richiesta richiedendo una dimensione di Integer.MAX_VALUE. In questo modo si ottiene la dimensione massima consentita dal genitore al passaggio successivo su onMeasure.

66
Grimmace

La documentazione è l'autorità su questo argomento: http://developer.Android.com/guide/topics/ui/how-Android-draws.html and http://developer.Android.com/guide /topics/ui/custom-components.html

Per riassumere: alla fine del metodo onMeasure sottoposto a override devi chiamare setMeasuredDimension.

Non dovresti chiamare super.onMeasure dopo aver chiamato setMeasuredDimension, questo cancellerà semplicemente tutto ciò che hai impostato. In alcune situazioni potresti voler chiamare prima super.onMeasure e poi modificare i risultati chiamando setMeasuredDimension.

Non chiamare setLayoutParams in onMeasure. Il layout avviene in un secondo passaggio dopo la misurazione.

38
satur9nine

ecco come ho risolto il problema:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        ....

        setMeasuredDimension( measuredWidth, measuredHeight );

        widthMeasureSpec = MeasureSpec.makeMeasureSpec( measuredWidth, MeasureSpec.EXACTLY );
        heightMeasureSpec = MeasureSpec.makeMeasureSpec( measuredHeight, MeasureSpec.EXACTLY);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

Inoltre era necessario per il componente ViewPager

0
Yuli Reiri

Penso che dipenda dal genitore che cosa stai ignorando.

Ad esempio, se stai estendendo un ViewGroup (come FrameLayout), quando hai misurato la dimensione, dovresti chiamare come sotto

super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));

perché potresti volere ViewGroup per fare il lavoro di riposo (fai un po 'di cose sulla vista figlio)

Se stai estendendo una vista (come ImageView), puoi semplicemente chiamare this.setMeasuredDimension(width, height);, perché la classe genitore farà semplicemente qualcosa che hai fatto di solito.

In una parola, se si desidera che alcune funzionalità della classe genitore siano gratuite, è necessario chiamare super.onMeasure() (passare di solito MeasureSpec.EXACTLY measure spec), altrimenti chiamare this.setMeasuredDimension(width, height); è sufficiente.

0
Yon

Dipende dal controllo che si sta utilizzando. Le istruzioni nella documentazione funzionano per alcuni controlli (TextView, Button, ...), ma non per gli altri (LinearLayout, ...). Il modo in cui ha funzionato molto bene per me è stato chiamare il super una volta che ho finito. Basato sull'articolo nel link sottostante.

http://humptydevelopers.blogspot.in/2013/05/Android-view-overriding-onmeasure.html

0
Aviral

Se si modifica la dimensione della vista all'interno di onMeasure, tutto ciò che serve è la chiamata setMeasuredDimension. Se si modifica la dimensione al di fuori di onMeasure, è necessario chiamare setLayoutParams. Ad esempio, cambiando la dimensione di una vista testuale quando il testo è cambiato.

0
Kyle O.