布局概述
為了讓組件(TextView,Button等)在不同的手機螢屏上都能運行良好(不同手機螢屏解析度、尺寸并不完全相同),如果讓程式手動控制每個組件的大小、位置,則將給編程帶來巨大的困難,為了解決這個問題,Android提供了布局管理器,布局管理器可以根據運行平臺來調整組件的大小,咱們程式員要做的只是為容器選擇合適的布局管理器,
每當Acitivity.setContentView(@LayoutRes int layoutResID)方法被呼叫,或者一個View通過LayoutInflater物件inflater出來,那么相關的布局檔案就會被加載并決議出來,XML檔案中每個大寫的XML節點對應著一個View物件,他們被系統實體化,在Acitviity或者Fragment的整個生命周期中,他們都是UI層級的一部分,這會影響到應用程式使用程序中的分配,

Android的布局管理器本身就是個UI組件,所有的布局管理器都是ViewGroup的子類,而ViewGroup是View的子類,所以布局管理器可以當成普通的UI組件使用,也可以作為容器類使用,可以呼叫多個多載addView()向布局管理器中添加組件,并且布局管理器可以互相嵌套,當然不推薦過多的嵌套(如果要兼容低端機型,最好不要超過5層),
布局層級管理
讓咱們一起了解一下每當系統繪制一個布局時,都會發生一些什么,這一程序由兩個步驟完成:
1、繪制(Measurement)
a、根布局測量自身,
b、根布局要求它內部所有子組件測量自身,
c、所有自布局都需要讓它們內部的子組件完成這樣的操作,直到遍歷完視圖層級中所有的View,
2、擺放( Positioning)
a、當布局中所有的View都完成了測量,根布局則開始將它們擺放到合適的位置,
b、所有子布局都需要做相同的事情,直到遍歷完視圖層級中所有的View,
當某個View的屬性發生變化(如:TextView內容變化或ImageView影像發生變化),View自身會呼叫View.invalidate()方法(必須從 UI 執行緒呼叫),自底向上傳播該請求,直到根布局(根布局會計算出需要重繪的區域,進而對整個布局層級中需要重繪的部分進行重繪),布局層級越復雜,UI加載的速度就越慢,因此,在撰寫布局的時候,盡可能地扁平化是非常重要的,
AbsoluteLayout已被棄用,咱就不多說它了,FrameLayout和TableLayout有各自的特殊用途,LinearLayout 和RelativeLayout是可以互換的,ConstraintLayout和RelativeLayout類似,也就是說,在撰寫布局時,可以選擇其中一種,咱們可以以不同的方式來撰寫下面這個簡單的布局,

第一種方式是使用LinearLayout,雖然可讀性比較強,但是性能比較差,由于嵌套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">
<View
android:id="@+id/view_top_1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/color_666666"/>
<View
android:id="@+id/view_top_2"
android:layout_width="200dp"
android:layout_height="100dp"
android:background="@color/teal_200"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<View
android:id="@+id/view_top_3"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/color_FF773D"/>
<View
android:id="@+id/view_top_4"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/purple_500"/>
</LinearLayout>
</LinearLayout>
LinearLayout視圖層級如下所示:

第二種方法基于RelativeLayout,在這種情況下,你不需要嵌套其他ViewGroup,因為每個子View可以相當于其他View,或相對與父控制元件進行擺放,
<?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">
<View
android:id="@+id/view_top_1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/color_666666"/>
<View
android:id="@+id/view_top_2"
android:layout_width="200dp"
android:layout_below="@id/view_top_1"
android:layout_height="100dp"
android:background="@color/teal_200"/>
<View
android:id="@+id/view_top_3"
android:layout_width="100dp"
android:layout_below="@id/view_top_2"
android:layout_height="100dp"
android:background="@color/color_FF773D"/>
<View
android:id="@+id/view_top_4"
android:layout_width="100dp"
android:layout_below="@id/view_top_2"
android:layout_toRightOf="@id/view_top_3"
android:layout_height="100dp"
android:background="@color/purple_500"/>
</RelativeLayout>
RelativeLayout視圖層級如下所示:

通過兩種方式,可以很容易看出,第一種方式LinearLayout需要3個視圖層級和6個View,第二種方式RelativeLayout僅需要2個視圖層級和5個View,
當然,雖然RelativeLayout效率更高,但不是所有情況都能通過相對布局的方式來完成控制元件擺放,所以通常情況下,這兩種方式需要配合使用,
注意:為了保證應用程式的性能,在創建布局時,需要盡量避免重繪,布局層級應盡可能地扁平化,這樣當View被重繪時,可以減少系統花費的時間,在條件允許的情況下,盡量的使用RelativeLayout和ConstraintLayout,而非LinearLayout,或者用GridLayoutl來替換LinearLayout,
開發者最常使用的是ViewGroup是LinearLayout,只是因為它很容易看懂,撰寫起來簡單,所以它就成了Android開發新手的首選,出于這個原因,Google推出了一個全新的ViewGroup,在適當的時候時候使用它,可以減少冗余,它就是網格布局GridLayout下面文章中也有講到,
布局復用
Android SDK提供了一個非常有用的標簽,在某些情況下,當你希望在其他布局中用一些已存在的布局時,<include/>標簽可通過制定相關參考ID,將一個布局添加到另一個布局,比如自定義一個標題欄,那么可以按照下面的方式,創建一個可重復用的布局檔案,
<?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="wrap_content">
<View
android:id="@+id/view_top_1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/color_666666"/>
</RelativeLayout>
接著,將<include/>標簽放入相應的布局檔案中,替換掉對應的View:
<?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">
<include layout="@layout/include_layout"/>
<View
android:id="@+id/view_top_2"
android:layout_width="200dp"
android:layout_height="100dp"
android:background="@color/teal_200"/>
<View
android:id="@+id/view_top_3"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/color_FF773D"/>
</RelativeLayout>
這么一來,當你希望重用某些View時,就不用復制/粘貼的方式來實作,只需要定義一個layout檔案,然后通過<include/>參考即可,但是這樣做,可能會引入一個冗余的ViewGroup(重用的布局檔案的根視圖),為此,Android SDK提供了另一個標簽,用來幫我們減少布局冗余,讓層級變得更加扁平化,我們只需要將可重用的根視圖,替換為<merge/>標簽即可,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="@+id/view_top_1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/color_666666"/>
</merge>
如此一來,就沒有了冗余的視圖控制元件,因為系統會忽略<merge/>標簽,并將<merge/>標簽中的視圖直接放置在相應的布局檔案中,替換<include/>標簽,
使用此標簽時,需要記住它的兩個主要限制,
a、它只能作為布局檔案的跟來使用,
b、每次呼叫LayoutInflater.inflate()時,必須為<merge/>布局檔案提供一個View,作為它的父容器:
LayoutInflater.from(this).inflate(R.layout.merge_layout,parent,true);
一、線性布局(LinearLayout常用)
LinearLayout是一個視圖組,呈線性橫向或縱向,依次繪制每個被添加進來的子組件,
LinearLayout的所有子組件依次堆疊,因此無論子視圖有多寬,垂直串列每行均只有一個子組件,水平串列將只有一行高(最高子組件的高度加上內邊距),LinearLayout會考慮子組件之間的邊距以及每個子組件的對齊方式(右對齊、居中對齊或左對齊),
布局權重
LinearLayout還支持使用android:layout_weight屬性為各個子組件分配權重,此屬性會根據視圖應在螢屏上占據的空間大小,向視圖分配“重要性”值,如果擁有更大的權重值,視圖便可展開,填充父視圖中的任何剩余空間,子組件可指定權重值,然后系統會按照子組件所宣告的權重值比例,為其分配視圖組中的任何剩余空間,默認權重為零,
LinearLayout常用XML屬性和相關方法說明
| XML屬性 | 相關方法 | 說明 |
| android:baselineAligned | setBaselineAligned(boolean) | 設定為 false 時,防止布局對齊其子項的基線, |
| android:baselineAlignedChildIndex | setBaselineAlignedChildIndex(int) | 當線性布局是另一個基線對齊的布局的一部分時,它可以指定基線對齊到其子項中的哪個子項(即,哪個子項 TextView), |
| android:divider | setDividerDrawable(Drawable) | 可繪制用作按鈕之間的垂直分隔線, |
| android:gravity | setGravity(int) | 指定物件應如何在其自身邊界內在 X 軸和 Y 軸上定位其內容, |
| android:measureWithLargestChild | setMeasureWithLargestChildEnabled | 當設定為 true 時,所有有重量的孩子都將被認為是最大孩子的最小尺寸, |
| android:orientation | setOrientation(int) | 布局應該是一列還是一行?對行使用“horizontal”,對列使用“vertical”, |
| android:weightSum | setWeightSum(float) | 定義最大權重總和, |
LinearLayout.LayoutParams
LinearLayout包含的所有子元素都受LinearLayout.LayoutParams控制,因此LinearLayout包含的子元素可以額外指定下列屬性,
LinearLayout.LayoutParams常用XML屬性和相關方法說明
| XML屬性 | 相關方法 | 說明 |
| android:layout_gravity | setGravity(int) | Gravity指定組件應如何放置在其單元組中, 必須是Gravity常量值中的一個或多個(以“|”分隔), |
| android:layout_weight |
| 指示 LinearLayout 中有多少額外空間分配給 與這些 LayoutParams 關聯的視圖, |
Gravity常量(必須使用一個或多個以“|”分隔,如:right|top)
| Constant | Value | 描述 |
| center | 11 | 將物件放置在其容器的垂直和水平軸的中心,不改變其大小, |
| center_horizontal | 1 | 將物件放置在其容器的水平中心,不改變其大小, |
| center_vertical | 10 | 將物件放在其容器的垂直中心,不改變其大小, |
| clip_horizontal | 8 | 可以設定為將子項的左邊緣和/或右邊緣剪裁到其容器邊界的附加選項,剪輯將基于水平重力:左重力將剪輯右邊緣,右重力將剪輯左邊緣,兩者都不會剪輯兩個邊緣, |
| clip_vertical | 80 | 可以設定為將子項的頂部和/或底部邊緣剪裁到其容器邊界的附加選項,剪輯將基于垂直重力:頂部重力將剪輯底部邊緣,底部重力將剪輯頂部邊緣,兩者都不會剪輯兩個邊緣, |
| fill | 77 | 如果需要,增加物件的水平和垂直大小,使其完全填滿其容器, |
| fill_horizontal | 7 | 如果需要,增加物件的水平尺寸,使其完全填滿其容器, |
| fill_vertical | 70 | 如果需要,增大物件的垂直尺寸,使其完全填滿其容器, |
| left | 3 | 將物件推到其容器的左側,不改變其大小, |
| right | 5 | 將物件推到其容器的右側,不改變其大小, |
| bottom | 50 | 將物件推到其容器的底部,而不改變其大小, |
| top | 30 | 將物件推到其容器的頂部,而不改變其大小, |
| start | 800003 | 將物件推到其容器的開頭,不改變其大小, |
| end | 800005 | 將物件推到其容器的末端,不改變其大小, |
均等分布
如要創建線性布局,讓每個子組件使用大小相同的螢屏空間,請將每個視圖的android:layout_height設定為"0dp"(針對垂直布局),或將每個視圖的android:layout_width設定為"0dp"(針對水平布局),然后,請將每個視圖的android:layout_weight設定為"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="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_top"
android:layout_width="match_parent"
android:layout_weight="1"
android:background="@color/color_188FFF"
android:orientation="horizontal"
android:layout_height="0dp">
</LinearLayout>
<LinearLayout
android:id="@+id/ll_bottom"
android:layout_width="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
android:background="@color/color_ff0000"
android:layout_height="0dp">
</LinearLayout>
</LinearLayout>
不等分布
你也可創建線性布局,讓子元素使用大小不同的螢屏空間:
a、如果有三個文本欄位,其中兩個宣告權重為 1,另一個未賦予權重,那么沒有權重的第三個文本欄位就不會展開,而僅占據其內容所需的區域,另一方面,另外兩個文本欄位將以同等幅度展開,填充測量三個欄位后仍剩余的空間,
b、如果有三個文本欄位,其中兩個欄位宣告權重為 1,而為第三個欄位賦予權重 2(而非 0),那么現在相當于宣告第三個欄位比另外兩個欄位更為重要,因此,該欄位將獲得總剩余空間的一半,而其他兩個欄位均享余下的空間,

<?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:id="@+id/ll_top"
android:layout_width="match_parent"
android:layout_weight="1"
android:background="@color/color_188FFF"
android:orientation="horizontal"
android:layout_height="0dp">
<View
android:id="@+id/view_top_1"
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="@color/color_ff0000"/>
<View
android:id="@+id/view_top_2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@color/purple_500"/>
<View
android:id="@+id/view_top_3"
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="@color/color_FF773D"/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_bottom"
android:layout_width="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
android:background="@color/color_ff0000"
android:layout_height="0dp">
<View
android:id="@+id/view_bottom_1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@color/color_FF773D"/>
<View
android:id="@+id/view_bottom_2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:background="@color/teal_200"/>
<View
android:id="@+id/view_bottom_3"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@color/color_ff0000"/>
</LinearLayout>
</LinearLayout>
二、相對布局(RelativeLayout常用)
RelativeLayout是一個視圖組,每個子組件位置是相對的,可以相對于同一層級下其他控制元件,也可以相對于父控制元件,
RelativeLayout是用于設計用戶界面的非常強大的實用程式,因為它可以消除嵌套視圖組并保持布局層次結構平坦,從而提高性能,如果你發現自己使用了多個嵌套LinearLayout組,則可以將它們替換為單個RelativeLayout,
定位視圖
RelativeLayout讓子視圖指定它們相對于父視圖或彼此的位置(由 ID 指定),因此,如果A組件的位置是由B組件的位置來決定,Android要求先定義B組件,再定義A組件
RelativeLayout常用XML屬性和相關方法說明
| XML屬性 | 相關方法 | 說明 |
| android:gravity | setGravity(int) | 指定物件應如何在其自身邊界內在X軸和Y軸上定位其內容, 必須是Gravity常量值中的一個或多個(以“|”分隔), |
| android:ignoreGravity | setIgnoreGravity(int) | 指示哪個視圖不應受重力影響, |
RelativeLayout.LayoutParams
為了控制RelativeLayout布局容器中各子組件的布局分布,RelativeLayout提供了一個內部類:RelativeLayout.LayoutParams,該類提供了大量的XML屬性來控制RelativeLayout布局容器中子組件的布局分布,
RelativeLayout.LayoutParams里設的XML屬性及說明
| XML屬性 | 說明 |
| android:layout_above | 將此視圖的底部邊緣定位在給定的錨視圖 ID 上方, |
| android:layout_alignBaseline | 將此視圖的基線定位在給定錨視圖 ID 的基線上, |
| android:layout_alignBottom | 使此視圖的底部邊緣與給定的錨視圖 ID 的底部邊緣匹配, |
| android:layout_alignEnd | 使此視圖的結束邊緣與給定錨視圖 ID 的結束邊緣匹配, |
| android:layout_alignLeft | 使此視圖的左邊緣與給定錨視圖 ID 的左邊緣匹配, |
| android:layout_alignParentBottom | 如果為 true,則使此視圖的底部邊緣與父視圖的底部邊緣匹配, |
| android:layout_alignParentEnd | 如果為 true,則使此視圖的結束邊緣與父視圖的結束邊緣匹配, |
| android:layout_alignParentLeft | 如果為 true,則使此視圖的左邊緣與父視圖的左邊緣匹配, |
| android:layout_alignParentRight | 如果為 true,則使此視圖的右邊緣與父視圖的右邊緣匹配, |
| android:layout_alignParentStart | 如果為 true,則使此視圖的起始邊緣與父視圖的起始邊緣匹配, |
| android:layout_alignParentTop | 如果為 true,則使此視圖的頂部邊緣與父視圖的頂部邊緣匹配, |
| android:layout_alignRight | 使此視圖的右邊緣與給定錨視圖 ID 的右邊緣匹配, |
| android:layout_alignStart | 使此視圖的起始邊緣與給定錨視圖 ID 的起始邊緣匹配, |
| android:layout_alignTop | 使此視圖的頂部邊緣與給定的錨視圖 ID 的頂部邊緣匹配, |
| android:layout_alignWithParentIfMissing | 如果設定為 true,則在 layout_toLeftOf、layout_toRightOf 等無法找到錨點時,將使用父級作為錨點, |
| android:layout_below | 將此視圖的頂部邊緣定位在給定的錨視圖 ID 下方, |
| android:layout_centerHorizontal | 如果為 true,則此子項在其父項內水平居中, |
| android:layout_centerInParent | 如果為 true,則此子項在其父項內水平和垂直居中, |
| android:layout_centerVertical | 如果為 true,則將此子項垂直居中于其父項內, |
| android:layout_toEndOf | 將此視圖的起始邊緣定位到給定錨視圖 ID 的末尾, |
| android:layout_toLeftOf | 將此視圖的右邊緣定位在給定錨視圖 ID 的左側, |
| android:layout_toRightOf | 將此視圖的左邊緣定位在給定錨視圖 ID 的右側, |
| android:layout_toStartOf | 將此視圖的結束邊緣定位到給定錨視圖 ID 的開始處, |
| android:layout_above | 將此視圖的底部邊緣定位在給定的錨視圖 ID 上方, |
除此之外,RelativeLayout.LayoutParams還繼承了ViewGroup.MarginLayoutParams,因此RelativeLayout布局容器中每個子組件也可以指定ViewGroup.MarginLayoutParams所支持的各XML屬性,
不設定相對位置(重疊在一起)

<?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">
<View
android:id="@+id/view_top_1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/color_666666"/>
<View
android:id="@+id/view_top_2"
android:layout_width="200dp"
android:layout_height="100dp"
android:background="@color/teal_200"/>
<View
android:id="@+id/view_top_3"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/color_FF773D"/>
</RelativeLayout>
設定相對位置,未出現重疊

<?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">
<View
android:id="@+id/view_top_1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/color_666666"/>
<View
android:id="@+id/view_top_2"
android:layout_width="200dp"
android:layout_below="@id/view_top_1"
android:layout_height="100dp"
android:background="@color/teal_200"/>
<View
android:id="@+id/view_top_3"
android:layout_width="100dp"
android:layout_below="@id/view_top_2"
android:layout_height="100dp"
android:background="@color/color_FF773D"/>
<View
android:id="@+id/view_top_4"
android:layout_width="100dp"
android:layout_below="@id/view_top_2"
android:layout_toRightOf="@id/view_top_3"
android:layout_height="100dp"
android:background="@color/purple_500"/>
</RelativeLayout>
三、網格布局(GridLayout)
GridLayout把這個容器劃分成rows×columns個網格,每個網格可以放一個組件, 除此之外,也可以設定一個組件橫跨多少列、一個組件縱跨多少行(支持跨行和跨列以及每個單元格組內的任意對齊形式),
GridLayout提供了setColumnCount(int)和setRowCount(int)方法來控制該網路的列數和行數,
GridLayout的XML屬性和相關方法說明
| XML屬性 | 相關方法 | 說明 |
| android:alignmentMode | setAlignmentMode(int) | 當設定為 alignMargins 時,會導致在視圖的外邊界之間進行對齊,由其邊距定義, |
| android:columnCount | setColumnCount(int) | 自動定位子項時要創建的最大列數, |
| android:columnOrderPreserved | setColumnOrderPreserved (boolean) | 設定為 true 時,強制列邊界以與列索引相同的順序出現, |
| android:orientation | setOrientation(int) | 布局期間不使用方向屬性, |
| android:rowCount | setRowCount(int) | 自動定位子項時要創建的最大行數, |
| android:rowOrderPreserved | setRowOrderPreserved(boolean) | 設定為 true 時,強制行邊界以與行索引相同的順序出現, |
| android:useDefaultMargins | setUseDefaultMargins(boolean) | 當設定為 true 時,告訴 GridLayout 在視圖的布局引數中未指定任何邊距時使用默認邊距, |
GridLayout.LayoutParams
為了控制GridLayout布局容器中各子組件的布局分布,GridLayout提供了一個內部類:GridLayout.LayoutParams,該類提供了大量的XML屬性來控制GridLayout布局容器中子組件的布局分布,
GridLayout.LayoutParams里設的XML屬性和相關方法說明
| XML屬性 | 相關方法 | 說明 |
| android:layout_column |
| 界定此視圖占用的單元格組左側的列邊界, |
| android:layout_columnSpan |
| 列跨度:界定此視圖占用的單元格組的左右邊界之間的差異, |
| android:layout_columnWeight |
| 在多余空間分配期間應分配給此視圖的水平空間的相對比例, |
| android:layout_gravity | setGravity(int) | 重力指定組件應如何放置在其單元組中, |
| android:layout_row |
| 界定此視圖占據的單元格組頂部的行邊界, |
| android:layout_rowSpan |
| 行跨度:界定此視圖占據的單元格組的頂部和底部邊界之間的差異, |
| android:layout_rowWeight |
| 在多余空間分配期間應分配給此視圖的垂直空間的相對比例, |

<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:columnCount="4"
android:rowCount="5">
<Button
android:id="@+id/one"
android:text="1" />
<Button
android:id="@+id/two"
android:text="2" />
<Button
android:id="@+id/three"
android:text="3" />
<Button
android:id="@+id/devide"
android:text="/" />
<Button
android:id="@+id/four"
android:text="4" />
<Button
android:id="@+id/five"
android:text="5" />
<Button
android:id="@+id/six"
android:text="6" />
<Button
android:id="@+id/multiply"
android:text="×" />
<Button
android:id="@+id/seven"
android:text="7" />
<Button
android:id="@+id/eight"
android:text="8" />
<Button
android:id="@+id/nine"
android:text="9" />
<Button
android:id="@+id/minus"
android:text="-" />
<Button
android:id="@+id/zero"
android:layout_columnSpan="2"
android:layout_gravity="fill"
android:text="0" />
<Button
android:id="@+id/point"
android:text="." />
<Button
android:id="@+id/plus"
android:layout_rowSpan="2"
android:layout_gravity="fill"
android:text="+" />
<Button
android:id="@+id/equal"
android:layout_columnSpan="3"
android:layout_gravity="fill"
android:text="=" />
</GridLayout>
這樣的布局用LinearLayout也能做,但是相對麻煩一點,所以在適當的時候時候使用GridLayout就非常的有必要了,而且你可能注意到了,子組件中并沒有指定android:layout_width和android:layout_height屬性,這是因為這兩個屬性的默認值都是LayoutPrams.WRAP_COUNTENT,而在此,我們希望使用的就是LayoutPrams.WRAP_COUNTENT,所以就沒必要指定了,GridLayout和LinaerLayout十分相似,所以將LinaerLayout替換為GridLayout也相當簡單,
四、表格布局(TableLayout)
TableLayout繼承了LinerarLayout,因此它的本質依然是線性布局管理器,表格采用行、列的形式來管理UI組件,TableLayout并不需要明確地宣告包含多少行、多少列,而是通過TableRow、其他組件來控制表格的行數和列數,
每次向TableLayout中添加TableRow,該TableRow就是一個表格行,TableRow也是容器,因此它也可以不斷的添加其他組件,每添加一個子組件該表格就增加一列,
如果直接向TableLayout添加組件,那么這個組件將直接占一行,
在TableLayout中、列的寬度由該列最寬的那個單元格決定,整個TableLayout的寬度取決于父容器的寬度(默認占滿父容器)
Collapsed:如果某列被設為Collapsed,那么該列所有單元格都會被隱藏,
在TableLayout中,可以為單元格設定的三種行為方式:
Shrinkable:如果某列被設為Shrinkable,那么該列所有單元格的寬度可以被收縮,以保證該變革能適應父容器的寬度,
Stretchable:如果某列被設為Stretchable,那么該列所有單元格的寬度可以被拉伸,以保證組件能完全填充滿表格空余空間,
TableLayout繼承了LinerarLayout,因此它完全可以支持LinerarLayout所支持的XML屬性,初次之外還支持下面的XML屬性,
TableLayout的常用XML屬性和相關方法說明
| XML屬性 | 相關方法 | 說明 |
| android:collapseColumns | setColumnCollapsed(int,boolean) | 要折疊的列的從零開始的索引, |
| android:shrinkColumns | setShrinkAllColumns(boolean) | 要收縮的列的從零開始的索引, |
| android:stretchColumns | setStretchAllColumns(boolean) | 要拉伸的列的從零開始的索引, |

<?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:layout_margin="10dp"
android:orientation="vertical">
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:shrinkColumns="1"
android:stretchColumns="2">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="頂層大佬" />
<TableRow>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="不變按鈕" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="收縮按鈕" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="拉伸按鈕" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:collapseColumns="0"
android:stretchColumns="2">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="高層大佬" />
<TableRow>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="隱藏按鈕" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="不變按鈕" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="拉伸按鈕" />
</TableRow>
</TableLayout>
</LinearLayout>
五、幀布局(FrameLayout)
FrameLayout將控制元件以堆疊的形勢堆疊起來,最近添加進去的控制元件繪制在最頂部,FrameLayout為每個加入其中的組件創建一個空白的區域(稱為一幀),每個子組件占據一幀,這些幀都會根據gravity屬性執行自動對齊,
FrameLayout常用的XML屬性和相關方法說明
| XML屬性 | 相關方法 | 說明 |
| android:foregroundGravity | setForegroundGravity(int) | 定義要應用于前景可繪制物件的重力, |
| android:measureAllChildren | setMeasureAllChildren(boolean) | 確定測量時是測量所有子項還是僅測量處于可見或不可見狀態的子項, |
FrameLayout包含的子元素也受到FrameLayout.LayoutParams的控制,因此它所包含的子元素也可以指定android:layout_gravity,

<?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">
<!--依次定義5個View,先定義的在最下面-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="280dp"
android:height="280dp"
android:text="1"
android:background="@color/color_FF773D"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="240dp"
android:text="2"
android:height="240dp"
android:background="@color/color_188FFF"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="200dp"
android:text="3"
android:height="200dp"
android:background="@color/color_ff0000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="160dp"
android:height="160dp"
android:text="4"
android:background="@color/teal_700"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="120dp"
android:height="120dp"
android:text="5"
android:background="@color/teal_200"/>
</FrameLayout>
將xml中的幾個android:text=""去掉,通過代碼進行顏色變化,可實作霓虹燈效果,
六、約束布局(ConstraintLayout)
將該庫作為依賴項添加到app/ build.gradle檔案中,
dependencies {
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
// To use constraintlayout in compose
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha06"
}
ConstraintLayout允許您以靈活的方式定位和調整子組件的大小, 它與RelativeLayout類似,所有的視圖都是根據兄弟視圖和父布局之間的關系來布局的,但是它比RelativeLayout更靈活,并且更易于在Android Studio的布局編輯器中使用,
ConstraintLayout的所有功能都可以直接從布局編輯器的可視化工具中使用,因為布局API和布局編輯器是專門為對方構建的, 所以你可以使用ConstraintLayout完全通過拖放操作來構建你的布局,而不是編輯XML,
請注意,約束中不能有回圈依賴,

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#11ff0000">
<TextView
android:id="@+id/tv1"
android:layout_width="140dp"
android:layout_height="86dp"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:background="#617"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="12dp"
android:text="就現在經濟大環境而言,很不樂觀,程式員的日子也很不好過"
android:textColor="#000000"
android:textSize="16dp"
app:layout_constraintLeft_toRightOf="@id/tv1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="12dp"
android:text="3分鐘前"
android:textColor="#333"
android:textSize="12dp"
app:layout_constraintBottom_toBottomOf="@id/tv1"
app:layout_constraintLeft_toRightOf="@id/tv1" />
</androidx.constraintlayout.widget.ConstraintLayout>
tv1設定了://父布局的左上角
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tv2設定了:tv2在tv1的右側,tv2的右側和父布局對其,tv2和tv1頂部對齊;
app:layout_constraintLeft_toRightOf="@id/tv1",
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv1"
tv3設定了:tv3在tv1的右側,tv3和tv1底部對其,
app:layout_constraintLeft_toRightOf="@id/tv1"
app:layout_constraintBottom_toBottomOf="@id/tv1"
相對定位
相對定位是在 ConstraintLayout 中創建布局的基本構建塊之一,這些約束允許您相對于另一個小部件定位給定的小部件,您可以在水平和垂直軸上約束小部件:
水平軸:左、右、起點和終點
垂直軸:頂邊、底邊和文本基線
一般概念是將小部件的給定一側約束到任何其他小部件的另一側,
以下是可用約束的串列:
layout_constraintLeft_toLeftOf
layout_constraintLeft_toRightOf
layout_constraintRight_toLeftOf
layout_constraintRight_toRightOf
layout_constraintTop_toTopOf
layout_constraintTop_toBottomOf
layout_constraintBottom_toTopOf
layout_constraintBottom_toBottomOf
layout_constraintBaseline_toBaselineOf
layout_constraintStart_toEndOf
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf
邊距
如果設定了邊距,它們將應用于相應的約束(如果存在),將邊距強制為目標邊和源邊之間的空間,通常的布局邊距屬性可用于此效果:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
請注意,邊距只能為正數或等于零,并且需要一個Dimension.
連接到 GONE 小部件時的邊距
當位置約束目標的可見性為 時View.GONE,您還可以使用以下屬性指示要使用的不同邊距值:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
尺寸限制
您可以為ConstraintLayout自身定義最小和最大尺寸:
android:minWidth 設定布局的最小寬度
android:minHeight 設定布局的最小高度
android:maxWidth 設定布局的最大寬度
android:maxHeight 設定布局的最大高度
七、絕對布局(AbsoluteLayout)
因為靈活性太差,在API Level 3中被廢棄,在實際使用中你需要為所有子組件指定x,y坐標,它的直接子類是WebView,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/286409.html
標籤:其他
上一篇:由淺入深學習android input系統(二) - input事件如何傳遞到app行程( InputDispatcher )
下一篇:fw問題修改
