在前面幾講中, 我們其實已經多次用到過Layout,用的最多的線性布局。今天我們來詳細探討一下布局。
Layout,是在Activity的界面的結構,它定義了您的UI元素該如何組織來呈現給用戶。Layout的定義其實有兩種方式:
- Xml定義
- 代碼定義
Xml layout 定義的好處在於,減少了與代碼的耦合,同一份代碼可以用不同layout以適應大小屏幕,橫豎屏。
代碼定義好的好處在於靈活性強,當然效率也相對要一些。
所以這兩種方式有很有用,有時也會結合起來使用。但平常用的最多的還是xml形式的。
主要的Layout一共有五種:
- LinearLayout 線性布局
- RelativeLayout 相對布局
- AbsoluteLayout 絕對定位,以絕對坐標來定位,已經被廢棄,因為Android平台的設備屏幕如此眾多,用絕對定位非常不合適。
- FrameLayout 幀布局
- TableLayout 表格布局
Android 3.0引入的還有Fragment, 嚴格來講它並不是layout,以后會詳細描述。
下面我們來詳細研究一下這幾種Layout:
LinearLayout
包括Vertical垂直, Horizontal水平兩種,由屬性android:orientation設定,這個在上一講已經講過,這里不在重復。
線性布局還有一個重要的屬性weight. 我們先來看一個例子:
我們有三個按鈕,水平放置:
<?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="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="收藏" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下載" /> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="分享" /> </LinearLayout>
預覽結果是:
實際上這樣不大好看,我們希望他們都居中,而且平分水平方向的空間,於是我們為每一個Button 加上android:layout_weight屬性,值都是1,表示他們的權重都是1:
<?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="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="收藏" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="下載" /> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="分享" /> </LinearLayout>
預覽結果:
所以當元素的layout_weight值都是一樣時,他們會平分長度(horizontal時)或者高度(vertical時)。
接下來我們做一下別的嘗試:
把兩邊的Button的layout_weight屬性去掉呢?
這個時候只有中間的Button有layout_weight=1, 把它的值調大點? 2? 3?。。。10?發現結果都是一樣的。所以:
LinearLayout下的子元素,1. 默認情況下layout_weight為零 2.所有的子元素當中,layout_weight值最大的那個元素,會占滿剩下的所有空間
LinearLayout中還有一個重要的屬性:android:weightSum 總權重值
還是這個例子,假如我們想讓兩邊的按鈕占四分之一,中間按鈕占四分之二, 可以這樣來實現:
LinearLayout的android:weightSum=”4”, 兩邊的Button layout_weight=”1”, 中間的為2,結果如下:
你也許注意到,既然已經有了layout_weight來分配寬度(horizontal時),layout_width的值還有意義嗎?
確實,沒有意義了,但是它又是必須要寫的屬性,所以,為了提高性能,我們可以把它寫成android_width=”0dp”.
<Button android:id="@+id/button3" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="分享" />
RelativeLayout
相對布局,是通過UI元素的相互參照來定位,如下圖,A,B,D在C的下面,而且D在A的右邊,也在B的左邊。
相對布局非常有用,它可是實現許多復雜要求的界面布局。
相對布局有如下重要屬性:
在某個元素的上下左右方,值為對應元素的id
android:layout_toLeftOf
android:layout_toRightOf
android:layout_above
讓本元素的邊緣與指定id的上下左右,基線邊緣對齊,值都是某個元素的Id
android:layout_alignBottom
android:layout_alignLeft
以下的值為true時,靠在父容器的上下左右邊緣
android:layout_alignParentBottom
android:layout_alignParentLeft
android:layout_alignParentRight
android:layout_alignParentTop
android:layout_centerHorizontal
android:layout_centerInParent
android:layout_centerVertical
android:layout_alignWithParentIfMissing
如果設置為true, 被依賴的View, 如果設置成了Gone(View 有個可見性屬性android:visibility, 可選三個值visible, invisible, gone), 將以其父容器作為參考。
舉一個實例,就容易明白了:
要求:
- 文本框和兩個按鈕靠界面底部,他們都是同一行。
- 兩個按鈕靠右排列
- 文本框靠左
- 圖片在文本框的上方
<?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" > <!-- android:layout_above, 在EditText 的上方 --> <ImageView android:id="@+id/top_image" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_above="@+id/et_reply" android:layout_marginBottom="10dp" android:src="@drawable/cat" /> <!-- android:layout_alignParentLeft,android:layout_alignParentBottom 靠左在界面底部 --> <EditText android:id="@+id/et_reply" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginLeft="10dp" android:ems="8" android:hint="留言..." /> <!-- layout_toLeftOf在btn_renren的右邊,layout_alignBottom與et_reply的底部邊緣對齊 --> <ImageButton android:id="@+id/btn_kaixin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/btn_renren" android:layout_alignBottom="@id/et_reply" android:src="@drawable/ic_chk_kaixin_selected" /> <ImageButton android:id="@+id/btn_renren" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@id/et_reply" android:layout_alignParentRight="true" android:src="@drawable/ic_chk_renren_selected" /> </RelativeLayout>
需要注意的是,填寫參考的id時,有時候是@id/xxx, 有時候是@+id/xxxx, 怎么分辨什么時候該用啥呢?
當依賴的元素在當前元素的后面(XML節點出現的順序),用@+id/xxxx,因為還沒有出現,所有要用@+id表示新建id
反之,在前面,用@id/xxxx, @id表示引用已有id
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" > <TextView android:id="@+id/tv1" android:layout_width="300dp" android:layout_height="300dp" android:gravity="bottom|right" android:text="First" android:textSize="40sp" android:background="#ffabff00" /> <TextView android:id="@+id/tv2" android:layout_width="200dp" android:layout_height="200dp" android:gravity="bottom|right" android:text="Second" android:textSize="40sp" android:background="#ff8432" /> <TextView android:id="@+id/tv3" android:layout_width="100dp" android:layout_height="100dp" android:gravity="bottom|right" android:text="Third" android:textSize="40sp" android:background="#0f0fff" /> </FrameLayout>
我們可以看到,FrameLayout里面的元素默認都是以左上角為對齊的。
這個FrameLayout可能有個Bug, 設置android:layout_margin時不生效,但是如果先設置了android:layout_gravity, layout_margin又生效了。
TableLayout
表格的方式來排列元素。
<?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:stretchColumns="0,1,2" > <TableRow android:id="@+id/tableRow1" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:id="@+id/top_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/pic1" /> <ImageView android:id="@+id/top_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/pic2" /> <ImageView android:id="@+id/top_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/pic3" /> </TableRow> <TableRow android:id="@+id/tableRow2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" > <ImageView android:id="@+id/top_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/pic4" /> <ImageView android:id="@+id/top_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/pic5" /> <ImageView android:id="@+id/top_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/pic6" /> </TableRow> </TableLayout>
TableLayout屬性有:
android:collapseColumns:以第0行為序,隱藏指定的列
如果android:collapseColumns=2,結果是:
android:shrinkColumns:以第0行為序,當行寬不夠包裹內容時,自動“縮水”指定的列
注意是“縮水”,我們先把最后一張換上大一點的圖片,讓它不夠位置,
如果android:shrinkColumns=2, 縮水最后一列,結果是:
如果android:shrinkColumns=1,縮水中間一列:
android:stretchColumns:以第0行為序,盡量把指定的列填充空白部分,注意是“空白部分”。第一個例子就是android:stretchColumns="0,1,2"
下一講,我們來用代碼定義Layout.