Ogranicz wysokość ListView w systemie Android

92

Chcę pokazać przycisk pod a ListView. Problem polega na tym, że jeśli ListViewzostanie wydłużony (dodane elementy ...), przycisk zostanie wypchnięty z ekranu.

Próbowałem LinearLayoutz wagami (jak zasugerowano w Androidzie: dlaczego nie ma maxHeight dla widoku? ), Ale albo źle zrozumiałem wagi, albo po prostu nie działało.

Również znalazłem gdzieś wskazówkę dotyczącą użycia pliku RelativeLayout. ListViewBędzie wówczas ustawiony nad przyciskiem z android:layout_aboveparam.

Problem polega na tym, że nie wiem, jak później ustawić przycisk. W przykładzie, który znalazłem, widok poniżej ListViewzostał dostosowany za pomocą android:layout_alignParentBottom, ale nie chcę, aby mój przycisk przylgnął do dolnej części ekranu.

Jakieś pomysły poza zastosowaniem metody setHeight i obliczeniem wymaganej przestrzeni?


Edycja: otrzymałem wiele przydatnych odpowiedzi.

  • Rozwiązanie bigstone & user639183 działało prawie idealnie. Musiałem jednak dodać dodatkowe wypełnienie / margines na dole przycisku, ponieważ nadal byłby wypychany do połowy z ekranu (ale potem zatrzymany)

  • Odpowiedź Adinii ze względnym układem jest w porządku tylko wtedy, gdy chcesz, aby przycisk był przymocowany do dołu ekranu. Nie to chciałem, ale nadal może być przydatne dla innych.

  • Rozwiązanie AngeloS było tym, które wybrałem na koniec, ponieważ stworzyło takie efekty, jakie chciałem. Jednak dokonałem dwóch drobnych zmian w obszarze LinearLayoutwokół przycisku:

    • Po pierwsze, ponieważ nie chciałem mieć żadnych wartości bezwzględnych w moim układzie, zmieniłem android:layout_height="45px"na wrap_content, co również działa dobrze.

    • Po drugie, ponieważ chciałem, aby przycisk był wyśrodkowany w poziomie, co jest obsługiwane tylko w pionie LinearLayout, zmieniłem android: orientacja = "pozioma" na "pionowa".

    AngeloS stwierdził również w swoim początkowym poście, że nie był pewien, czy android:layout_weight="0.1"parametr w LinearLayoutokolicy ListViewmiał jakikolwiek wpływ; Właśnie próbowałem i faktycznie działa! Bez przycisku przycisk zostaje ponownie wypchnięty z ekranu.

Meduza
źródło
w ten sposób wewnętrzny układ względny wydłuża się niż ekran, jednym krokiem może być dodanie android:layout_alignParentBottom="true". Ale żeby było jasne, czy chcesz, aby przycisk pozostawał dołączony do dołu ListView, gdy jest kilka elementów? Jeśli tak, zobacz, co mówi Rich.
bigstones
tak, tego właśnie chcę.
meduzy
lata później mamy teraz maksymalną wysokość dzięki ConstraintLayout: stackoverflow.com/questions/42694355/…
user1506104

Odpowiedzi:

55

Miałem dokładnie ten problem i aby go rozwiązać, stworzyłem dwa osobne, LinearLayoutsaby pomieścić odpowiednio ListViewi Button. Stamtąd włożyłem oba Linear Layouti ustawiłem ten pojemnik android:orientationna vertical. Ustawiłem również wagę tego, w LinearLayoutktórym mieści ListViewsię, 0.1ale nie wiem, czy to ma jakiś wpływ. Stamtąd możesz ustawić wysokość dolnego pojemnika (z przyciskiem) na dowolną wysokość.

EDYTUJ to mam na myśli:

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

Powyższe rozwiązanie naprawi przycisk na dole ekranu.


Aby przycisk znajdował się swobodnie u dołu listy, zmień wysokość ListView01na 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>

AngeloS
źródło
Widzę to jako coś podobnego do <divtagów w HTML .. to tylko opakowanie i to rozwiązanie zdecydowanie działa.
AngeloS
A jeśli chodzi o narzuty, to niewiele różni się od tego, co robisz ze względnymi układami… w tej chwili masz jedno zewnętrzne opakowanie i zagnieżdżasz inne… Sugeruję zagnieżdżenie jeszcze jednego i podzielenie widoku listy a przycisk do dwóch kontenerów, tworząc efekt stosu w pionowym układzie liniowym. Nie mogę wystarczająco podkreślić, że jest to działające rozwiązanie.
AngeloS
1
TAK! to działa! ważne, aby pamiętać, jedyną różnicą między pierwszym a drugim rozwiązaniem jest linearlayout, który musi zawierać wrap_content, więc skończyłem z ustawieniem typu początkowego : imgur.com/c9L1Z . Toa każdego, kto to znajdzie: waga jest ważna, ale może mieć dowolną wartość.
Sam
2
nie ma potrzeby zawijania wszystkich widoków w ten sposób - zobacz rozwiązanie @ Sparkle
Richard Le Mesurier
Czy potrzebne jest podanie 45 pikseli lub dokładnej wartości układu przycisku? Muszę zamiast tego wstawić wrap_content
Mario Velasco,
65

Rozwiązałem ten problem w kodzie, ustawiając wysokość widoku listy tylko wtedy, gdy ma więcej niż 5 elementów:

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

Zwróć uwagę, że ustawiłem maksymalną wysokość na 5,5 razy większą niż wysokość pojedynczego elementu, aby użytkownik wiedział na pewno, że musi wykonać przewijanie! :)

shaylh
źródło
1
Niezła odpowiedź. Za pomocą tego kodu odkrywam wysokość mojego przedmiotu, a teraz mogę ustawić rozmiar mojej listy, aby pokazać, ile chcę elementów. Dzięki.
Derzu
3
To najlepsza odpowiedź. Po co pisać 50 wierszy zagnieżdżonego XML, skoro można rozwiązać problem za pomocą 5 linijek kodu?
Greg Ennis
Dziękuję @shaylh. Działał doskonale.
Anju
Mimo że ładnie wyczyściłem rozwiązania XML, ostatecznie wykorzystałem ten pomysł w moim produkcie końcowym.
Richard Le Mesurier
1
@JayR nigdy nie jest za późno na komentarz
Manza
21

Podczas ostatniej edycji wystarczy dodać również android:layout_above="@+id/butt1"kod ListView.

Aby pokazać Ci (i wszystkim tutaj, którzy wcześniej próbowali odpowiedzieć), że naprawdę nie musisz używać więcej niż jednej RelativeLayout, oto poprawiony kod :

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

i wynik , używając losowej listy:
wprowadź opis obrazu tutaj

Adinia
źródło
1
Dziękuję bardzo, bardzo za pomoc, ale mający przycisk umieszczony na dole ekranu po prostu nie to, co zamierzałem. Powinien znajdować się na dole ListView.
meduzy
Rzeczywiście, wydaje się, że tym razem LinearLayouts może być jedynym rozwiązaniem tego, czego chcesz; Wypróbowałem różne kombinacje z RelativeLayouts i żadna tak naprawdę nie działała :( ... Ale cieszę się, że znalazłeś odpowiedź.
Adinia
1
Dziękuję Ci! Jest doskonały!
Guicara
6

Za pomocą LinearLayoutustaw wysokość swojego ListViewi Buttondo wrap_contentoraz dodaj wagę = 1 do ListView. To powinno działać tak, jak chcesz.
I tak, ustaw layout_gravitywartość Buttonnabottom

ernazm
źródło
6

Znalazłem sposób na zrobienie tego bez użycia zagnieżdżonych kontenerów, zainspirowany rozwiązaniem AngeloS.

Użyłem litery LinearLayoutz orientacją pionową, która ma ListViewi przycisk. Ustawiłem android:layout_weight="0.1"dlaListView .

Udaje mu się zawsze umieścić przycisk na dole listy. Przycisk nie jest wypychany z ekranu, gdy lista rośnie.

<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"
    />
Blask
źródło
2
Nie, po prostu spróbowałem, a przycisk pozostaje na dole ekranu, nie pozostaje na dole listy. :(
Adinia,
@Adinia Działa to doskonale przynajmniej na 4.4.3. Niezłe rozwiązanie, Sparkle, powinno mieć więcej głosów.
Richard Le Mesurier
Humm… może masz jakieś inne ustawienia w swoim układzie? Właśnie przetestowałem ponownie na Nexusie 4 z 4.4.3, a przycisk pozostaje na dole układu, a nie na liście, nie przykleja się do listy.
Adinia
2
@Richard Le Mesurier Rzeczywiście, z android:layout_height="wrap_content" LinearLayout, tak jak w twoim rozwiązaniu, działa idealnie i nie tylko na 4.4.3, ale ponieważ Sparkle o tym nie wspomniał, próbowałem go match_parentwcześniej.
Adinia
Pracuję też nad Pie. +1
Zubair Younas
5

RelativeLayout jest rozwiązaniem, jeśli nie chcesz, aby przycisk znajdował się zbyt blisko dołu, możesz dodać marginesy (wypełnienie przycisku mogłoby go złamać, ponieważ używa tła z 9 łatami i ustawia własne wypełnienie).

Byłoby tak samo, gdybyś użył a LinearLayout: sposobem na osiągnięcie tego, co chcesz, jest ustawienie ListViewwysokości = 0 i wagi = 1, a dla przycisku wysokość = zawartość_zawijania i waga = 0. (ustawienie obu na wrap_content, jak powiedział użytkownik639183, nie ograniczy ListViewwysokości).

wielkie kamienie
źródło
Tak, to ograniczy ListViewwysokość
ernazm
@ user639183 właśnie próbowałam, masz rację Przepraszam, byłem tego taki pewien.
bigstones
Zmieniłem wagę zgodnie z sugestią (wcześniej miałem wagę ListView = 2 i wagę przycisku = 1, zastanawiam się, dlaczego to nie zadziałało?) Efekt jest bardzo interesujący: przycisk jest teraz wypychany tylko do połowy z ekranu. Właściwie mogę sprawić, by pozostał tam, gdzie chcę, dodając trochę „android: layout_marginBottom”. Jednak mógłbym również wypróbować podejście Maxims i sprawdzić, czy to też działa.
meduzy
@jellyfish: Nie wiem, moje przekonania zostały zburzone przez @ user639183. Chodzi o to, że cała wysokość będzie wspólna dla dwóch widoków. Ilość otrzymywanych udziałów jest podana ich wagi, więc 1-0 -> wszystko do pierwszego (2-1 dałoby 1/3 miejsca drugiej). Pomyślałem, że ustawienie wrap_content na przewijanym widoku sprawi, że będzie tak wysoki, jak jego zawartość. Jednak… czy ustawiłeś zewnętrzny układ na fill_parent?
bigstones
To naprawdę dziwne, że zagnieżdżony RelativeLayout (zgodnie z sugestią Maxima) nie działa. Mogę po prostu opublikować to powyżej, ponieważ mam wrażenie, że właśnie przegapiłem coś ...
meduza
2

Prawdopodobnie możesz to wykonać, używając kontenerów zagnieżdżonych. Możliwe, że będziesz musiał owinąć Button w drugim (wewnętrznym) pojemniku, aby zajmował więcej miejsca, i po prostu wyrównaj Button do górnej części pojemnika wewnętrznego.

Możliwe coś takiego:

RelativeLayout

- ListView

- RelativeLayout

---- Przycisk

Używając różnych opcji wyrównania w dwóch kontenerach, powinieneś być w stanie to zadziałać.

Bogaty
źródło
Myślę, że najlepszym rozwiązaniem jest relatywny układ, ale naprawdę nie rozumiem, dlaczego miałbyś używać zagnieżdżonych kontenerów, skoro możesz po prostu użyć czegoś podobnego android:layout_marginTop="30dip" do przycisku, jeśli chcesz na przykład więcej miejsca między listą a przyciskiem.
Adinia
w pytaniu OP powiedział, że jeśli ściśle ustawi pozycję przycisku względem ListView, zniknie on z ekranu, gdy ListView osiągnie odpowiednią wysokość. W tego typu przypadkach trzeba się trochę pogodzić z zagnieżdżonymi kontenerami
Rich
2

Oto najczystszy sposób na zrobienie tego:

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

Jest podobny do rozwiązania Angelosa, ale nie potrzebujesz układu liniowego, który otacza ListView. Możesz również użyć FrameLayout, który jest lżejszy w porównaniu do LinearLayout, aby zawinąć Button.

user2994360
źródło
2

Ideę w bardzo dobrych rozwiązaniach zarysowuje:

Oba wydają się działać doskonale przynajmniej w wersji 4.4.3.

Nadal musiałem poświęcić trochę czasu na pisanie kodu testowego, aby go sprawdzić i potwierdzić każdą metodę. Poniżej znajduje się samodzielny, wymagany minimalny kod testowy.


Layout jest oparty na rozwiązaniu Sparkle, ponieważ zawiera mniej zagnieżdżonych układów. Został również zaktualizowany, aby odzwierciedlić obecne kontrole 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>

Aktywność zawiera standardowy kod do samodzielnego przetestowania rozwiązania.

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

Zapraszam do dodawania lub ulepszania, ponieważ jest to „wiki społeczności”.

Richarda Le Mesuriera
źródło
1

Spróbuj użyć RelativeLayout z przyciskiem na dole. Ustaw wysokość układu jako „wrap_content”. Nie próbowałem tego. Po prostu pomysł

Maksyma
źródło
Naprawdę myślałem, że to powinno działać, ale wygląda na to, że nie. Układ wypełnia całą pozostałą przestrzeń, tak jakby wysokość była ustawiona na match_parent. Nie ma to jednak sensu.
meduzy
1

w LinearLayout, po prostu dodaj android:layout_weight="1"do siebie ListView

DawnYu
źródło
0

Oto, co zadziałało dla mnie ...

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


                }

Uwaga: parametr params.width = ... należy również ustawić ...

Powyższy przykład dotyczy użycia TableRow i ListView w TableRow ...

Atul Dravid - White Pvt. Sp. z o.o.
źródło
0

zawiń zawartość w układzie liniowym

w widoku listy dodaj: android: layout_weight = "1"

w Twoim Button ustaw stałą wysokość

<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>
Toma
źródło
0

Jeśli chcesz, aby zawartość poniżej widoku listy przesuwała się w dół w miarę dodawania elementów do listy, wypróbuj następujące rozwiązanie:

Dodaj dopełnienie dodatnie na dole widoku listy i dopełnienie ujemne na górze „stopki”. To zadziała w układzie liniowym lub względnym.

<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"/>
Jenny Pushkarskaya
źródło
-1

Ponieważ nie ma atrybutu MaxHeight, najlepszym rozwiązaniem jest ustawienie wysokości ListView na określoną wartość lub użycie wrap_content.

Chris Cashwell
źródło
-2

Rozwiązałem ten problem, umieszczając ListView wewnątrz ScrollView. Lintowi się to nie podobało, ale dodając minHeight i ustawiając fillViewport na true, mam niezły wynik.

    <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>        
Jon
źródło
Wypróbowałem to podejście, nawet jeśli ogranicza rozmiar widoku listy, nie pozwala mi przewijać widoku listy, co jest niezręczne. Wiesz dlaczego?
Eduardo,
7
NIGDY nie umieszczaj ListView wewnątrz ScrollView!
jenzz
Tak, nigdy nie umieszczaj ListView wewnątrz ScrollView. Ale dzięki temu „hackowi” jest to możliwe ... stackoverflow.com/a/14577399/1255990
Leonardo Cardoso