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.


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>


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! :)


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


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


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

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


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


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.


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


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ł


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


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


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>

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

-1

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


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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.