Android应用界面布局

Posted createchance

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android应用界面布局相关的知识,希望对你有一定的参考价值。

android的应用编写基本都会有一个界面,而Android应用的编写逻辑是遵循MVC模式的,它将界面和控制逻辑是分开的,这样一来,界面编写就和应用的业务逻辑是分开的,更改系统业务逻辑也无需改变前台界面,增强了应用的可维护性,降低长期开发成本。
在Android系统中,应用程序的界面是通过一系列的布局文件实现的。这些布局文件使用XML语法编写,使用标签中的属性指定界面上的视图控件本身的属性和控件之间的关系属性。
Android系统提供了几个非常灵活的布局,但是日常开发中我们最常使用的也就是其中的几种。本文我们重点介绍在Android应用开发中使用频率很高的四种布局:线性布局,相对布局,帧布局,百分比布局。所谓这些布局,其实就是定义了它内部的视图控件的位置怎么排放,约束关系等等。我们可以布局看成是一个盒子,然后我们的button,edittext等控件就是需要放到这些盒子中的物件,同时布局的内部也可以存放其他的布局,也就是说,大盒子的内部可以是小的物件,也可以是小的盒子。
需要强调两点,第一点,在Android应用开发中,布局XML文件不是必须存在的,我们完全可以在java代码中使用代码来构建我们的布局,但是这样的话我们的代码会变得丑陋无比,后期无法维护。这并不是说在代码中控制界面不可取,正确的做法是大部分的布局我们使用xml文件构建,只是在某些特殊的情况我们需要使用代码来控制添加或者删除某些界面上的控件。第二点就是,Android官方提供的android studio工具中的视图化的界面编辑非常方便,但是大家千万不要直接使用这个工具编辑界面,因为在这个界面上妥妥拽拽不能做到精细化设计界面,我们还是需要手动编辑文本,然后使用这个工具进行效果预览就可以了。

线性布局LinearLayout

顾名思义,线性布局的意思就是它内部的控件的位置排列是线性的,要么垂直,要么水平。我们先看一个例子:
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.createchance.uilayouttest.MainActivity">

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

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

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

这个布局的效果如下图:

这里,我们看到默认的控件位置是水平排放的。我们可以使用android:orientation属性来指定这个线性的水平布局,可以选择的参数是:horizontal(水平,默认值)和vertical(垂直),当我们在LinearLayout标签下增加了android:orientation=”vertical”之后布局就成了下面这样:

按照标准来说,每一个控件都应该使用android:layout_width和android:layout_height字段来描述这个控件的宽和高信息,如果没有的话编译会报错(后面我们会看到在百分比布局中,控件可以没有这两个属性)。在线性布局中需要注意的一点就是,如果排列方向是horizontal的话,那么内部的控件的宽度就不能指定为match_parent(铺满父窗口),因为如果指定的话就会是下面这个效果:

你会奇怪,怎么第二个和第三个button不见了?是的,他们被button 1挤出去了,你看不见他们了。因为你的button 1的宽度是match_parent,因此它霸占了整个宽度,第二个和第三个button没有地方待了!同理,如果你的布局方向是vertical的话,那么内部的控件的高度就不能是match_parent。
在线性布局中,我们需要注意的一个属性就是android:layout_gravity,这个属性和android:gravity属性看起来有些类似,但是他们之间是有很大的区别的。android:layout_gravity用于制定控件在布局中的对齐方式,而android:gravity用于执行文字或者内容在控件本身中的对齐位置。android:layout_gravity和android:gravity可选值是类似的,但是需要注意的是,当布局的方向是horizontal的时候,只有垂直方向的对齐才是有效的,因为这个时候水平方向的长度是不确定的,如果你新添加一个控件的话水平长度就发生变化了。同理,如果你的布局方向是垂直的,那么只有水平方向的对齐才有效。我们将刚才界面上的三个按钮错开排放:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.createchance.uilayouttest.MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:text="Button 1"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Button 2"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:text="Button 3"/>
</LinearLayout>

效果如下:

这里的布局方向是垂直的。
下面,我们介绍另外一个在线性布局中非常重要的属性:android:layout_weight。这个属性可以让我们指定控件在这个布局的某个方向上的占用位置的比重。比如我们想让上面的三个按钮在垂直方向上,均分屏幕高度,我们可以这样:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.createchance.uilayouttest.MainActivity">

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

    <Button
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="Button 2"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="Button 3"/>
</LinearLayout>

效果如下:

如果我们让三个按钮按照1:2:3的比例分配屏幕高度,我们可以这样:

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

    <Button
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:text="Button 2"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="3"
        android:text="Button 3"/>

效果如下:

可以看到,android:layout_weight的作用就是制定某个控件的占屏比,计算方式就是讲所有的控件的这个属性的值相加,然后讲控件的值除以这个和得出的比值就是占用屏幕的比值。需要说明的是,这里的android:layout_height=”0dp”并不是说这个控件的高度就是0dp,而是说当前的这个属性不指定控件高度,高度有weight属性制定的权重分配,这里的0dp是标准的写法。
有关线性布局中的xml属性参数,可以参考官方文档:https://developer.android.com/reference/android/widget/LinearLayout.html

相对布局RelativeLayout

相对布局也是一种非常常用的界面布局,和线性布局不同的是,这个布局中的控件位置相对随意自由一些。他可以通过相对位置的方式来制定控件的位置,某个控件的位置可以相对于界面边框或者其他的控件而言。正是由于这个原因,相对布局中的属性非常多,但是不用担心,这些属性的命名非常友好,你一眼就能记住并且理解他们的意思。
下面我们给出一个例子:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.createchance.uilayouttest.MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 1"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 2"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 3"
        android:layout_centerInParent="true"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 4"
        android:layout_alignParentLeft="true"
        android:layout_alignParentBottom="true"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 5"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"/>

</RelativeLayout>

效果如下:

上面的布局代码,我想不解释大家都能看明白吧,属性的命名非常简单易懂。
上面的例子给出的控件相对参照物是布局的边界,同样地,我们也就将这个参照物制定未其中的某一个控件,比如我们这里将这个参照物指定未button 3:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.createchance.uilayouttest.MainActivity">

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 3"
        android:layout_centerInParent="true"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 1"
        android:layout_above="@id/button3"
        android:layout_toLeftOf="@id/button3"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 2"
        android:layout_above="@id/button3"
        android:layout_toRightOf="@id/button3"/>


    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 4"
        android:layout_below="@id/button3"
        android:layout_toLeftOf="@id/button3"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 5"
        android:layout_below="@id/button3"
        android:layout_toRightOf="@id/button3"/>

</RelativeLayout>

效果如下:

这里需要注意,因为我们将button 3作为其他控件的参照物,因此我们需要做到两件事情:
1. 首先定义button 3,并且给button 3指定一个id,指定参照物的时候需要使用
2. 为了使得我们的界面在任何的手机上都能看起来一致,我们需要将屏幕中参照物相对屏幕的位置固定住,这里button 3的位置仍然是在父布局中水平垂直居中。因为这个参照物固定了,其他参考他的控件位置也就固定了。
相对布局中的xml参数有很多,我们只要理解了相对布局是什么就行,至于全部的参数可以参考官方文档,到时候查阅就可以:https://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams.html

帧布局FrameLayout

帧布局相对于前两种布局就简单多了,因此他的使用场景也比较少。这种布局没有灵活的定位方式,所有的控件默认都是放在屏幕的左上角。我们看一个例子:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.createchance.uilayouttest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is a string: hello world." />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button 2" />

</FrameLayout>

效果如下:

可以看到,上图中的后定义的button将textview遮挡住了,这是因为帧布局中所有的控件默认都是左上角放置的。但是,我们仍然可以通过android:layout_gravity属性来指定控件的位置:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.createchance.uilayouttest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is a string: hello world." />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:text="button 2" />

</FrameLayout>

效果如下:

在实际的开发中,我们直接使用帧布局来构建界面的情况不是很多,更多的情况是我们使用这个布局和Fragment配合使用。

百分比布局Percent Layout

前面我们讲述了常用的三种布局,这些布局从Android的第一个正式版本1.0中就开始提供了,并且到现在一直在使用。但是这里面有一个问题,那就是我们在线性布局中可以使用android:layout_weight属性来指定控件占用屏幕的比例大小,但是在剩下的两个布局中我们做不到这一点。比如说,我们想在相对布局中实现让两个按钮平分布局高度的效果,就是比较困难的。这个问题,Android开发团队肯定意识到了,并且及时提供了一种新型的界面布局:百分比布局。这种布局中我们不在需要使用wrap_content, match_parent等方式来指定控件的大小了,而是直接指定控件在布局中占用的百分比,使用十分方便。
由于线性布局本身就可以使用android:layout_weight来实现这样的效果,因此Android只是提供了帧布局和相对布局的功能进行了扩展,提供了PercentFrameLayout和PercentRelativeLayout两种布局。这些布局的实现并不是在framework中的是,而是在Android的support包中的,以便提供不同版本Android系统的兼容性。因此我们需要在android studio中的build.gradle中添加百分比布局的依赖库:

dependencies 
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', 
        exclude group: 'com.android.support', module: 'support-annotations'
    )
    compile 'com.android.support:appcompat-v7:23.4.0'
    // 添加百分比布局依赖库
    compile 'com.android.support:percent:23.0.0'
    testCompile 'junit:junit:4.12'

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentFrameLayout
    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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.createchance.uilayouttest.MainActivity">

    <Button
        app:layout_widthPercent="50%"
        app:layout_heightPercent="50%"
        android:layout_gravity="top|left"
        android:text="button 1" />

    <Button
        app:layout_widthPercent="50%"
        app:layout_heightPercent="50%"
        android:layout_gravity="top|right"
        android:text="button 2" />

    <Button
        app:layout_widthPercent="50%"
        app:layout_heightPercent="50%"
        android:layout_gravity="bottom|left"
        android:text="button 3" />

    <Button
        app:layout_widthPercent="50%"
        app:layout_heightPercent="50%"
        android:layout_gravity="bottom|right"
        android:text="button 4" />

</android.support.percent.PercentFrameLayout>

效果如下:

看到了没?我们很轻松地实现了四个按钮将整个布局平分了!这里需要注意的是,在布局文件中的根标签需要讲百分比布局全部名称写上,因为整个布局是实现在支持包中的。另外需要注意的是,我们需要定义个app的xml命名空间,这样下面我们就可以使用app:layout_widthPercent这样的属性了。
最后,说明一下,如果你的android studio是低于2.2版本的话,那么可能会出现错误:提示说控件没有给出宽和高的定义,这是因为原先系统默认的是每一个控件必须提供宽和高的定义,但是百分比布局出现之后,这个定义可以由app:layout_widthPercent等属性来给出。这个时候你直接忽略这些错误提示即可。

以上是关于Android应用界面布局的主要内容,如果未能解决你的问题,请参考以下文章

Android_Layout

Android应用界面布局

Android应用开发技术:用户界面布局管理器

Android Studio入门:Android应用界面详解(上)(View布局管理器)

Android相对布局

安卓应用的界面编程