Come ridimensionare una vista Android in base alle dimensioni del suo genitore


104

Come posso ridimensionare una vista in base alle dimensioni del layout principale. Ad esempio, ho un RelativeLayoutche riempie lo schermo intero e voglio una vista bambino, diciamo un ImageView, per occupare l'intera altezza e metà della larghezza?

Ho provato l'override tutti su onMeasure, onLayout, onSizeChanged, ecc e non ho potuto farlo funzionare ....


È possibile farlo utilizzando ConstraintLayout, controlla questo: stackoverflow.com/questions/37318228/…
Ali Nem

Risposte:


124

Non so se qualcuno stia ancora leggendo questo thread o no, ma la soluzione di Jeff ti porterà solo a metà strada (letteralmente). Quello che farà il suo onMeasure è visualizzare metà dell'immagine nella metà del genitore. Il problema è che chiamando super.onMeasure prima di setMeasuredDimensionmisurerà tutti i bambini nella vista in base alla dimensione originale, quindi taglia la vista a metà quando la setMeasuredDimensionridimensiona.

Invece, è necessario chiamare setMeasuredDimension(come richiesto per un override onMeasure) e fornire un nuovo LayoutParamsper la visualizzazione, quindi chiamare super.onMeasure. Ricorda, LayoutParamssei derivato dal tipo principale della tua vista, non dal tipo della tua vista.

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

Credo che l'unica volta che avrai problemi con il genitore LayoutParamsè se il genitore è un AbsoluteLayout(che è deprecato ma a volte ancora utile).


12
Nella mia esperienza, questo funziona raramente, specialmente. quando vengono richiamati fill / match_parent o weights. È meglio richiamare measureChildren dopo setMeasuredDimension (con ad esempio MeasureSpec.makeMeasureSpec (newWidth, MeasureSpec.AT_MOST)).
M. Schenk

1
Fa MeasureSpec.getSize(widthMeasureSpec)davvero dare la larghezza delle parent's corrette? Per me restituisce solo larghezze casuali che sono abbastanza vicine alla larghezza effettiva, ma non esatte.
Konsumierer

1
@ M.Schenk ce l'ha. Ho un VideoView all'interno di un layout ponderato. Ho bisogno che la larghezza sia una percentuale della dimensione dello schermo e ho bisogno di mantenere le proporzioni. Questo allunga il video, quindi wrap_contentnon lo farà. La risposta di Vic non funziona per questo scenario, ma il commento di @ M.Schenk sì. Salva anche un passaggio di layout aggiuntivo. Dovresti anche pubblicarlo come risposta per visibilità.
dokkaebi

7
La chiamata non si super.onMeasure()limiterà a sovrascrivere e annullare gli effetti della chiamata precedente a this.setMeasuredDimension()?
Spinner

1
Sono anche curioso, come menzionato da @Spinner, perché la chiamata a super.onMeasure()non sovrascrive i calcoli precedenti.
jwir3

39

È possibile risolvere questo problema creando una visualizzazione personalizzata e sovrascrivendo il metodo onMeasure (). Se usi sempre "fill_parent" per layout_width nel tuo xml, il parametro widthMeasureSpec passato al metodo onMeasusre () dovrebbe contenere la larghezza del genitore.

public class MyCustomView extends TextView {

    public MyCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
        this.setMeasuredDimension(parentWidth / 2, parentHeight);
    }
}   

Il tuo XML sarebbe simile a questo:

<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <view
        class="com.company.MyCustomView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

2
@jeff => perché parentWidth / 2 ??
Saeed-rz

6
@Leon_SFS: La domanda chiede: "tutta l'altezza e metà della larghezza"
EdgarT

28

Ho scoperto che è meglio non scherzare con l'impostazione delle dimensioni misurate da soli. In realtà c'è un po 'di negoziazione tra le viste padre e figlia e non vuoi riscrivere tutto quel codice .

Quello che puoi fare, però, è modificare le measureSpecs, quindi chiamare super con esse. La tua vista non saprà mai che sta ricevendo un messaggio modificato dal suo genitore e si prenderà cura di tutto per te:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
    int myWidth = (int) (parentHeight * 0.5);
    super.onMeasure(MeasureSpec.makeMeasureSpec(myWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
}

16

Quando si definisce un layout e una vista su XML, è possibile specificare la larghezza e l'altezza del layout di una vista come contenuto a capo o riempimento padre. Occupare metà dell'area è un po 'più difficile, ma se avessi qualcosa che volevi sull'altra metà potresti fare qualcosa di simile.

   <LinearLayout android:layout_width="fill_parent"
                android:layout_height="fill_parent">
        <ImageView android:layout_height="fill_parent"
                 android:layout_width="0dp"
                 android:layout_weight="1"/>
        <ImageView android:layout_height="fill_parent"
                 android:layout_width="0dp"
                 android:layout_weight="1"/>
   </LinearLayout>

Dare a due cose lo stesso peso significa che si allungheranno per occupare la stessa proporzione dello schermo. Per ulteriori informazioni sui layout, vedere la documentazione degli sviluppatori.


Non lo consiglio, ma ... come hack, se usi l'approccio sopra puoi rendere una di quelle viste un "fittizio" e impostare android: visibile = "invisibile" per riempire metà dell'area
RickNotFred

Qual è lo scopo di utilizzare solo metà dell'area? Hai intenzione di mostrare qualcosa nell'altra metà? Quello che farai con l'area rimanente determinerà l'approccio migliore
RickNotFred

questo dovrebbe essere sicuramente il numero 1 - se puoi farlo nel tuo xml, perché farlo nel tuo java?
fandang

9

Credo che l' approccio XML di Mayras possa venire in ordine. Tuttavia è possibile renderlo più preciso, con una sola visualizzazione impostando weightSum. Non lo definirei più un hack, ma a mio avviso l'approccio più semplice:

<LinearLayout android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:weightSum="1">
    <ImageView android:layout_height="fill_parent"
               android:layout_width="0dp"
               android:layout_weight="0.5"/>
</LinearLayout>

In questo modo puoi usare qualsiasi peso, ad esempio 0.6 (e centratura) è il peso che mi piace usare per i pulsanti.


3

Prova questo

int parentWidth = ((parentViewType)childView.getParent()).getWidth();
int parentHeight = ((parentViewType)childView.getParent()).getHeight();

quindi puoi usare LinearLayout.LayoutParams per impostare i parametri di chileView

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(childWidth,childLength);
childView.setLayoutParams(params);

2

È ora possibile utilizzare PercentRelativeLayout. Boom! Problema risolto.


2
PercentRelativeLayout è stato deprecato nel livello API 26.0.0-beta1.
dzikovskyy

Cosa intendi con "A livello API"? Intendi il numero di versione della libreria? PRL è nella libreria di supporto, non ha un livello API.
androidguy

Per livello API intendo la versione di Android. Informazioni da qui developer.android.com/reference/android/support/percent/… . Maggiori informazioni sul livello API qui developer.android.com/guide/topics/manifest/…
dzikovskyy

È ancora possibile utilizzare questa classe a meno che per qualche motivo non sia necessaria la versione 26.0.0 o successiva.
androidguy

1

Roman, se vuoi fare il tuo layout in codice Java (discendente ViewGroup), è possibile. Il trucco è che devi implementare entrambi i metodi onMeasure e onLayout. OnMeasure viene chiamato per primo e devi "misurare" la sottoview (ridimensionandola efficacemente al valore desiderato) lì. È necessario ridimensionarlo di nuovo nella chiamata onLayout. Se non riesci a eseguire questa sequenza o non riesci a chiamare setMeasuredDimension () alla fine del codice onMeasure, non otterrai risultati. Perché questo è progettato in modo così complicato e fragile è al di là di me.


1

Se l'altro lato è vuoto. Immagino che il modo più semplice sarebbe aggiungere una vista vuota (ad esempio un layout lineare) quindi impostare le larghezze di entrambe le viste su fill_parent ed entrambi i loro pesi su 1.

Funziona in un LinearLayout ...


0

È qualcosa del genere:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.company.myapp.ActivityOrFragment"
    android:id="@+id/activity_or_fragment">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/linearLayoutFirst"
    android:weightSum="100">   <!-- Overall weights sum of children elements -->

    <Spinner
        android:layout_width="0dp"   <!-- It's 0dp because is determined by android:layout_weight -->
        android:layout_weight="50"
        android:layout_height="wrap_content"
        android:id="@+id/spinner" />

</LinearLayout>


<LinearLayout
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:layout_below="@+id/linearLayoutFirst"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:id="@+id/linearLayoutSecond">

    <EditText
        android:layout_height="wrap_content"
        android:layout_width="0dp"
        android:layout_weight="75"
        android:inputType="numberDecimal"
        android:id="@+id/input" />

    <TextView
        android:layout_height="wrap_content"
        android:layout_width="0dp"
        android:layout_weight="25"
        android:id="@+id/result"/>

</LinearLayout>
</RelativeLayout>

-1

Ho lottato con questa domanda per molto tempo, voglio cambiare la larghezza del cassetto del mio DrawerLayout, che è il secondo figlio del suo genitore. Di recente l'ho capito, ma non so se c'è un'idea migliore.

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
    super.onLayout(changed, l, t, r, b)
    (getChildAt(1).layoutParams as LayoutParams).width = measuredWidth/2
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.