这篇就对LinearLayout、RelativeLayout、自定义ViewGroup、FrameLayout、TableLayout、AbsoluteLayout六种布局进行详细的讲解。
线性布局,两种排法:
一个竖向的大LinearLayout嵌套着两个小LinearLayout,第一个小LinearLayout为横向,第二个小LinearLayout为竖向。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="horizontal">
<TextView
android:layout_width="96dp"
android:layout_height="match_parent"
android:background="#b2dfdb" />
<TextView
android:layout_width="96dp"
android:layout_height="match_parent"
android:background="#80cbc4" />
<TextView
android:layout_width="96dp"
android:layout_height="match_parent"
android:background="#4db6ac" />
<TextView
android:layout_width="96dp"
android:layout_height="match_parent"
android:background="#26a69a" />
LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="68dp"
android:background="#b2dfdb" />
<TextView
android:layout_width="match_parent"
android:layout_height="68dp"
android:background="#80cbc4" />
<TextView
android:layout_width="match_parent"
android:layout_height="68dp"
android:background="#4db6ac" />
<TextView
android:layout_width="match_parent"
android:layout_height="68dp"
android:background="#26a69a" />
LinearLayout>
LinearLayout>
参考其他控件进行布局,默认为父控件。
有三种类型的属性:
各取一个来写例子,如图。
代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
style="@style/btn_relative"
android:text="1" />
<TextView
style="@style/btn_relative"
android:text="2" />
<TextView
android:id="@+id/txt_center"
style="@style/btn_relative"
android:layout_centerInParent="true"
android:text="3" />
<TextView
style="@style/btn_relative"
android:layout_alignParentBottom="true"
android:text="4" />
<TextView
style="@style/btn_relative"
android:layout_below="@id/txt_center"
android:background="#d0d9ff"
android:text="5" />
<TextView
style="@style/btn_relative"
android:layout_alignBottom="@+id/txt_center"
android:text="6" />
<TextView
style="@style/btn_relative"
android:layout_marginLeft="150dp"
android:text="7" />
<TextView
style="@style/btn_relative"
android:layout_centerVertical="true"
android:layout_marginLeft="100dp"
android:layout_toRightOf="@id/txt_center"
android:text="8" />
RelativeLayout>
自定义布局主要是重写两个方法:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式
*/
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
// 计算出所有的childView的宽和高
measureChildren(widthMeasureSpec, heightMeasureSpec);
/**
* width和height是当wrap_content时使用的属性。
*/
int width = 0;
int height = 0;
int cCount = getChildCount();
int cWidth = 0;
int cHeight = 0;
/**
* 在这里计算当wrap_content时,布局的大小。
*/
for (int i = 0; i < cCount; i++) {
View childView = getChildAt(i);
cWidth = childView.getMeasuredWidth();
cHeight = childView.getMeasuredHeight();
width += cWidth;
height += cHeight;
}
/**
* 如果是wrap_content设置为我们计算的值
* 否则:直接设置为父容器计算的值
*/
setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth
: width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight
: height);
}
首先要说一下布局计算模式,即最后的EXACTLY。一共有三种计算模式:
最后的设定大小时,如果是精确尺寸就是用sizeWidth即获取的尺寸,如果是最大尺寸就是要我们自己计算的那个尺寸了。
onMeasure()最主要的功能就是计算wrap_content的尺寸和设置尺寸。
我将这个方法称为“建画布”,先建了画布才能在上面绘图嘛。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int cCount = getChildCount();
/**
* 遍历所有childView根据其宽和高,以及margin进行布局
*/
for (int i = 0; i < cCount; i++) {
View childView = getChildAt(i);
r = l + childView.getMeasuredWidth();
b = t + childView.getMeasuredHeight();
childView.layout(l, t, r, b);
l += childView.getMeasuredWidth();
t += childView.getMeasuredHeight();
}
}
这个方法的作用是设置摆放子元素的位置。其中onLayout()传入的l、t、r、b分别是这样
并且可以使用childview.getMeasuredWidth()和childView.getMeasureHeight()得到子元素的宽和高。
这样就可以来对每个子元素进行布局了。
我称这个方法为“定位置”。定完位置后那么子元素就被放到了我们想要的地方。
这样一个自定义ViewGroup就可以使用了。
xml文件如下:
<com.example.layoutdemo.MyLayout.MyLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#b2dfdb" />
<TextView
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#80cbc4" />
<TextView
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#4db6ac" />
<TextView
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#26a69a" />
com.example.layoutdemo.MyLayout.MyLayout>
帧布局,这个布局的特点是从左上角开始,后面的会覆盖前面的控件。
代码如下:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="100dp"
android:textColor="#9c27b0"
android:text="第一层"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="80dp"
android:textColor="#e91e63"
android:text="第二层"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="60dp"
android:textColor="#e51c23"
android:text="第三层"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="40dp"
android:textColor="#5677fc"
android:text="第四层"/>
FrameLayout>
表格布局。
它遵循着以下结构:
<TableLayout>
<TableRow>
<!-在这里填充第一行的元素->
TableRow>
<TableRow>
<!-在这里填充第二行的元素->
TableRow>
TableLayout>
还有几个重要属性:
代码如下:
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:collapseColumns="2"
android:shrinkColumns="1"
android:stretchColumns="0">
<TableRow
>
<TextView android:text="我是伸展的第一列" />
<TextView android:text="我是收缩的第二列" />
<TextView android:text="我被隐藏了" />
TableRow>
<TableRow>
<TextView android:text="我可以伸展的很长很长很长长" />
<TextView android:text="我可以收缩,我可以变的很深很深很深" />
<TextView android:text="我被隐藏了T_T" />
TableRow>
<TableRow>
<TextView
android:layout_column="1"
android:text="我要在第2列" />
TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_span="2"
android:text="我要 跨 两 列" />
TableRow>
TableLayout>
绝对布局,极力不推荐,官方已经舍弃。
定义两个控件左上角坐标轴
即android:layout_x 和android:layout_y来控制位置。
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
style="@style/btn_relative"
android:text="1" />
<TextView
style="@style/btn_relative"
android:layout_x="60dp"
android:layout_y="60dp"
android:text="1" />
<TextView
style="@style/btn_relative"
android:layout_x="160dp"
android:layout_y="160dp"
android:text="1" />
<TextView
style="@style/btn_relative"
android:layout_x="260dp"
android:layout_y="260dp"
android:text="1" />
AbsoluteLayout>
源码下载地址:LayoutDemo