web-dev-qa-db-fra.com

Limiter la hauteur de ListView sur Android

Je veux montrer un bouton sous une ListView. Le problème, c'est que si la ListView est étendue (éléments ajoutés ...), le bouton est poussé hors de l'écran. 

J'ai essayé une LinearLayout avec des poids (comme suggéré dans Android: pourquoi n'y a-t-il pas de maxHeight pour une vue? ), mais je me suis trompé ou j'ai tout simplement échoué. 

En outre, j'ai trouvé quelque part la suggestion d'utiliser un RelativeLayout. La ListView serait alors définie au-dessus du bouton avec le paramètre Android:layout_above

Le problème avec ceci est que je ne sais pas comment positionner le bouton après. Dans l'exemple que j'ai trouvé, la vue située sous la ListView a été ajustée à l'aide de Android:layout_alignParentBottom, mais je ne veux pas que mon bouton s'accroche au bas de l'écran. 

Des idées en dehors de l'utilisation de la méthode setHeight et du calcul de l'espace requis?


Edit: J'ai eu beaucoup de réponses utiles.

  • la solution de bigstone & user639183 presque fonctionnait parfaitement. Cependant, je devais ajouter une marge supplémentaire au bas du bouton, car il serait toujours poussé à mi-chemin hors de l'écran (puis arrêté

  • La réponse d'Adinia avec la disposition relative est satisfaisante si vous voulez que le bouton soit fixé au bas de l'écran. Ce n'est pas ce que je voulais, mais ça pourrait quand même être utile pour les autres.

  • La solution AngeloS est celle que j'ai choisie à la fin, car elle vient de créer les effets que je voulais. Cependant, j'ai apporté deux modifications mineures à la LinearLayout autour du bouton: 

    • Premièrement, comme je ne voulais pas avoir de valeurs absolues dans ma mise en page, j'ai changé Android:layout_height="45px" en wrap_content, ce qui fonctionne aussi très bien. 

    • Deuxièmement, comme je voulais que le bouton soit centré horizontalement, ce qui n’est supporté que par LinearLayout vertical, j’ai changé Android: orientation = "horizontal" en "vertical". 

    AngeloS a également déclaré dans son message initial qu'il n'était pas sûr si le Android:layout_weight="0.1" param de la LinearLayout autour de la ListView avait un effet quelconque; Je viens d'essayer et c'est le cas! Sans cela, le bouton est à nouveau poussé hors de l'écran.

86
jellyfish

J'ai eu ce problème exact et pour le résoudre, j'ai créé deux variables LinearLayouts distinctes pour abriter respectivement les variables ListView et Button. À partir de là, je mets les deux dans un autre Linear Layout et je règle le Android:orientation de ce conteneur sur vertical. J'ai également réglé le poids de la LinearLayout qui abritait la ListView sur 0.1 mais je ne sais pas si cela a un effet. À partir de là, vous pouvez définir la hauteur du conteneur du bas (contenant le bouton) à la hauteur souhaitée.

EDITc'est ce que je veux dire:

<LinearLayout
  xmlns:Android="http://schemas.Android.com/apk/res/Android"
  Android:layout_width="fill_parent"
  Android:layout_height="fill_parent"
  Android:orientation="vertical">

  <LinearLayout
        Android:orientation="horizontal"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:layout_weight="0.1"
        >   



                  <ListView Android:id="@+id/ListView01" 
                    Android:layout_height="fill_parent"
                    Android:layout_width="fill_parent"
                    Android:dividerHeight="2px">
                 </ListView>



    </LinearLayout> 

<LinearLayout
    Android:orientation="horizontal"
    Android:layout_width="fill_parent"
    Android:layout_height="45px"
    Android:background="@drawable/drawable" 
    > 


                <Button Android:background="@drawable/btn_more2"                     
                     Android:id="@+id/moreButton"
                     Android:layout_width="wrap_content"
                     Android:layout_height="fill_parent"
                     Android:layout_alignParentRight="true"
                     Android:paddingRight="20px"
                     />

</LinearLayout>
</LinearLayout>

La solution ci-dessus corrigera le bouton au bas de l'écran.


Pour que le bouton flotte en bas de la liste, modifiez la hauteur de ListView01 en wrap_content:

<LinearLayout
  xmlns:Android="http://schemas.Android.com/apk/res/Android"
  Android:layout_width="fill_parent"
  Android:layout_height="wrap_content"
  Android:orientation="vertical">

  <LinearLayout
        Android:orientation="horizontal"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:layout_weight="0.1"
        >   

        <ListView Android:id="@+id/ListView01" 
                    Android:layout_height="wrap_content"
                    Android:layout_width="fill_parent"
                    Android:dividerHeight="2px">
                 </ListView>



    </LinearLayout> 

<LinearLayout
    Android:orientation="horizontal"
    Android:layout_width="fill_parent"
    Android:layout_height="45px"
    Android:background="@drawable/drawable" 
    > 


                <Button Android:background="@drawable/btn_more2"                     
                     Android:id="@+id/moreButton"
                     Android:layout_width="wrap_content"
                     Android:layout_height="fill_parent"
                     Android:layout_alignParentRight="true"
                     Android:paddingRight="20px"
                     />

</LinearLayout>
</LinearLayout>
51
AngeloS

J'ai résolu ce problème dans le code, en définissant height de listview uniquement s'il contient plus de 5 éléments:

if(adapter.getCount() > 5){
        View item = adapter.getView(0, null, listView);
        item.measure(0, 0);         
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, (int) (5.5 * item.getMeasuredHeight()));
        listView.setLayoutParams(params);
}

Remarquez que je règle la hauteur maximale à 5,5 fois la hauteur d'un seul élément, afin que l'utilisateur sache qu'il doit faire défiler! :)

61
shaylh

Lors de votre dernière modification, il vous suffit d'ajouter également Android:layout_above="@+id/butt1" dans votre code ListView. 

Et pour vous montrer (et à tous ceux qui ont essayé une réponse plus tôt) que vous n'avez vraiment pas besoin d'utiliser plus d'un RelativeLayout, voici votre code corrigé :

   <RelativeLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="fill_parent"
    Android:layout_height="fill_parent"
    Android:background="@drawable/bkg">
    <TextView
        Android:id="@+id/textView1"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:text="TextView1"
        Android:layout_alignParentTop="true">
    </TextView>
    <TextView
        Android:id="@+id/textView2"
        Android:layout_below="@+id/textView1"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:text="TextView2"
        Android:layout_centerHorizontal="true">
    </TextView>
    <Button
        Android:id="@+id/butt1"
        Android:text="string/string3"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_centerHorizontal="true"
        Android:layout_alignParentBottom="true">
    </Button>
    <ListView
        Android:id="@+id/Android:list"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:layout_marginTop="2dip"
        Android:layout_marginBottom="2dip"
        Android:drawSelectorOnTop="false"
        Android:visibility="visible"
        Android:layout_below="@+id/textView2"
        Android:layout_above="@+id/butt1" />
    </RelativeLayout>

et le résultat , en utilisant une liste aléatoire:
enter image description here

21
Adinia

En utilisant LinearLayout, définissez la hauteur de votre ListView et Button sur wrap_content et ajoutez un poids = 1 à ListView. Cela devrait fonctionner comme vous voulez.
Et oui, définissez le layout_gravity de la Button sur bottom

6
ernazm

RelativeLayout est une solution. Si vous ne souhaitez pas que le bouton reste trop près du bas, vous pouvez ajouter des marges (le remplissage d'un bouton le casserait car il utilise un arrière-plan de 9 correctifs et définit son propre remplissage).

Ce serait la même chose si vous utilisiez une LinearLayout: la manière d’atteindre ce que vous voulez est de définir la ListView sur une hauteur = 0 et un poids = 1, et pour le bouton height = wrap_content et weight = 0. (définir les deux comme étant wrap_content, comme dit user639183, ne limiterait pas la hauteur de ListView).

5
bigstones

Nous avons trouvé un moyen de le faire sans utiliser de conteneurs imbriqués, inspirés de la solution AngeloS. 

J'ai utilisé un LinearLayout avec une orientation verticale, qui a un ListView et un bouton. Je règle le Android:layout_weight="0.1" pour la ListView

Il parvient toujours à placer le bouton au bas de la liste. Et le bouton ne sera pas poussé hors de l'écran lorsque la liste s'allongera.

<ListView
    Android:id="@+id/notes_list"
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
    Android:layout_weight="0.1"        
    />

<Button
    Android:id="@+id/create_note_btn"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"        
    Android:onClick="onCreateButtonClicked"
    Android:text="@string/create_notes"
    />
5
Sparkle

C'est la manière la plus propre de le faire:

<LinearLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
    Android:orientation="vertical">
  <ListView
      Android:id="@+id/ListView01"
      Android:layout_width="fill_parent"
      Android:layout_height="0dp"
      Android:layout_weight="1"
      Android:dividerHeight="2px">
  </ListView>
  <FrameLayout
      Android:layout_width="fill_parent"
      Android:layout_height="wrap_content"
      Android:background="@drawable/drawable"
      >
    <Button Android:background="@drawable/btn_more2"
        Android:id="@+id/moreButton"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_alignParentRight="true"
        Android:paddingRight="20px"
        />    
  </LinearLayout>
</LinearLayout>

C'est similaire à la solution d'Angelos mais vous n'avez pas besoin de la linéarité qui enveloppe le ListView. Vous pouvez également utiliser un FrameLayout plus léger que le LinearLayout pour boucler le bouton.

2
user2994360

Vous pouvez probablement faire ce travail en utilisant des conteneurs imbriqués. Il est possible que vous deviez envelopper le bouton dans un deuxième conteneur (interne) pour qu'il prenne plus de place et aligner simplement le bouton sur le dessus du conteneur interne.

Possible quelque chose comme ça:

Disposition relative

- ListView

-- Disposition relative

---- Bouton

En utilisant les différentes options d'alignement sur les deux conteneurs, vous devriez pouvoir le faire fonctionner.

2
Rich

L'idée est décrite dans les très bonnes solutions par:

Ils semblent tous deux parfaitement fonctionner au moins sur la v4.4.3.

Il me restait encore du temps à écrire le code de test pour le vérifier et confirmer chaque méthode. Vous trouverez ci-dessous le code de test minimal et autonome requis.


La disposition est basée sur la solution de Sparkle, car elle contient moins de dispositions imbriquées. Également mis à jour pour refléter les vérifications LINT actuelles.

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
    Android:orientation="vertical"
    tools:context="MainActivity" >

    <ListView
        Android:id="@+id/listview"
        Android:layout_width="fill_parent"
        Android:layout_height="0dp"
        Android:layout_weight="1" />

    <Button
        Android:id="@+id/btn"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:text="Grow List"
        tools:ignore="HardcodedText" />

</LinearLayout>

Activity fournit le code passe-partout pour tester la solution pour vous-même. 

public class MainActivity extends Activity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ListView listview = (ListView)findViewById(R.id.listview);
        final ArrayAdapter<String> adapter = 
                new ArrayAdapter<String>(this,
                                         Android.R.layout.simple_list_item_1,
                                         new ArrayList<String>());
        adapter.setNotifyOnChange(true);
        listview.setAdapter(adapter);

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                int count = adapter.getCount();
                adapter.add(String.valueOf(count));
                listview.setSelection(count);
            }
        });
    }
}

N'hésitez pas à ajouter ou à améliorer car il s'agit d'un "wiki de communauté".

2

Essayez d'utiliser RelativeLayout avec un bouton en bas. Définissez la hauteur de la présentation sur "wrap_content" . Je ne l’ai pas essayé. Juste une idée

1
Maxim

dans LinearLayout, ajoutez simplement Android:layout_weight="1" à ListView

1
DawnYu

Voici ce qui a fonctionné pour moi ...

 if(adapter.getCount() > 3){
                    View item = adapter.getView(0, null, impDateListView);
                    item.measure(0, 0);         
                    LayoutParams params = impDateListView.getLayoutParams();
                    params.width = LayoutParams.MATCH_PARENT;
                    params.height = 3 * item.getMeasuredHeight();
                    impDateListView.setLayoutParams(params);


                }

Remarque: Le paramètre params.width = ... doit également être défini ...

L'exemple ci-dessus concerne l'utilisation de TableRow et ListView dans TableRow ...

envelopper le contenu dans une mise en page linéaire

en mode liste, ajoutez: Android: layout_weight = "1"

dans votre jeu de boutons hauteur fixe

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
              Android:layout_width="match_parent"
              Android:layout_height="wrap_content"
              Android:orientation="vertical">

<ListView
    Android:id="@+id/my_list"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:layout_weight="1">
</ListView>

 <Button
    Android:text="Button"
    Android:layout_width="match_parent"
    Android:layout_height="50dp"/>

</LinearLayout>
0
Toma

Si vous souhaitez que le contenu situé sous la vue de liste descende au fur et à mesure que des éléments sont ajoutés à la liste, essayez cette solution:

Ajoutez un remplissage positif au bas de la vue et un remplissage négatif au haut du "pied de page". Cela fonctionnera dans une mise en page linéaire ou une mise en page relative.

<ListView
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:paddingBottom="50dp"/>

<TextView
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:layout_marginTop="-50dp"/>
0
Jenny Pushkarskaya