Обмежити висоту ListView на Android


92

Я хочу показати кнопку під ListView. Проблема полягає в тому, що якщо ListViewдодаток розширюється (елементи додаються ...), кнопка виштовхується з екрану.

Я спробував a LinearLayoutз вагами (як пропонується в Android: чому для перегляду немає maxHeight? ), Але або я неправильно зрозумів ваги, або він просто не спрацював.

Крім того, я десь знайшов підказку щодо використання RelativeLayout. ListViewПотім буде встановлено над кнопкою з android:layout_aboveпарами.

Проблема в тому, що я не знаю, як потім розташувати кнопку. У прикладі, який я знайшов, подання нижче ListViewбуло відрегульовано за допомогою android:layout_alignParentBottom, але я не хочу, щоб моя кнопка чіплялася внизу екрана.

Будь-які ідеї, крім використання методу setHeight та деяких обчислень необхідного простору?


Редагувати: Я отримав багато корисних відповідей.

  • Рішення bigstone та user639183 майже працювали ідеально. Однак мені довелося додати додаткове заповнення / поле внизу кнопки, оскільки воно все одно буде висунуте наполовину з екрана (але потім зупинено)

  • Відповідь Adinia лише відносним макетом чудова, якщо ви хочете, щоб кнопка була зафіксована внизу екрана. Це не те, що я задумав, але все одно може бути корисним для інших.

  • Рішення AngeloS було тим, яке я вибрав наприкінці, оскільки воно просто створило ефекти, яких я хотів. Однак я вніс дві незначні зміни LinearLayoutнавколо кнопки:

    • По-перше, оскільки я не хотів, щоб у моєму макеті були якісь абсолютні значення, я перейшов android:layout_height="45px"на wrap_content, що також прекрасно працює.

    • По-друге, оскільки я хотів, щоб кнопка була по центру горизонтально, що підтримується лише вертикаллю LinearLayout, я змінив android: direction = "horizontal" на "vertical".

    AngeloS також заявив у своєму початковому дописі, що він не був впевнений, чи має android:layout_weight="0.1"параметр LinearLayoutнавколо ListViewякийсь ефект; Я просто спробував, і це насправді так! Без цього кнопка знову виштовхується з екрану.


таким чином внутрішній відносний макет стає довшим, ніж екран, можна додати один крок android:layout_alignParentBottom="true". Але щоб було зрозуміло, чи хочете ви, щоб кнопка залишалася прикріпленою внизу ListView, коли елементів мало? Якщо так, то подивіться, що каже Річ.
bigstones

так, це те, що я хочу.
медуза

років після того, як ми тепер маємо максимальну висоту завдяки ConstraintLayout: stackoverflow.com/questions/42694355 / ...
user1506104

Відповіді:


55

У мене було саме це питання, і для його вирішення я створив два окремі LinearLayoutsбудинки для розміщення ListViewі Buttonвідповідно. Звідти я ставлю як в інший Linear Layoutі наборі , який контейнер android:orientationв vertical. Я також встановити вагу , LinearLayoutщо розміщувався ListViewна , 0.1але я не знаю , якщо це має якийсь - або ефект. Звідти ви можете встановити висоту нижнього контейнера (на якому є ваша кнопка) до будь-якої висоти, яку ви хотіли б.

EDIT це те, що я маю на увазі:

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

Вищевказане рішення зафіксує кнопку внизу екрана.


Щоб кнопка плавала внизу списку, змініть висоту ListView01на 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>


Я бачу це як щось подібне до <divтегів у HTML .. це просто обгортка, і це рішення, безумовно, працює.
AngeloS

А що стосується накладних витрат, це не сильно відрізняється від того, що ви робите з відносними макетами .. зараз у вас є одна зовнішня обгортка, і ви вкладаєте іншу .. я пропоную вам вкласти ще одну і розділити вигляд списку і кнопку у два контейнери, що створює ефект стека у вертикальному лінійному компонуванні. Я не можу підкреслити, що це робоче рішення.
AngeloS

1
ТАК! це працює! важливо зауважити, єдина різниця між вашим першим та другим рішенням полягає у необхідності linearlayout wrap_content, тому я закінчив із встановленим початковим типом: imgur.com/c9L1Z . Для всіх, хто вважає це: зважування важливо, але може приймати будь-яке значення.
Сем

2
не потрібно так обгортати всі погляди - перевірте рішення @ Sparkle
Richard Le Mesurier

Чи потрібно вказати 45 пікселів або точне значення для розкладки кнопок? Мені потрібно поставити wrap_content замість цього
Маріо Веласко

65

Я вирішив цю проблему в коді, встановивши висоту перегляду списку, лише якщо в ньому більше 5 елементів:

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

Зверніть увагу, що я встановив максимальну висоту в 5,5 разів більше висоти окремого предмета, тому користувач точно знатиме, що потрібно виконати прокрутку! :)


1
Приємна відповідь. За допомогою цього коду я виявляю висоту свого предмета, і тепер я можу встановити розмір свого списку, щоб показати, скільки ітен я хочу. Дякую.
Derzu

3
Це найкраща відповідь. Навіщо писати 50 рядків вкладеного XML, коли можна вирішити проблему за допомогою 5 рядків коду?
Грег Енніс

Дякую @shaylh. Працював ідеально.
Anju

Незважаючи на те, що я добре очистив рішення XML, я все одно використав цю ідею у своєму кінцевому продукті.
Річард Ле Мес'єр'є,

1
@JayR ніколи не пізно коментувати
Манза

21

Під час останнього редагування вам просто потрібно додати android:layout_above="@+id/butt1"свій код ListView.

І щоб показати вам (і всім, хто раніше намагався відповісти), що вам дійсно не потрібно використовувати більше одного RelativeLayout, ось ваш виправлений код :

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

і результат , використовуючи якийсь випадковий список:
введіть тут опис зображення


1
Щиро дякую за допомогу, але закріплення кнопки внизу екрану було просто не тим, що я передбачав. Це повинно бути внизу ListView.
медуза

Справді, здається, цього разу LinearLayouts може бути єдиним рішенням для того, що ви хочете; Я пробував різні комбінації з RelativeLayouts, і жодна з них насправді не спрацьовувала :( ... Але я рада, що ви знайшли свою відповідь.
Adinia

1
Дякую! Це прекрасно!
Гікара

6

Використовуючи LinearLayout, встановіть висоту вашого ListViewі Buttonдо wrap_contentі додайте вагу = 1 до ListView. Це має працювати так, як ти хочеш.
І так, встановіть layout_gravityзначення Buttonнаbottom


6

Знайшов спосіб зробити це, не використовуючи вкладені контейнери, натхненний рішенням AngeloS.

Я використовував a LinearLayoutз вертикальною орієнтацією, що має ListViewкнопку і. Я встановив android:layout_weight="0.1"для ListView.

Йому вдається завжди дотримуватися кнопки внизу списку. І кнопка не відштовхується від екрана, коли список зростає.

<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
Ні, просто спробував, і кнопка залишається внизу екрана, вона не залишається внизу списку. :(
Adinia

@Adinia Це чудово працює принаймні на 4.4.3. Гарне рішення, Спаркл, повинно мати більше голосів.
Річард Ле Мессюр'є,

Хамм..може, у вас є якісь інші налаштування у вашому макеті? Я щойно протестував на Nexus 4 з 4.4.3, і кнопка залишається внизу макета, а не в списку, вона не прилипає до списку.
Adinia

2
@Richard Le Mesurier Справді, android:layout_height="wrap_content" для LinearLayout, як у вашому рішенні, він працює ідеально, і не тільки на 4.4.3, але оскільки Sparkle про це не згадував, я пробував це і match_parentраніше.
Adinia

Також працюємо над Пирогом. +1
Зубайр Юнас,

5

RelativeLayout це рішення, якщо ви не хочете, щоб кнопка залишалася занадто близько до нижньої частини, ви можете додати поля (заповнення кнопки зламало б її, оскільки вона використовує 9-патч-фон, і вона встановлює власні відступи).

Це було б так само, якби ви використовували a LinearLayout: спосіб досягти того, що ви хочете, це встановити ListViewдля height = 0 і weight = 1, а для кнопки height = wrap_content і weight = 0. (встановлення обох для wrap_content, як сказав користувач639183, не обмежує ListViewвисоту).


Так, він буде обмежувати ListView«S висота
ernazm

@ user639183 щойно спробував, ти маєш рацію, вибачте, я був у цьому впевнений.
bigstones

Я змінив вагу, як було запропоновано (раніше у мене був ListView вага = 2 і вага кнопки = 1, цікаво, чому це не спрацювало?) Ефект дуже цікавий: кнопка зараз натиснута лише на половину екрану. Насправді, я можу змусити його залишатися там, де я хочу, додавши трохи "android: layout_marginBottom". Однак я міг би також спробувати підхід Максима і перевірити, чи це теж працює.
медуза

@jellyfish: Не знаю, @ user639183 збив мою впевненість. Ідея полягає в тому, що ці два висоти будуть розділені двома видами. Сума отриманих акцій визначається їх вагою, тому 1-0 -> все першому (2-1 дало б 1/3 місця другому). Я думав, що встановлення wrap_content для прокручуваного подання зробить його таким високим, як його вміст. Однак .. ви встановили зовнішній макет fill_parent?
bigstones

Насправді дивно, що вкладений RelativeLayout (як пропонує Максим) не працює. Я можу просто опублікувати це вище, оскільки у мене відчуття, що я просто щось пропустив ...
медуза

2

Можливо, ви можете зробити цю роботу за допомогою вкладених контейнерів. Можливо, вам може знадобитися обернути кнопку у другий (внутрішній) контейнер, щоб він зайняв більше місця, і просто вирівняти кнопку по верхній частині внутрішнього контейнера.

Можливо щось подібне:

RelativeLayout

- ListView

- RelativeLayout

---- Кнопка

Використовуючи різні варіанти вирівнювання на двох контейнерах, ви зможете змусити це працювати.


Я вважаю, що використання relativeLayout є найкращим рішенням, але я справді не можу зрозуміти, чому ви використовуєте вкладені контейнери, коли ви можете просто використовувати щось на кшталт android:layout_marginTop="30dip" кнопки, якщо вам потрібно більше простору між списком і кнопкою, наприклад.
Adinia

у питанні, OP сказав, що якщо він суворо робить позиціонування кнопки відносно ListView, вона відключається від екрану, як тільки ListView виросте досить високим. У таких випадках вам доведеться хитрувати з вкладеними контейнерами
Rich

2

Це найчистіший спосіб зробити це:

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

Це схоже на рішення Анджелоса, але вам не потрібен лінійний макет, який завершує ListView. Також ви можете використовувати FrameLayout, який є легшим порівняно з LinearLayout, щоб обернути кнопку.


2

Ідея викладена в дуже хороших рішеннях:

Здається, вони обидва чудово працюють принаймні на v4.4.3.

Мені все одно довелося витратити трохи часу на написання тестового коду, щоб перевірити його та підтвердити кожен метод. Нижче наведено автономний мінімальний код тесту.


Макет заснований на рішенні Sparkle, оскільки він містить менше вкладеного макета. Також оновлено з урахуванням поточних перевірок 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 надає шаблонний код, щоб випробувати рішення самостійно.

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

Не соромтеся додавати або вдосконалювати, оскільки це "вікі спільноти".


1

Спробуйте використовувати RelativeLayout із кнопкою внизу. Встановіть висоту макета як "wrap_content". Я не пробував. Просто ідея


Я справді думав, що це має спрацювати, але, здається, ні. Макет заповнює весь простір, що залишився, ніби висоту встановлено на match_parent. Однак сенсу немає.
медуза


0

Ось що мені вдалося ...

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


                }

Примітка: Params.width = ... Потрібно також встановити ...

Наведений вище приклад - це коли ви використовуєте TableRow і ListView всередині TableRow ...


0

обернути вміст у лінійний макет

у поданні списку додайте: android: layout_weight = "1"

у вашій кнопці встановіть фіксовану висоту

<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

Якщо ви хочете, щоб вміст під поданням списку переміщувався вниз, коли елементи додаються до списку, спробуйте це рішення:

Додайте додатне заповнення внизу списку та негативне заповнення у верхню частину "нижнього колонтитула". Це буде працювати в лінійному макеті або відносному макеті.

<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

Оскільки не існує атрибута MaxHeight, найкращим варіантом є встановити висоту ListView на встановлене значення або використовувати wrap_content.


-2

Я вирішив це, помістивши ListView всередину ScrollView. Лінту це не сподобалось, але додавши minHeight і встановивши fillViewport на true, я маю хороший результат.

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

Я спробував такий підхід, навіть якщо він обмежує розмір перегляду списку, це не дозволяє мені прокручувати перегляд списку, що незручно. Ти знаєш чому?
Едуардо

7
НІКОЛИ не кладіть ListView всередину ScrollView!
jenzz

Так, ніколи не кладіть ListView всередину ScrollView. Але з цим "рубати" можливо ... stackoverflow.com/a/14577399/1255990
Леонардо Кардосо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.