Як вирівняти подання внизу екрана?


635

Ось мій код компонування;

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView android:text="@string/welcome"
        android:id="@+id/TextView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
    </TextView>

    <LinearLayout android:id="@+id/LinearLayout"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="bottom">

            <EditText android:id="@+id/EditText"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">
            </EditText>

            <Button android:text="@string/label_submit_button"
                android:id="@+id/Button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
            </Button>

    </LinearLayout>

</LinearLayout>

Як це виглядає зліва, і як я хочу, щоб це виглядало, справа.

Макет Android - фактичний (зліва) та бажаний (праворуч)

Очевидною відповіддю є встановлення TextView для заповнення_прозрачного по висоті, але це не призводить до того, що не залишається місця для кнопки або поля введення.

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

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


Відповідна схема була справді відповіддю:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView
        android:text="@string/welcome"
        android:id="@+id/TextView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true">
    </TextView>

    <RelativeLayout
        android:id="@+id/InnerRelativeLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true" >

        <Button
            android:text="@string/label_submit_button"
            android:id="@+id/Button"
            android:layout_alignParentRight="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
        </Button>

        <EditText
            android:id="@+id/EditText"
            android:layout_width="fill_parent"
            android:layout_toLeftOf="@id/Button"
            android:layout_height="wrap_content">
        </EditText>

    </RelativeLayout>

</RelativeLayout>

7
@oneself Paint;) Я використовую шкіру на емуляторі, хоча люб’язно надано Tea Vui Huang teavuihuang.com/android
gav

14
+1 для публікації XML-макета, який її вирішив. Допоміг мені зрозуміти, що з моїм не так.
Howler

Відповіді:


526

Сучасний спосіб зробити це - мати ConstraintLayout і обмежити низ подання до низу ConstraintLayout за допомогоюapp:layout_constraintBottom_toBottomOf="parent"

Наведений нижче приклад створює FloatingActionButton, який буде вирівняний в кінці та внизу екрана.

<android.support.constraint.ConstraintLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_height="match_parent"
   android:layout_width="match_parent">

<android.support.design.widget.FloatingActionButton
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"

    app:layout_constraintBottom_toBottomOf="parent"

    app:layout_constraintEnd_toEndOf="parent" />

</android.support.constraint.ConstraintLayout>

Для довідки я збережу свою стару відповідь.

До введення ConstraintLayout відповідь була відносною схемою .


Якщо у вас є відносна компоновка, яка заповнює весь екран, ви повинні мати можливість android:layout_alignParentBottomпереміщати кнопку в нижній частині екрана.

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


5
FYI: це не працює в ScrollView. Це питання, з яким я стикаюся зараз. Див stackoverflow.com/questions/3126347 / ...
IgorGanapolsky

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

ок .. який сенс у другому абзаці відповіді тут? "Ви повинні знайти макет, який спочатку охоплює нижню частину екрана"? тоді ми повинні використовувати layout_alignParentBottom всередині макета? Для чого нам потрібно android:layout_above?
Євген

Вище потрібно, якщо ви хочете щось на зразок смуги внизу, а потім LinearLayout над цією смужкою, яка тягнеться від верхньої частини екрана до смуги.
Януш

1
Я читав в одному з "Android тижневиків", що that RelativeLayoutзаймає пам'ять, і його слід уникати, коли це можливо.
Томаш Муларчик

153

У ScrollViewцьому це не спрацьовує, оскільки RelativeLayoutпотім перекриє все, що знаходиться ScrollViewвнизу сторінки.

Я виправив це за допомогою динамічно розтягування FrameLayout:

<ScrollView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent" 
    android:layout_width="match_parent"
    android:fillViewport="true">
    <LinearLayout 
        android:id="@+id/LinearLayout01"
        android:layout_width="match_parent" 
        android:layout_height="match_parent"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical">

                <!-- content goes here -->

                <!-- stretching frame layout, using layout_weight -->
        <FrameLayout
            android:layout_width="match_parent" 
            android:layout_height="0dp"
            android:layout_weight="1">
        </FrameLayout>

                <!-- content fixated to the bottom of the screen -->
        <LinearLayout 
            android:layout_width="match_parent" 
            android:layout_height="wrap_content"
            android:orientation="horizontal">
                                   <!-- your bottom content -->
        </LinearLayout>
    </LinearLayout>
</ScrollView>

1
це чудово - також це "мінімально інвазивно" та більш інтуїтивно зрозуміло, ніж підхід RelativeLayout. Я б дав більше ніж одну пропозицію, якби міг!
manmal

4
Я використовую ваше рішення у своїй програмі, але в моєму випадку я хочу, щоб при появі клавіатури кнопки залишалися в нижній частині екрана (за клавіатурою). Такси.
Йоанн

1
@DoubleYo: в маніфесті android: windowSoftInputMode = "коригуватиPan"
Kopfgeldjaeger

2
ЯКЩО ви хочете, щоб дно було зафіксовано постійно, так що це показує весь час, це не працює. Інакше це працює.
Карл Моррісон

72

Ви можете зберегти свій початковий лінійний макет, вклавши відносний макет у межах лінійного макета:

<LinearLayout
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView android:text="welcome" 
        android:id="@+id/TextView" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content">
    </TextView>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <Button android:text="submit" 
            android:id="@+id/Button" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true">
        </Button>
        <EditText android:id="@+id/EditText" 
            android:layout_width="match_parent" 
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@id/Button"
            android:layout_alignParentBottom="true">
        </EditText>
    </RelativeLayout>
</LinearLayout>

2
Це безладний підхід, оскільки він не дуже модульний. Ви не повинні мати макетів, що перекриваються. Цей дизайн не працюватиме, як тільки ви хочете змінити фон RelativeLayout або хочете збільшити будь-який із переглядів або додати перегляд.
Патрік

42

Відповідь вище (Януш) цілком правильна, але я особисто не відчуваю себе на 100% комфортно з RelativeLayouts, тому я вважаю за краще ввести «наповнювач», порожній TextView, як це:

<!-- filler -->
<TextView android:layout_height="0dip" 
          android:layout_width="fill_parent"
          android:layout_weight="1" />

перед елементом, який повинен знаходитися внизу екрана.


Це розшириться на вісь x або y. Якщо висота 0dip для висоти зробить перегляд тексту без висоти? або розшириться стільки, скільки може просто подобатися до осі x?
Лукап

Це розширюється вертикально, тому що висота (вертикальна вісь) встановлена ​​на 0, а вага - на 1 (якщо вважати, що інші елементи мають нульову вагу).
Тиморес

На осі x це буде його батько (fill_parent)
Тиморес

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

33

Ви також можете це зробити за допомогою LinearLayout або ScrollView. Іноді це легше здійснити, ніж відносний макет. Єдине, що вам потрібно зробити, це додати наступний вигляд перед переглядами, які ви хочете вирівняти в нижній частині екрана:

<View
    android:layout_width="wrap_content"
    android:layout_height="0dp"
    android:layout_weight="1" />

Це створює порожній вигляд, заповнюючи порожній простір і висуваючи наступні подання в нижній частині екрана.


27

Це також працює.

<LinearLayout 
    android:id="@+id/linearLayout4"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_below="@+id/linearLayout3"
    android:layout_centerHorizontal="true"
    android:orientation="horizontal" 
    android:gravity="bottom"
    android:layout_alignParentBottom="true"
    android:layout_marginTop="20dp"
>

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" 

    />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" 


    />

</LinearLayout>

gravity = "дно", щоб перемістити елементи LinearLayout до низу


12
android: layout_alignParentBottom = "true" не має ефекту, якщо LinearLayout не вкладений всередині RelativeLayout.
Томас Дігнан

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

26

1. Використовуйте ConstraintLayoutу вашому кореневому макеті

І встановіть, app:layout_constraintBottom_toBottomOf="parent"щоб макет був у нижній частині екрана:

<LinearLayout
    android:id="@+id/LinearLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintBottom_toBottomOf="parent">
</LinearLayout>

2. Використовуйте FrameLayoutу вашому кореневому макеті

Просто встановіть android:layout_gravity="bottom"у своєму макеті

<LinearLayout
    android:id="@+id/LinearLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:orientation="horizontal">
</LinearLayout>

3. Використовуйте LinearLayoutу кореневому макеті ( android:orientation="vertical")

(1) Встановіть макет android:layout_weight="1"у верхній частині макета

<TextView
    android:id="@+id/TextView"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:text="welcome" />

(2) Встановіть дитину LinearLayoutнаandroid:layout_width="match_parent" android:layout_height="match_parent" android:gravity="bottom"

Основний атрибут - ndroid:gravity="bottom"нехай Дитина перегляне внизу макета.

<LinearLayout
    android:id="@+id/LinearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="bottom"
    android:orientation="horizontal">
</LinearLayout>

4. Використовуйте RelativeLayoutу кореневому макеті

І встановіть, android:layout_alignParentBottom="true"щоб макет був у нижній частині екрана

<LinearLayout
    android:id="@+id/LinearLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:orientation="horizontal">
</LinearLayout>

Вихідні дані

Введіть тут опис зображення


20

Виконуючи елегантне рішення Timores , я виявив, що наступне створює вертикальне заповнення вертикального LinearLayout і горизонтальне заповнення горизонтальним LinearLayout:

<Space
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1" />

@sepehr У випадку, коли ти знайшов, де моє рішення не працює, має бути ще один фактор. Я просто спробував своє рішення в макеті фрагментів, і він також працює там.
stevehs17

ваги підтримуються в лінійних схемах, а @sepehr вони також працюватимуть у фрагментах, заходах, сповіщеннях, діалогах;)
Jan Rabe

16

Вам навіть не потрібно вкладати другий relativeмакет всередині першого. Просто використовуйте android:layout_alignParentBottom="true"в Баттона і EditText .


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

11

Якщо ви не хочете вносити багато змін, то можете просто помістити:

android:layout_weight="1"

для TextView , що має ідентифікатор в якості @+id/TextViewтобто

<TextView android:text="@string/welcome" 
    android:id="@+id/TextView" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:layout_weight="1">
</TextView>

Або додайте навколишній LinearLayout з android: layout_weight = "1" - це також добре працює у ScrollView!
bk138

7

Створюючи і колонтитул, і колонтитул , ось приклад:

Макет XML

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/backgroundcolor"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="40dp"
        android:background="#FF0000">
    </RelativeLayout>

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="40dp"
        android:layout_alignParentBottom="true"
        android:background="#FFFF00">
    </RelativeLayout>

</RelativeLayout>

Знімок екрана

Введіть тут опис зображення


4

Використовуйте наведений нижче код. Вирівняйте кнопку вгору. Це працює.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn_back"
        android:layout_width="100dp"
        android:layout_height="80dp"
        android:text="Back" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.97"
        android:gravity="center"
        android:text="Payment Page" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Submit"/>
    </LinearLayout>

</LinearLayout>

3

Для такого випадку завжди використовуйте RelativeLayouts. LinearLayout не призначений для такого використання.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/db1_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <!-- Place your layout here -->

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_gravity="bottom"
        android:orientation="horizontal"
        android:paddingLeft="20dp"
        android:paddingRight="20dp" >

        <Button
            android:id="@+id/setup_macroSavebtn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Save" />

        <Button
            android:id="@+id/setup_macroCancelbtn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Cancel" />

        </LinearLayout>

</RelativeLayout>

2

Використовуйте android:layout_alignParentBottom="true" у своєму <RelativeLayout>.

Це, безумовно, допоможе.


1
Це передбачає, що користувач хоче використовувати RelativeLayout.
ІгорГанапольський

2

Якщо у вас є така ієрархія:

<ScrollView> 
  |-- <RelativeLayout> 
    |-- <LinearLayout>

Спочатку зверніться android:fillViewport="true"до, ScrollViewа потім застосуйте android:layout_alignParentBottom="true"до LinearLayout.

Це працювало для мене чудово.

<ScrollView
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:scrollbars="none"
    android:fillViewport="true">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:id="@+id/linearLayoutHorizontal"
            android:layout_alignParentBottom="true">
        </LinearLayout>
    </RelativeLayout>
</ScrollView>

2

Ви можете просто дати свій вид зверху дитини (в TextView @ + код / TextView ) атрибут: android:layout_weight="1".

Це змусить усі інші елементи під ним на дно.


2

Це можна зробити і за лінійною схемою.

Просто введіть висоту = 0dp і вага = 1 для макету вгорі і того, який ви хочете внизу. Просто напишіть висоту = обернути вміст і без ваги.

Він надає вміст обгортання для макета (той, який містить текст та кнопку редагування), а той, який має вагу, займає решту макета.

Я виявив це випадково.


0

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

ScrollView буде частково прихованим у міру зростання вмісту. Використання android:paddingBottomв останньому перегляді допомагає показувати весь вміст ScrollView.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.