如何将视图对齐到屏幕底部?

674

这是我的布局代码:

<?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 画画吧 ;) 不过我正在使用模拟器上的皮肤,这得感谢 Tea Vui Huang http://teavuihuang.com/android/。 - gav
19
感谢您发布解决问题的布局XML,这帮助我找出了我的错误。+1(表示点赞或支持)。 - Howler
18个回答

548

现代的方法是使用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将其余布局定位在视图上方。这使得底部视图可以占用所需的所有空间,而其余布局可以填充屏幕的所有剩余空间。


6
FYI:在ScrollView中这样做行不通。这是我现在面临的问题。请参阅https://dev59.com/HnA75IYBdhLWcg3wv77A。 - IgorGanapolsky
6
这是正确的,ScrollView和RelativeLayout混合使用效果不佳。如果您要显示太多内容而无法在一页上全部显示,请使用LinearLayout,并将底部视图放在最后。如果您希望该视图在小屏幕上出现在ScrollView的最后,在大屏幕手机上出现在页面底部,请考虑使用不同的布局文件,并使用资源限定符让设备选择正确的布局文件。 - Janusz
1
我在《Android Weekly》中读到,RelativeLayout占用内存较多,应尽可能避免使用。 - Tomasz Mularczyk
相对布局是这种情况下的最佳选择。 - Habel Philip
我的解决方案中没有关于按钮对齐的属性可用:在包“com.XXX”中未找到属性“layout_constraintBottom_toBottomOf”的资源标识符。XXX C:\projects\erp\XXX\Resources\layout\layout_test.axml - Windgate
显示剩余3条评论

164
在一个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
我在我的应用程序中使用了你们的解决方案,但在我的情况下,当键盘出现时,我希望按钮保持在屏幕底部(键盘后面)。有解决方法吗?谢谢。 - Yoann
1
@DoubleYo:在 Android 的清单文件中,android:windowSoftInputMode="adjustPan"。 - nspo
2
如果您想要底部固定,使其始终显示,那么这种方法不起作用。否则它是有效的。 - basickarl

75

你可以通过将相对布局嵌套在线性布局中来保留最初的线性布局:

<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的背景或者想要使任何视图变大或添加视图,这种设计就不起作用了。 - Patrick

46

上面的回答(由Janusz提供)是相当正确的,但我个人对RelativeLayout不是100%舒适,因此我更喜欢引入一个“填充器”,即空TextView,就像这样:

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

在应该位于屏幕底部的元素之前。


这会扩展到x轴或y轴吗?将高度设置为0dip会使TextView没有任何高度吗?还是会像x轴一样尽可能地扩展? - Lukap
这会垂直扩展,因为高度(垂直轴)设置为0,权重设置为1(假设其他元素的权重为零)。 - Timores
在x轴上,它将与其父级相同(fill_parent)。 - Timores
我会使用另一个线性布局而不是TextView。布局视图似乎意味着它可以用来填充空间? - ComeIn

41

你也可以使用LinearLayout或ScrollView来实现这个效果。有时它比RelativeLayout更容易实现。你需要做的唯一一件事就是在你想要对齐到屏幕底部的视图之前添加以下视图:

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

这将创建一个空视图,填充空白空间并将下一个视图推到屏幕底部。


1
这个概念与@Timores先前所说的"填充器"类似。 - gumuruh
这就是我几个小时以来一直在寻找的。谢谢! - ng-User

34

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"

主要属性是android: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>

输出

在此输入图片描述


这里展示了一张图片,点击链接可以查看更多信息。

29

这个也可以工作。

<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
除非该LinearLayout嵌套在RelativeLayout中,否则android:layout_alignParentBottom="true"不会生效。 - Thomas Dignan
需要进行解释(例如,基本变化,它是如何工作的,为什么它能够工作等)。 - Peter Mortensen

24

在跟进Timores的优秀解决方案后,我发现以下代码可以使一个垂直的LinearLayout填满垂直方向,一个水平的LinearLayout填满水平方向:

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

@sepehr 在你发现我的解决方案不起作用的情况下,必须还有另一个因素在起作用。我刚刚在段落布局中尝试了我的解决方案,它也可以正常工作。 - stevehs17
权重在线性布局中得到支持,@sepehr 它们也将在片段、活动、通知和对话框中起作用 ;) - Jan Rabe
这个方法可行!多么简单的解决方案。 - Asim

20

你甚至不需要将第二个 relative 布局套在第一个布局里面。只需在 ButtonEditText 中使用 android:layout_alignParentBottom="true" 即可。


请注意,尽管此方法适用于Button和EditText,但如果您尝试以此方式对齐TableLayout,则无法正常工作。您需要将其嵌套在另一个RelativeLayout中。 - user4903

12

如果您不想做出太多更改,那么您可以直接输入:

android:layout_weight="1"

对于具有ID @+id/TextView 的 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>

或者在外面加一个android:layout_weight="1"的LinearLayout - 这也可以在ScrollView中很好地工作! - bk138

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接