Как выровнять виды внизу экрана?

636

Вот мой код компоновки;

<?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 по высоте, но это не оставляет места для кнопки или поля ввода.

По сути, проблема в том, что я хочу, чтобы кнопка отправки и текстовая запись были фиксированной высоты внизу, а текстовое представление заполняло оставшееся пространство. Аналогично, в горизонтальном линейном макете я хочу, чтобы кнопка отправки обернула свое содержимое, а текстовая запись заполнила оставшееся пространство.

Если первый элемент в линейном макете сообщается 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
Гав
14
+1 за размещение макета XML, который решил это. Помог мне понять, что случилось с моим.
Howler

Ответы:

527

Современный способ сделать это - использовать 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
К вашему сведению: это не будет работать внутри ScrollView. Это проблема, с которой я сталкиваюсь сейчас. См stackoverflow.com/questions/3126347/...
IgorGanapolsky
6
Это верно, ScrollViews и Relative Layouts не очень хорошо сочетаются. Если вам нужно много контента, чтобы отобразить все на одной странице, просто используйте линейное расположение и поместите в нижний вид в последнюю очередь. Если вы хотите, чтобы представление отображалось последним в представлении прокрутки на небольших экранах и в нижней части страницы на более крупных телефонах, рассмотрите возможность использования различных файлов макетов и использования классификаторов ресурсов, чтобы устройство могло выбрать правильный файл макета.
Януш
хорошо .. какой смысл второго абзаца ответа здесь? «Вы должны найти макет, который сначала покрывает нижнюю часть экрана»? тогда мы должны использовать layout_alignParentBottom внутри макета? Для чего нам нужно android:layout_above?
Евгений
Вы должны выше, если вы хотите что-то вроде полосы в нижней части, а затем LinearLayout над этой полосой, которая простирается от верхней части экрана до полосы.
Януш
1
Я прочитал в одном из «Android Weekly», что that RelativeLayoutзанимает много памяти и его следует избегать, когда это возможно.
Томаш Муларчик
153

В a 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. Я бы дал больше одного голоса, если бы мог!
мужчина
4
Я использую ваше решение в своем приложении, но в моем случае я хочу, чтобы при появлении клавиатуры кнопки оставались в нижней части экрана (за клавиатурой). Для этого есть какое-то решение? Thaks.
Йоанн
1
@DoubleYo: в манифесте Android: windowSoftInputMode = "AdjustPan"
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>
pseudosudo
источник
2
Это грязный подход, поскольку он не очень модульный. Вы не должны иметь перекрывающихся макетов. Этот дизайн не будет работать, как только вы захотите изменить фон RelativeLayout или захотите увеличить любой из видов или добавить их.
Патрик
42

Ответ выше (автор Janusz) вполне корректен, но лично я не чувствую себя на 100% комфортно с RelativeLayouts, поэтому я предпочитаю ввести «заполнитель», пустой TextView, например:

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

перед элементом, который должен быть в нижней части экрана.

Timores
источник
Это расширится до оси X или Y. Задание 0dip для высоты сделает текстовое представление без какой-либо высоты? или будет расширяться настолько, насколько это возможно, просто как на оси х?
Лукап
Это расширяется по вертикали, потому что высота (вертикальная ось) установлена ​​в 0, а вес в 1 (при условии, что другие элементы имеют нулевой вес).
Тимор
На оси х он будет в качестве своего родителя (fill_parent)
Тимор,
Вместо просмотра текста я бы использовал другой линейный макет. Вид компоновки предполагает, что он может быть использован для заполнения пространства?
ComeIn
33

Вы также можете сделать это с помощью LinearLayout или ScrollView. Иногда это легче реализовать, чем RelativeLayout. Единственное, что вам нужно сделать, это добавить следующий вид перед представлениями, которые вы хотите выровнять по нижней части экрана:

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

Это создает пустое представление, заполняя пустое пространство и выдвигая следующие представления внизу экрана.

keybee
источник
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 = "bottom" для перемещения элементов 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", пусть дочерний View в нижней части Layout.

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

Вывод

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

KeLiuyue
источник
20

Следуя элегантному решению Тимора , я обнаружил, что следующее создает вертикальную заливку в вертикальной LinearLayout и горизонтальную заливку в горизонтальной LinearLayout:

<Space
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1" />
stevehs17
источник
@sepehr Должен быть другой фактор в случае, если вы обнаружили, что мое решение не работает. Я только что попробовал свое решение в макете фрагмента, и оно работает там же.
stevehs17
веса поддерживаются в линейных макетах и ​​@sepehr, они также будут работать во фрагментах, действиях, уведомлениях, диалогах;)
Jan Rabe
16

Вам даже не нужно вкладывать второй relativeмакет в первый. Просто используйте android:layout_alignParentBottom="true"в кнопку и EditText .

Стив Хейли
источник
Просто обратите внимание, что хотя это работает с Button и EditText, если вы попытаетесь выровнять TableLayout таким образом, он не будет работать. Вы должны будете вложить его в другой RelativeLayout.
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>
sharma_kunal
источник
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>.

Это определенно поможет.

Jigar
источник
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".

Это заставит все остальные элементы под ним снизу.

IgorGanapolsky
источник
2

Это также можно сделать с помощью линейного макета.

Просто укажите Height = 0dp и weight = 1 для макета выше и тот, который вы хотите внизу. Просто напишите высоту = оберните содержимое и не вес.

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

Я обнаружил это случайно.

Райхан Ахмед
источник
0

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

ScrollView будет частично скрыт по мере роста с содержанием. Использование android:paddingBottomв последнем представлении помогает показать весь контент в ScrollView.

jeremyvillalobos
источник