Android入門——六大布局詳解
本博文對LinearLayout、RelativeLayout、自定義ViewGroup、FrameLayout、TableLayout、AbsoluteLayout六種佈局進行詳細的講解。
一.LinearLayout佈局
<?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"> <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" android:id="@+id/textView" /> </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佈局
參考其他控制元件進行佈局,預設為父控制元件。
有三種類型的屬性:
屬性值是true或false
android:layout_centerHrizontal 水平居中
android:layout_centerVertical 垂直居中
android:layout_centerInparent 相對於父元素完全居中。
android:layout_alignParentBottom 位於父元素的下邊緣
android:layout_alignParentTop 位於父元素的上邊緣
android:layout_alignParentLeft 位於父元素的左邊緣
android:layout_alignParentRight 位於父元素的右邊緣
屬性值是”@id/*“
android:layout_below 在某元素的下方
android:layout_above 在某元素的上方
andorid:layout_toRightOf 在某元素的右方
android:layout_toLeftOf 在某元素的左方
android:layout_alignBottom 和某元素下方對齊
android:layout_alignTop 和某元素上方對齊
android:layout_alignRight 和某元素右方對齊
android:layout_alignLeft 和某元素左方對齊
屬性值是數值
android:layout_marginLeft 離某元素左邊緣的距離
android:layout_marginRight 離某元素右邊緣的距離
android:layout_marginTop 離某元素上邊緣的距離
android:layout_marginBottom 離某元素下邊緣的距離
下面為舉例:
注意:
如果沒有定義左右,那麼預設在左邊,如果沒有定義上下,預設在上邊。
相同位置,新定義的元素會覆蓋舊的元素。例:2下面其實還有1,但是1被2覆蓋了。
4只定義了在父元素的下部,左右沒有定義,於是預設就在左邊了。
android:layout_below,在某元素的下部並不意味著就一定是緊隨某元素,只是在下部的預設位置。例如:5是在3的下部,但是是在下部的預設左邊。
6為下邊緣對齊3,7為marginLeft=150dp。
8為多個屬性共同定義的結果。首先是在3的右部,然後是垂直居中,然後marginLeft=100dp得到最後位置。<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/button1" android:layout_width="50dp" android:layout_height="50dp" android:textSize="50sp" android:text="1" android:background="#26a69a"/> <TextView android:id="@+id/button2" android:layout_width="50dp" android:layout_height="50dp" android:textSize="50sp" android:text="2" android:background="#26a69a"/> <TextView android:id="@+id/button3" android:layout_width="50dp" android:layout_height="50dp" android:textSize="50sp" android:background="#26a69a" android:text="3" android:layout_centerInParent="true"/> <TextView android:id="@+id/button4" android:layout_width="50dp" android:layout_height="50dp" android:textSize="50sp" android:background="#26a69a" android:text="4" android:layout_alignParentBottom="true"/> <TextView android:id="@+id/button5" android:layout_width="50dp" android:layout_height="50dp" android:textSize="50sp" android:background="#26a69a" android:text="5" android:layout_below="@id/button3"/> <TextView android:id="@+id/button6" android:layout_width="50dp" android:layout_height="50dp" android:textSize="50sp" android:background="#26a69a" android:text="6" android:layout_alignBottom="@+id/button3"/> <TextView android:id="@+id/button7" android:layout_width="50dp" android:layout_height="50dp" android:textSize="50sp" android:background="#26a69a" android:text="7" android:layout_marginLeft="150dp"/> <TextView android:id="@+id/button8" android:layout_width="50dp" android:layout_height="50dp" android:textSize="50sp" android:background="#26a69a" android:text="8" android:layout_centerVertical="true" android:layout_marginLeft="100dp" android:layout_toRightOf="@id/button3"/> </RelativeLayout>
三.MyLayout佈局(自定義ViewGroup)
自定義佈局主要是重寫兩個方法:
- onMeasure() 這個是寫自定義容器的大小。
- onLayout() 這個是寫子元素的佈局。
我自己寫了一個自定義佈局,是順序填充會延對角線進行排列。
onLayout()方法的作用是設定擺放子元素的位置。其中onLayout()傳入的l、t、r、b分別是這樣
l,t分別對應子元素左上角的left,top座標
r,b分別對應子元素右下角的right,bottom座標
並且可以使用childview.getMeasuredWidth()和childView.getMeasureHeight()得到子元素的寬和高。
這樣就可以來對每個子元素進行佈局了。
我稱這個方法為“定位置”。定完位置後那麼子元素就被放到了我們想要的地方。
這樣一個自定義ViewGroup就可以使用了。
public class MyLayout extends ViewGroup {
public MyLayout(Context context) {
super(context);
}
public MyLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@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);
/**
* 記錄如果是wrap_content是設定的寬和高
*/
int width = 0;
int height = 0;
int cCount = getChildCount();
int cWidth = 0;
int cHeight = 0;
//根據childView計算的出的寬和高,以及設定的margin計算容器的寬和高,主要用於容器是warp_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);
}
@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();
}
}
}
首先要說一下佈局計算模式,即最後的EXACTLY。一共有三種計算模式:
MeasureSpec.EXACTLY:精確尺寸,相當於具體數值和match_parent。
MeasureSpec.AT_MOST:最大尺寸,相當於 warp_content。
MeasureSpec.UNSPECIFIED:未指定尺寸,這種情況不多,一般用於AdapterView。
最後的設定大小時,如果是精確尺寸就是用sizeWidth即獲取的尺寸,如果是最大尺寸就是要我們自己計算的那個尺寸了。
onMeasure()最主要的功能就是計算wrap_content的尺寸和設定尺寸。
這個方法稱為“建畫布”,先建了畫布才能在上面繪圖,XML檔案如下:<?xml version="1.0" encoding="utf-8"?> <com.example.layout.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.layout.MyLayout>
四.FrameLayout佈局
幀佈局,這個佈局的特點是從左上角開始,後面的會覆蓋前面的控制元件。
<?xml version="1.0" encoding="utf-8"?>
<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="120dp"
android:textColor="#9c27b0"
android:text="第一層"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="95dp"
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佈局
表格佈局。
它遵循著以下結構:<TableLayout> <TableRow> <!-在這裡填充第一行的元素-> </TableRow> <TableRow> <!-在這裡填充第二行的元素-> </TableRow> </TableLayout>
還有幾個重要屬性:
寫在TableLayout中的屬性
android:stretchColumns 設定第幾列為伸展(0表示第一列)
android:shrinkColumns 設定第幾列為收縮
android:collapseColumns 設定第幾列為隱藏
寫在TableRow裡的控制元件裡的屬性
android:layout_column 設定控制元件在第幾列
android:layout_span 設定控制元件能跨多少列<?xml version="1.0" encoding="utf-8"?> <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>
六.AbsoluteLayout佈局
絕對佈局,極力不推薦,官方已經捨棄。在此不做深究。