除了我们讲的ConstraintLayout和RelativeLayout,还有很多其它的Layout控件,实际上这两个是最复杂的,所以现在再学其它的Layout就感觉到很easy了。
FrameLayout
FrameLayout是最简单的一种Layout,既然是个Layout,它当然可以容纳多个View。但是它并没有一定的规则去排列多个View,而只是简单的把它们堆叠在一起,后添加的会盖住先添加的。
上一节我们添加了一个Layout资源(fragme_test_layout.xml),其根控件是FrameLayout,我们直接用它来玩一下吧。双击打开文件frame_test_layout.xml,向里面添加View,你会发现它们都堆在了一起:
FrameLayout一般用于整个页面只有一个子控件的场景或用于实现翻页效果的场景。
LinearLayout
这种Layout也比较简单,它里面的子控件是依次排列的,有横向和纵向之分。请像上一节一样,创建一个新的layout文件,其根元素为LinearLayout:
可以看到这个LinearLayout的是一个纵向的(vertical):
这个Layout的宽和高都是“match_parent”,也就是充满了整个容器的空间(这里是预览,可以看到它充满了除工具栏之外的整个屏幕的)。向这个Layout里面拖入一些View玩玩吧:
可以看到按钮们都依次纵向排列。
纵向LinearLayout中子控件横向居中
现在我们把Button们的layout_width改为wrap_content,出现如图效果:
但Button全部靠左了,强迫症肯定希望这些按钮都居中,我们就满足他们吧。要使LinearLayout中的子控件横向居中,有两种方式,一是设置LinearLayout的gravity属性,如图:
二是设置子控件本身的属性:layout_gravity(重心),如下图所示:
可以设置控件在layout中靠上靠下靠左靠右还是居中。我们选则横向居中(center_horizontal)。注意纵向居中此时没意义,选了也不起作用。
Gravity属性表示控件的内容的重心在哪里,即内容在控件内如何对齐;layout_gravity表示控件在父控件中如何对齐,但并不是任何类型的父控件都支持。设置layout_gravity的话可以单独控制每个控件在其父控件中的对齐方式。这两个随便选择一种方式吧,因为所有控件都居中,选择设置LinearLayout的gravity更省事。设置后,效果如下:
子控件均匀分布
虽然上一节使按钮们都居中了,但是对要强迫症来说还不能满足,他们可能希望这些按钮们能在纵向空间上均匀分布。此时依然不能再指望LinearLayout有设置子控件分布模式的属性了,得研究子控件。子控件有个叫layout_weight(比重)的属性,用于设置子控件在LinearLayout中在纵向或横向空间上所占的比重,要想让它正确的起作用,需要将子控件的layout_width(在横向LinearLayout中时)或layout_height(在纵向LinearLayout中时)设置为“0dp”!。要均匀分布,就需要为各子控件设置相同的layout_weight值,都设为1吧,效果变成了这样:
子控件按比例分布
上一节讲到了比重,我们用它来玩一下非均匀分布吧,我们把第一个按钮的layout_weight设为1,其余的都设为2,看看有什么效果:
所有按钮按比例分配了整个纵向空间,第一个按钮与其余按钮之间的高度比例为1:2,如果你不想让子控件的layout_height为“0dp”,而为一个固定的值或为wrap_content,那么你需要把它的layout_weight去掉。比如我们想让第一个Button和最后一个Button的高度都为固定值,其余的都按比例充满剩余的空间,效果如图:
现在,整个linear_layout_test文件的源码如下:
<?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:gravity="center_horizontal"
android:orientation="vertical">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:text="Button" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:text="Button" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:text="Button" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:text="Button" />
</LinearLayout>
用LinearLayout实现登录界面
观察一下前面登录界面的例子,你可以发现各控件都是纵向排列的,完全可以用LinearLayout代替RelativeLayout来实现。但如果一个界面需要多个LinearLayout组合才能实现的话,我们就应该用RelativeLayout或ConstraintLayout来实现,虽然RelativeLayout或ConstraintLayout看起来比较复杂,但对于复杂的排版,它们的处理速度更快。但我们这个登录界面不是很复杂的界面类型,所以它也适合以LinearLayout来实现。下面我们就来搞一下。
我们再创建一个Layout文件,其根元素为ScrollView(使用ScrollView是为了适应横屏显示不了整个登录内容的情况):
点“OK”,创建出layout文件,向其中拖入一个纵向的LinearLayout,再依次向LinearLayout中拖入 ImageView,Plain Text EditText,Password EditText,Button。拖入ImageView时选择要显示的头像为Drawable下的一个图像,我选择了female;修改各EditText控件的hint,把各EditText的text清空,修改Button的text,将ImageView的宽和高都置为“100dp”,把各EditText和按钮的宽都改为“300dp”,现在各控件的id倒是不重要了,因为它们之间不需要设置相对位置关系。现在看起来界面是这样的:
设置LinearLayout的gravity,使子控件们横向居中(center_horizontal),于是,linear_layout_login.xml的代码是这样的:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/imageView3"
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/female" />
<EditText
android:id="@+id/editText"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:ems="10"
android:hint="请输入用户名"
android:inputType="textPersonName" />
<EditText
android:id="@+id/editText2"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:ems="10"
android:hint="请输入密码"
android:inputType="textPassword" />
<Button
android:id="@+id/button6"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:text="登录" />
</LinearLayout>
</ScrollView>
完成收功!
GridLayout
Grid是网格的意思,就是把显示区分成n行n列,每列的宽度都一样,主要用于显示表格式的排版。一个View放在此种layout中,需要设置View的layout_row和layout_column来决定View处于第几行第几列。
我创建一个新的layout资源:gridlayout_test.xml,设置其根View为GridLayout。
下面是个示例图:
这个控件对于鼠标拖放的支持不是很好,所以子控件的位置应手动去编辑。子控件的主要相关属性有layout_row(在第几行,从0开始)、layout_column(在第几列,从0开始)和layout_columnSpan(跨几列)、layout_rowSpan(跨几行)。
TableLayout
TableLayout与GridLayout有些类似,也是可以分成多行多列,但它的各行之间的独立的,每一行的列数可以不同,比如一行是三列,而另一行是五列。此Layout的每一行是一个单独的Layout:TableRow,所以要添加一行,需要先添加一个TableRow,然后再向这一行中添加View,如下图:
其实这个效果可以用一个纵向的LinearLayout和多个横向的LinearLayout模拟出来,一个横向的LinearLayout就是一行,但其执行效率不如TableLayout+TableRow高。
(摘自《Android9编程通俗演义》-清华大学出版社,京东淘宝及各大书店有售)