Limite de altura de ListView no Android


92

Quero mostrar um botão sob a ListView. O problema é que, se o ListViewfor estendido (itens adicionados ...), o botão será empurrado para fora da tela.

Eu tentei um LinearLayoutcom pesos (como sugerido no Android: por que não há maxHeight para um View? ), Mas ou achei os pesos errados ou simplesmente não funcionou.

Além disso, encontrei em algum lugar a dica para usar a RelativeLayout. O ListViewseria então definido acima do botão com o android:layout_aboveparâmetro.

O problema com isso é que não sei como posicionar o botão depois. No exemplo que encontrei, a visualização abaixo do ListViewfoi ajustada usando android:layout_alignParentBottom, mas não quero que meu botão grude na parte inferior da tela.

Alguma ideia além de usar o método setHeight e alguns cálculos do espaço necessário?


Edit: recebi muitas respostas úteis.

  • A solução da bigstone's & user639183 quase funcionou perfeitamente. No entanto, eu tive que adicionar um preenchimento / margem extra na parte inferior do botão, já que ele ainda seria empurrado para fora da tela (mas depois parado)

  • A resposta de Adinia com o layout relativo só é adequada se você quiser que o botão seja fixado na parte inferior da tela. Não é o que eu pretendia, mas ainda pode ser útil para outras pessoas.

  • A solução da AngeloS foi a que escolhi no final, pois ela acabou de criar os efeitos que eu queria. No entanto, fiz duas pequenas alterações ao LinearLayoutredor do botão:

    • Primeiro, como eu não queria ter nenhum valor absoluto em meu layout, mudei android:layout_height="45px"para wrap_content, o que também funciona bem.

    • Em segundo lugar, como eu queria que o botão ficasse centralizado horizontalmente, o que só é suportado pela vertical LinearLayout, alterei android :idance = "horizontal" para "vertical".

    AngeloS também afirmou em sua postagem inicial que não tinha certeza se o android:layout_weight="0.1"parâmetro em LinearLayouttorno do ListViewteve algum efeito; Eu apenas tentei e realmente funciona! Sem, o botão é empurrado para fora da tela novamente.


desta forma, o layout relativo interno está crescendo mais que a tela, uma etapa pode ser adicionar android:layout_alignParentBottom="true". Mas, para ser claro, você deseja que o botão permaneça anexado à parte inferior do ListView quando houver poucos itens? Se sim, veja o que diz Rich.
— bigstones

sim, é isso que eu quero.
— água

anos depois, agora temos altura máxima graças ao ConstraintLayout: stackoverflow.com/questions/42694355/…
— user1506104

Respostas:


55

Eu tive esse problema exato e para resolvê-lo criei dois separados LinearLayoutspara abrigar o ListViewe Buttonrespectivamente. A partir daí, coloco os dois em outro Linear Layoute configurei o contêiner android:orientationpara vertical. Eu também definir o peso do o LinearLayoutque abrigava a ListViewpara 0.1, mas não sei se isso tem algum efeito. A partir daí, você pode definir a altura do recipiente inferior (que contém o seu botão) para qualquer altura que desejar.

EDITAR isto é o que quero dizer:

<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:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_weight="0.1"
    android:orientation="horizontal">

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

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

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

</LinearLayout>

A solução acima corrigirá o botão na parte inferior da tela.


Para que o botão flutue na parte inferior da lista, altere a altura de ListView01para 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:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_weight="0.1"
    android:orientation="horizontal">

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

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

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


Eu vejo isso como algo semelhante a <divtags em HTML .. é apenas um invólucro e essa solução definitivamente funciona.
— AngeloS

E com relação à sobrecarga, não é muito diferente do que você está fazendo com os layouts relativos .. agora você tem um invólucro externo e está aninhando outro .. estou sugerindo que aninhe apenas mais um e divida a exibição de lista e o botão em dois contêineres, criando um efeito de pilha no layout linear vertical. Eu não posso enfatizar o suficiente que esta é uma solução de trabalho.
— AngeloS

1
SIM! isso funciona! importante observar, a única diferença entre a primeira e a segunda solução é que o linearlayout precisa para wrap_content, então terminei com um tipo de iniciação configurado: imgur.com/c9L1Z . Para qualquer pessoa que descubra isso: a ponderação é importante, mas pode assumir qualquer valor.
— Sam

2
não há necessidade de envolver todas as visualizações assim - confira a solução do @ Sparkle
— Richard Le Mesurier

É necessário colocar 45px ou um valor exato para o layout do botão? Preciso colocar wrap_content em vez disso
— Mario Velasco

65

Resolvi esse problema no código, definindo a altura do listview apenas se ele contiver mais de 5 itens:

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

Observe que eu defino a altura máxima para 5,5 vezes a altura de um único item, então o usuário saberá com certeza que há alguma rolagem a ser feita! :)


1
Boa resposta. Com esse código descobri a altura do meu item, e agora posso definir o tamanho da minha lista para mostrar quantos itens quero. Obrigado.
— Derzu de

3
Esta é a melhor resposta. Por que escrever 50 linhas de XML aninhado quando você pode resolver o problema com 5 linhas de código?
— Greg Ennis

Obrigado @shaylh. Funcionou perfeitamente.
— Anju

Mesmo tendo limpado as soluções XML muito bem, ainda acabei usando essa ideia em meu produto final.
— Richard Le Mesurier de

1
@JayR nunca é tarde para comentar
— Manza

21

Em sua última edição, você só precisa adicionar também android:layout_above="@+id/butt1"em seu código ListView.

E para mostrar a você (e a todos aqui que tentaram uma resposta anteriormente) que você realmente não precisa usar mais de um RelativeLayout, aqui está seu código corrigido :

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

e o resultado , usando alguma lista aleatória:
insira a descrição da imagem aqui


1
Muito, muito obrigado por sua ajuda, mas ter o botão fixado na parte inferior da tela não era o que eu pretendia. Ele deveria estar na parte inferior do ListView.
— água

Na verdade, parece que desta vez LinearLayouts pode ser a única solução para o que você deseja; Eu tentei diferentes combinações com RelativeLayouts, e nenhuma funcionou :( ... Mas estou feliz que você encontrou sua resposta.
— Adinia,

1
Obrigado! Está perfeito!
— Guicara

6

Usando LinearLayout, defina a altura de seu ListViewe Buttonpara wrap_contente adicione um peso = 1 a ListView. Isso deve funcionar como você deseja.
E sim, defina o layout_gravityde Buttonparabottom


6

Encontrou uma maneira de fazer isso sem usar contêineres aninhados, inspirado na solução da AngeloS.

Usei um LinearLayoutcom orientação vertical, que tem um ListViewe um botão. Eu defino o android:layout_weight="0.1"para o ListView.

Consegue colocar o botão sempre no final da lista. E o botão não é empurrado para fora da tela quando a lista aumenta.

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

2
Não, apenas tentei e o botão fica na parte inferior da tela, não fica na parte inferior da lista. :(
— Adinia

@Adinia Isso funciona perfeitamente pelo menos no 4.4.3. Boa solução, Sparkle, deve ter mais votos.
— Richard Le Mesurier de

Humm ... talvez você tenha algumas outras configurações em seu layout? Acabei de testar novamente em um Nexus 4 com 4.4.3, e o botão fica na parte inferior do layout, não na lista, ele não adere à lista.
— Adinia

2
@Richard Le Mesurier De fato, com android:layout_height="wrap_content" o LinearLayout, como na sua solução, está funcionando perfeitamente, e não apenas no 4.4.3, mas como o Sparkle não mencionou, eu tentei match_parentantes.
— Adinia

Trabalhando no Pie também. +1
— Zubair Younas

5

RelativeLayout é uma solução, se você não quiser que o botão fique muito perto da parte inferior, você pode adicionar margens (o preenchimento de um botão iria quebrá-lo porque ele usa um fundo de 9 remendos e define seu próprio preenchimento).

Seria o mesmo se você usasse a LinearLayout: a maneira de conseguir o que deseja é definir o ListViewpara a altura = 0 e peso = 1, e para o botão altura = wrap_content e peso = 0. (definir ambos como wrap_content, como o usuário639183 disse, não limitaria ListViewa altura de).


Sim, vai limitar a ListViewaltura de
— ernazm

@ user639183 acabou de tentar, você está certo. Sinto muito, eu tinha tanta certeza disso.
— bigstones

Mudei o peso conforme sugerido (antes, eu tinha o peso do ListView = 2 e o peso do botão = 1, me pergunto por que isso não funcionou?) O efeito é muito interessante: o botão agora é empurrado apenas até a metade da tela. Na verdade, posso fazê-lo ficar onde quero adicionando alguns "android: layout_marginBottom". No entanto, também posso tentar a abordagem do Maxims e ver se está funcionando também.
— água

@ água-viva: Não sei, minhas certezas foram demolidas por @ user639183. A ideia é que toda a altura seja compartilhada pelas duas visualizações. A quantidade de compartilhamentos que eles obtêm é dada por seu peso, então 1-0 -> tudo para o primeiro (2-1 daria 1/3 de espaço para o segundo). Achei que definir wrap_content em uma exibição de rolagem o tornaria tão alto quanto seu conteúdo. No entanto ... você definiu o layout externo para fill_parent?
— bigstones

É realmente estranho que um RelativeLayout aninhado (como sugerido por Maxim) não funcione. Eu poderia postar acima, pois tenho a sensação de que perdi algo ...
— água

2

Você provavelmente pode fazer isso funcionar usando contêineres aninhados. É possível que você precise envolver o botão em um segundo contêiner (interno) para que ele ocupe mais espaço e apenas alinhar o botão ao topo do contêiner interno.

Possível algo assim:

Esquema relativo

-- Exibição de lista

-- Esquema relativo

---- Botão

Usando as diferentes opções de alinhamento nos dois contêineres, você deve conseguir fazer isso funcionar.


Eu acho que usar um relativeLayout é a melhor solução, mas eu realmente não consigo ver por que você usaria containers aninhados, quando você pode apenas usar algo como android:layout_marginTop="30dip" para o Botão, se quiser mais espaço entre a Lista e o Botão, por exemplo.
— Adinia,

na pergunta, o OP disse que se ele fizer estritamente o posicionamento do botão em relação ao ListView, ele sai da tela assim que o ListView crescer o suficiente. Nesses tipos de casos, você precisa ser complicado com contêineres aninhados
— Rich

2

Esta é a maneira mais limpa de fazer isso:

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

É semelhante à solução de Angelos, mas você não precisa do linearlayout que envolve o ListView. Você também pode usar um FrameLayout que é mais leve do que um LinearLayout para encerrar o Botão.


2

A ideia é delineada nas soluções muito boas por:

Ambos parecem funcionar perfeitamente pelo menos na v4.4.3.

Eu ainda tive que gastar algum tempo escrevendo o código de teste para verificar e confirmar cada método. Abaixo está o código de teste mínimo necessário e independente.


O layout é baseado na solução do Sparkle, pois contém menos layout aninhado. Também foi atualizado para refletir as verificações atuais do LINT.

<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 fornece o código padrão para testar a solução por si mesmo.

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

Sinta-se à vontade para adicionar ou melhorar, pois este é um "wiki da comunidade".


1

Tente usar o RelativeLayout com o botão na parte inferior. Defina a altura do layout como "wrap_content". Eu não tentei. Apenas ideia


Eu realmente pensei que isso deveria funcionar, mas parece que não. O layout preenche todo o espaço restante, como se a altura fosse definida como match_parent. Mas não faz sentido.
— água

1

no LinearLayout, basta adicionar android:layout_weight="1"a você ListView


0

A seguir está o que funcionou para mim ...

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


                }

Nota: O params.width = ... Precisa ser definido também ...

O exemplo acima é quando você usa TableRow e ListView dentro de TableRow ...


0

envolver o conteúdo em layout linear

na visualização de lista, adicione: android: layout_weight = "1"

em seu botão definir altura fixa

<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

Se você deseja que o conteúdo abaixo da visualização de lista desça conforme os elementos são adicionados à lista, tente esta solução:

Adicione preenchimento positivo na parte inferior da visualização de lista e preenchimento negativo na parte superior do "rodapé". Isso funcionará em um layout linear ou relativo.

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

-1

Como não há atributo MaxHeight, sua melhor aposta é definir a altura do ListView para um valor definido ou usar wrap_content.


-2

Resolvi isso colocando o ListView dentro de um ScrollView. Lint não gostou, mas adicionando minHeight e definindo fillViewport como true, obtive um bom resultado.

    <ScrollView 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="1dp"
        android:layout_marginRight="1dp"
        android:minHeight="100dp"
        android:fillViewport="true"
        android:fadeScrollbars="false"
        android:paddingTop="2dp" 
        android:orientation="vertical"
        android:scrollbarAlwaysDrawVerticalTrack="true" >

        <ListView
            android:id="@+id/workoutAElistRoutines"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="fill_vertical"
            android:background="@drawable/dialog_inner_border_tan"
            android:choiceMode="singleChoice"
            android:orientation="vertical"
            android:paddingLeft="3dp"
            android:paddingRight="3dp" >

        </ListView>
    </ScrollView>        

Eu tentei essa abordagem, embora ela limite o tamanho do listview, não me deixa rolar o listview, o que é estranho. Você sabe por quê?
— Eduardo

7
NUNCA coloque um ListView dentro de um ScrollView!
— jenzz

Sim, nunca coloque um ListView dentro de um ScrollView. Mas com este "hack" é possível ... stackoverflow.com/a/14577399/1255990
— Leonardo Cardoso
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.