2010-01-29 4 views
95

Comment puis-je dimensionner une vue en fonction de la taille de sa mise en page parent. Par exemple j'ai un RelativeLayout qui remplit le plein écran, et je veux une vue d'enfant, disons un ImageView, pour prendre toute la taille, et 1/2 la largeur?Comment dimensionner une vue Android en fonction des dimensions de son parent

J'ai essayé sur tous les remplaçant onMeasure, onLayout, onSizeChanged, etc et je ne pouvais pas le faire fonctionner ....

+0

Il est possible de le faire en utilisant ConstraintLayout, vérifiez ceci: https://stackoverflow.com/questions/37318228/how-to-make-constraintlayout-work-with-percentage-values ​​ –

Répondre

15

Lorsque vous définissez une mise en page et vue sur XML, vous pouvez spécifier la mise en page La largeur et la hauteur d'une vue peuvent être soit du contenu en retour, soit remplir un parent. Prendre la moitié de la zone 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. Donner deux choses du même poids signifie qu'elles vont s'étirer pour occuper la même proportion de l'écran. Pour plus d'informations sur les dispositions, voir the dev docs.

+0

Je ne le recommande pas, mais ... comme un hack, si vous utilisez l'approche ci-dessus, vous pourriez faire une de ces vues un "dummy" et mettre android: visibility = "invisible" pour remplir la moitié de la zone – RickNotFred

+0

Quel est le but de n'utiliser que la moitié région? Avez-vous l'intention d'afficher quoi que ce soit dans l'autre moitié? Qu'est-ce que vous faites avec la zone restante informera la meilleure approche – RickNotFred

+0

cela devrait certainement être # 1 - si vous pouvez le faire dans votre xml, pourquoi le faire dans votre java? – fandang

1

Roman, si vous voulez faire votre mise en page en code Java (ViewGroup descendant), c'est possible. L'astuce est que vous devez implémenter les méthodes onMeasure et onLayout. OnMeasure est appelé en premier et vous devez "mesurer" la sous-vue (en l'ajustant à la valeur désirée). Vous devez le redimensionner dans l'appel onLayout. Si vous ne parvenez pas à exécuter cette séquence ou si vous ne parvenez pas à appeler setMeasuredDimension() à la fin de votre code onMeasure, vous n'obtiendrez pas de résultats. Pourquoi est-ce conçu de manière si compliquée et fragile est au-delà de moi.

35

Vous pouvez résoudre ce problème en créant une vue personnalisée et remplacer 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 ceci:

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

@jeff => pourquoi parentWidth/2 ?? –

+5

@Leon_SFS: La question demande pour cela: "toute la hauteur, et 1/2 la largeur" ​​ – EdgarT

120

Je ne sais pas si quelqu'un est en train de lire encore ce fil ou non, mais la solution de Jeff ne vous obtenir à mi-chemin (un peu littéralement) . Ce que son onMeasure fera est d'afficher la moitié de l'image dans la moitié du parent. Le problème est qu'appeler super.onMeasure avant le setMeasuredDimension mesurera tous les enfants dans la vue en fonction de la taille d'origine, puis coupez simplement la vue en deux lorsque le setMeasuredDimension la redimensionne.

, vous avez besoin au lieu d'appeler setMeasuredDimension (comme requis pour un remplacement de onMeasure) et fournissent une nouvelle LayoutParams pour votre vue, puis appel super.onMeasure. Souvenez-vous que vos LayoutParams sont dérivés du type 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 que vous aurez des problèmes avec le parent LayoutParams est si le parent est un AbsoluteLayout (qui est dépréciée, mais encore parfois utile).

+10

Dans mon expérience, cela fonctionne rarement, esp. lorsque fill/match_parent ou des poids sont invoqués. Mieux vaut appeler measureChildren après setMeasuredDimension (avec par exemple MeasureSpec.makeMeasureSpec (newWidth, MeasureSpec.AT_MOST)). –

+0

J'ai besoin de changer la marge gauche d'un TextView au lieu de sa taille en fonction de la largeur de la mise en page parent. En utilisant votre code cela fonctionne plus ou moins, mais cela me donne des résultats étranges en l'utilisant dans les lignes d'un ListView, je. e. ce n'est pas toujours dans la bonne position après le défilement. Dois-je remplacer une autre méthode? Comment dois-je appeler setMeasuredDimension dans ce cas? – Konsumierer

+1

Est-ce que 'MeasureSpec.getSize (widthMeasureSpec)' donne vraiment la largeur du parent correct? Pour moi, il retourne juste des largeurs aléatoires qui sont assez proches de la largeur réelle, mais pas exactes. – Konsumierer

1

Si l'autre côté est vide. Je suppose que le moyen le plus simple serait d'ajouter une vue vide (par exemple une disposition linéaire) puis définir les largeurs des deux vues à fill_parent et leurs deux poids à 1.

Cela fonctionne dans un LinearLayout ...

24

J'ai trouvé qu'il est préférable de ne pas déranger avec le réglage des dimensions mesurées vous-même. Il y a en fait un peu de négociation qui se passe 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 measureSpecs, puis d'appeler super avec eux. Votre vue ne saura jamais qu'il devient un message modifié depuis son parent et se chargera 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); 
} 
9

Je crois que Mayras XML-approach peut venir propre. Cependant, il est possible de le rendre plus précis, avec une seule vue en définissant le weightSum. Je ne dirais pas cela un hack plus, 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 tout le poids, par exemple 0,6 (et le centrage) est le poids que je préfère utiliser pour les boutons.

0

Il est quelque chose comme ceci:

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

Essayez cette

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

vous pouvez utiliser LinearLayout.LayoutParams pour régler les paramètres de chileView

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

J'ai une autre solution. Nous pouvons obtenir la largeur et la hauteur du parent, alors il vous suffit de l'utiliser pour calculer la taille et l'assigner aux paramètres de mise en page.
Comme ceci:

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); // Don't for get this 
    int parentWidth = ((View) getParent()).getMeasuredWidth(); 
    int parentHeight = ((View) getParent()).getMeasuredHeight(); 
    if (parentWidth*parentHeight != 0) { // Check if both width and height in non-zero 
     LayoutParams lp = getLayoutParams(); 
     lp.width = parentWidth/2; 
     lp.height = parentHeight; 
    } 
} 
2

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

+1

PercentRelativeLayout a été déprécié au niveau de l'API 26.0.0-beta1. – dzikovskyy

+0

Que voulez-vous dire "Au niveau de l'API"? Voulez-vous dire le numéro de version de la bibliothèque? PRL est dans la bibliothèque de support, n'a aucun niveau d'API. – user3175580

+0

Par niveau d'API, je veux dire la version d'Android. Info d'ici https://developer.android.com/reference/android/support/percent/PercentRelativeLayout.html. Plus d'informations sur le niveau de l'API ici https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels – dzikovskyy

Questions connexes