web-dev-qa-db-fra.com

Comment dimensionner une vue Android en fonction des dimensions de son parent)

Comment dimensionner une vue en fonction de la taille de sa disposition parente. Par exemple, j'ai un RelativeLayout qui remplit tout l'écran et je veux une vue enfant, disons un ImageView, pour occuper toute la hauteur et la moitié de la largeur?

J'ai essayé de tout annuler sur onMeasure, onLayout, onSizeChanged, etc., et je ne pouvais pas le faire fonctionner ....

99
Mitch

Je ne sais pas si quelqu'un lit encore ce fil ou non, mais la solution de Jeff ne vous mènera qu'à la moitié (littéralement). Ce que son onMeasure va faire, c'est afficher la moitié de l'image dans la moitié du parent. Le problème est que l'appel de super.onMeasure avant le setMeasuredDimension mesurera tous les enfants de la vue en fonction de la taille d'origine, puis coupera la vue en deux lorsque le setMeasuredDimension le redimensionnera.

Au lieu de cela, vous devez appeler setMeasuredDimension (comme requis pour une substitution onMeasure) et fournissez un nouveau LayoutParams pour votre vue, alors appelez super.onMeasure. Rappelez-vous que vos LayoutParams sont dérivés du type de parent de votre vue, et non du type de votre vue.

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

Je crois que la seule fois où vous aurez des problèmes avec le parent LayoutParams, c’est si le parent est un AbsoluteLayout (ce qui est obsolète mais reste parfois utile).

122
Vic

Vous pouvez résoudre ce problème en créant une vue personnalisée et en remplaçant la méthode onMeasure (). Si vous utilisez toujours "fill_parent" pour layout_width dans votre fichier xml, le paramètre widthMeasureSpec transmis à la méthode onMeasusre () doit contenir la largeur du parent.

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

Votre XML ressemblerait à quelque chose comme ça:

<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>
39
Jeff

J'ai trouvé qu'il est préférable de ne pas perdre son temps à régler vous-même les dimensions mesurées. En fait, il y a un peu de négociation entre les vues parent et enfant et vous ne voulez pas réécrire tout cela code .

Ce que vous pouvez faire, cependant, est de modifier les mesures, puis d'appeler super avec elles. Votre vue ne saura jamais qu'elle reçoit un message modifié de son parent et s'occupera de tout pour vous:

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

Lorsque vous définissez une présentation et une vue sur XML, vous pouvez spécifier la largeur et la hauteur de la présentation d’une vue soit en tant que contenu renvoyé, soit en remplissant le parent. Prendre la moitié de la surface est un peu plus difficile, mais si vous aviez quelque chose que vous vouliez sur l'autre moitié, vous pourriez faire quelque chose comme ce qui suit.

   <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>

Donner le même poids à deux choses signifie qu'elles vont s'étirer pour occuper la même proportion de l'écran. Pour plus d'informations sur les dispositions, voir les documents de développement.

15
Cheryl Simon

Je crois que approche XML de Mayras peut être soigné. Cependant, il est possible de le rendre plus précis, avec une seule vue en réglant le weightSum. Je n'appellerais plus cela un piratage mais, à mon avis, l'approche la plus simple:

<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>

Comme cela, vous pouvez utiliser n’importe quel poids, 0.6 par exemple (et le centrage) est le poids que j’aime utiliser pour les boutons.

9
pinkwerther

Essaye ça

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

alors vous pouvez utiliser LinearLayout.LayoutParams pour définir les paramètres de chileView

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

Vous pouvez maintenant utiliser PercentRelativeLayout. Boom! Problème résolu.

2
androidguy

Si l'autre côté est vide. Le moyen le plus simple consiste à ajouter une vue vide (une disposition linéaire, par exemple), puis à définir les largeurs des deux vues sur fill_parent et leur poids à 1.

Cela fonctionne dans un LinearLayout ...

1
jpm

Roman, si vous voulez faire votre mise en page dans Java (descendant de ViewGroup)), c’est possible. Le truc, c’est que vous devez implémenter les méthodes onMeasure et onLayout. Le onMeasure est appelé en premier et vous devez "mesurer" la sous-vue (en la dimensionnant effectivement à la valeur souhaitée). Vous devez redimensionner à nouveau dans l'appel onLayout. Si vous ne parvenez pas à effectuer cette séquence ou à appeler setMeasuredDimension () à la fin de votre onMeasure code, vous n'obtiendrez aucun résultat. Pourquoi cela est-il conçu de manière si compliquée et si fragile me dépasse-t-il?.

1
Pavel Lahoda

C'est quelque chose comme ça:

<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>
0
Mario