Jak wyrównać widoki u dołu ekranu?

634

Oto mój kod układu;

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

To, jak to wygląda, znajduje się po lewej stronie, a to, co chcę, aby wyglądało, jest po prawej stronie.

Układ Androida - rzeczywisty (lewy) i pożądany (prawy)

Oczywistą odpowiedzią jest ustawienie TextView na fill_parent na wysokości, ale nie powoduje to pozostawienia miejsca dla przycisku lub pola wprowadzania.

Zasadniczo problem polega na tym, że chcę, aby przycisk wysyłania i wpis tekstu miały stałą wysokość u dołu, a widok tekstu wypełniał resztę miejsca. Podobnie w poziomym układzie liniowym chcę, aby przycisk wysyłania zawinął jego zawartość i aby wpis tekstu wypełnił resztę miejsca.

Jeśli polecenie pierwszemu elementowi w układzie liniowym zostanie wypełnione, to robi to dokładnie, nie pozostawiając miejsca na inne elementy. Jak uzyskać element, który jako pierwszy ma układ liniowy, aby wypełnić całą przestrzeń oprócz minimum wymaganego przez pozostałe elementy w układzie?


Względne układy były rzeczywiście odpowiedzią:

    <?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>
gav
źródło
7
@oneself farbą;) Używam skórę na emulatorze chociaż uprzejmości Tea VUI Huang teavuihuang.com/android
GAV
14
+1 za opublikowanie układu XML, który go rozwiązał. Pomógł mi zrozumieć, co było nie tak z moim.
Wyjec

Odpowiedzi:

526

Współczesnym sposobem na to jest ConstraintLayout i ograniczenie dolnej części widoku do dolnej części ConstraintLayout za pomocąapp:layout_constraintBottom_toBottomOf="parent"

Poniższy przykład tworzy FloatingActionButton, który zostanie wyrównany do końca i dołu ekranu.

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

Dla porównania zachowam moją starą odpowiedź.

Przed wprowadzeniem ConstraintLayout odpowiedzią był układ względny .


Jeśli masz względny układ, który wypełnia cały ekran, powinieneś być w stanie android:layout_alignParentBottomprzenieść przycisk na dół ekranu.

Jeśli twoje widoki u dołu nie są pokazane we względnym układzie, być może układ nad nim zajmuje całą przestrzeń. W takim przypadku możesz umieścić widok, który powinien znajdować się na dole, najpierw w pliku układu i ustawić resztę układu nad widokami za pomocą android:layout_above. Dzięki temu widok z dołu zajmuje tyle miejsca, ile potrzebuje, a reszta układu może wypełnić całą resztę ekranu.

Janusz
źródło
5
FYI: to nie działałoby w ScrollView. To jest problem, z którym się teraz spotykam. Zobacz stackoverflow.com/questions/3126347/…
IgorGanapolsky
6
To jest prawidłowe ScrollViews i Relative Layouts nie mieszają się zbyt dobrze. Jeśli musisz mieć dużo treści, aby wyświetlić wszystko na jednej stronie, po prostu użyj liniowego wyświetlania i umieść na dole widok na końcu. Jeśli chcesz, aby widok pojawiał się jako ostatni w widoku przewijania na małych ekranach i na dole strony w większych telefonach, rozważ użycie różnych plików układu i skorzystaj z kwalifikatorów zasobów, aby pozwolić urządzeniu wybrać odpowiedni plik układu.
Janusz
ok .. jaki jest sens drugiego akapitu odpowiedzi tutaj? „Powinieneś znaleźć układ, który najpierw zakrywa dolną część ekranu”? czy powinniśmy użyć layout_alignParentBottom wewnątrz układu? Czego potrzebujemy android:layout_above?
eugene
Potrzebujesz tego, jeśli chcesz coś w rodzaju paska na dole, a następnie LinearLayout nad tym paskiem, który rozciąga się od góry ekranu do paska.
Janusz
1
Przeczytałem w jednym z „Android Weekly” that RelativeLayoutzajmuje pamięć i należy tego unikać, gdy tylko jest to możliwe.
Tomasz Mularczyk
153

W ScrollViewtym nie działa, ponieważ RelativeLayoutwówczas nakładałyby się na to, co jest ScrollViewna dole strony.

Naprawiłem to za pomocą dynamicznego rozciągania 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>
Bram Avontuur
źródło
1
jest to świetne - jest też „minimalnie inwazyjne” i bardziej intuicyjne niż podejście RelativeLayout. Dałbym więcej niż jeden głos, gdybym mógł!
manmal
4
Korzystam z twojego rozwiązania w mojej aplikacji, ale w moim przypadku chcę, aby po pojawieniu się klawiatury przyciski pozostały na dole ekranu (za klawiaturą). Thaks
Yoann,
1
@DoubleYo: w manifeście android: windowSoftInputMode = "adjustPan"
Kopfgeldjaeger
2
JEŚLI chcesz, aby dno zostało naprawione na stałe, tak więc pokazuje to cały czas, że to nie działa. W przeciwnym razie to działa.
Karl Morrison,
72

Możesz zachować początkowy układ liniowy, zagnieżdżając układ względny w układzie liniowym:

<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
źródło
2
Jest to niechlujne podejście, ponieważ nie jest bardzo modułowe. Nie powinieneś mieć nakładających się układów. Ten projekt nie będzie działać, gdy tylko chcesz zmienić tło RelativeLayout lub chcesz powiększyć widok lub dodać widok.
Patrick,
42

Powyższa odpowiedź (autorstwa Janusza) jest całkiem poprawna, ale osobiście nie czuję się w 100% komfortowo z RelativeLayouts, więc wolę wprowadzić „wypełniacz”, pusty TextView, taki jak ten:

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

przed elementem, który powinien znajdować się na dole ekranu.

Timory
źródło
Czy to rozwinie się do osi x lub y. Podanie 0dip dla wysokości spowoduje, że widok tekstu nie będzie miał żadnej wysokości? czy powiększy się tak bardzo, jak to możliwe, do osi x?
Lukap
Rozwija się on w pionie, ponieważ wysokość (oś pionowa) jest ustawiona na 0, a waga na 1 (przy założeniu, że inne elementy mają zerową wagę).
Timores,
Na osi x będzie on jako jego rodzic (fill_parent)
Timores,
Zamiast widoku tekstu użyłbym innego układu liniowego. Widok układu wydaje się sugerować, że można go użyć do wypełnienia miejsca?
ComeIn
33

Możesz to zrobić również za pomocą LinearLayout lub ScrollView. Czasami jest łatwiejsze do wdrożenia niż RelativeLayout. Jedyne, co musisz zrobić, to dodać następujący widok przed widokami, które chcesz wyrównać do dolnej części ekranu:

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

Tworzy to pusty widok, wypełniając puste miejsce i przesuwając kolejne widoki na dół ekranu.

kluczowiec
źródło
27

To też działa.

<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”, aby przenieść elementy LinearLayout do dołu

Michael Reed
źródło
12
android: layout_alignParentBottom = "true" nie ma żadnego efektu, chyba że LinearLayout jest zagnieżdżony w RelativeLayout.
Thomas Dignan,
Wytłumaczenie byłoby w porządku (np. Zasadnicza zmiana, jak to działa, dlaczego działa itp.).
Peter Mortensen
26

1. Użyj ConstraintLayoutw swoim głównym układzie

I ustaw, app:layout_constraintBottom_toBottomOf="parent"aby układ u dołu ekranu:

<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. Użyj FrameLayoutw swoim głównym układzie

Wystarczy ustawić android:layout_gravity="bottom"w swoim układzie

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

3. Użyj LinearLayoutw swoim głównym układzie ( android:orientation="vertical")

(1) Ustaw układ android:layout_weight="1"na górze układu

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

(2) Ustaw dziecka LinearLayoutdoandroid:layout_width="match_parent" android:layout_height="match_parent" android:gravity="bottom"

Głównym atrybutem jest ndroid:gravity="bottom"pozwól dziecku wyświetlić na dole Układu.

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

4. Użyj RelativeLayoutw układzie głównym

I ustaw, android:layout_alignParentBottom="true"aby układ u dołu ekranu

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

Wynik

Wpisz opis zdjęcia tutaj

KeLiuyue
źródło
20

Kontynuując eleganckie rozwiązanie Timores , stwierdziłem, że następujące tworzy pionowe wypełnienie w pionowym LinearLayout i poziome wypełnienie w poziomym LinearLayout:

<Space
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1" />
stevehs17
źródło
@sepehr W przypadku, gdy moje rozwiązanie nie działa, musi istnieć jeszcze jeden czynnik. Właśnie wypróbowałem moje rozwiązanie w układzie fragmentów i ono również tam działa.
stevehs17,
wagi są obsługiwane w układach liniowych i @sepehr będą działać również we fragmentach, działaniach, powiadomieniach, dialogach;)
Jan Rabe
16

Nie musisz nawet zagnieżdżać drugiego relativeukładu w pierwszym. Po prostu użyj android:layout_alignParentBottom="true"w Button i EditText .

Steve Haley
źródło
Wystarczy pamiętać, że chociaż działa to z Button i EditText, próba wyrównania TableLayout w ten sposób nie działałaby. Będziesz musiał zagnieździć go w innym RelativeLayout.
11

Jeśli nie chcesz wprowadzać wielu zmian, możesz po prostu umieścić:

android:layout_weight="1"

dla TextView o identyfikatorze jako @+id/TextViewnp

<TextView android:text="@string/welcome" 
    android:id="@+id/TextView" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:layout_weight="1">
</TextView>
Kiran Parmar
źródło
Lub dodaj otaczający LinearLayout z Androidem: layout_weight = "1" - działa to również dobrze w ScrollView!
bk138,
7

Tworząc zarówno nagłówek, jak i stopkę , oto przykład:

Układ 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>

Zrzut ekranu

Wpisz opis zdjęcia tutaj

Madan Sapkota
źródło
4

Użyj poniższego kodu. Dopasuj przycisk do przycisku. To działa.

<?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
źródło
3

W takim przypadku zawsze używaj RelativeLayouts. LinearLayout nie jest przeznaczony do takiego użycia.

<?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>
Shubham A.
źródło
2

Użyj android:layout_alignParentBottom="true" w swoim <RelativeLayout>.

To na pewno pomoże.

dżigar
źródło
1
To zakłada, że ​​użytkownik chce użyć RelativeLayout.
IgorGanapolsky
2

W przypadku takiej hierarchii:

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

Najpierw złóż android:fillViewport="true"wniosek, ScrollViewa następnie złóż android:layout_alignParentBottom="true"wniosek LinearLayout.

To działało dla mnie idealnie.

<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>
Książę
źródło
2

Można po prostu dać pogląd top dziecka (na TextView @ + id / TextView ) atrybut: android:layout_weight="1".

To zmusi wszystkie pozostałe elementy pod nim do dołu.

Igor Ganapolski
źródło
2

Można to zrobić również w układzie liniowym.

Podaj wysokość = 0dp i wagę = 1 do powyższego układu i tego, który chcesz na dole. Wystarczy napisać wysokość = zawartość opakowania i bez wagi.

Zapewnia zawartość zawijania dla układu (ten, który zawiera tekst edycji i przycisk), a następnie ten, który ma wagę, zajmuje resztę układu.

Odkryłem to przez przypadek.

Rahhan Ahmed
źródło
0

Użyłem rozwiązania opublikowanego przez Janusza, ale do ostatniego widoku dodałem dopełnienie, ponieważ górną częścią mojego układu był ScrollView.

ScrollView zostanie częściowo ukryty, gdy rośnie wraz z zawartością. Użycie android:paddingBottomostatniego widoku pomaga wyświetlić całą zawartość w ScrollView.

jeremyvillalobos
źródło