Android Notes|細數「十大布局」那些事兒
最近的心情,最近的狀態,似乎沒法說個一二三四五。
做 Android 好幾年了,從單純的 Android,到現在大雜燴,這個滋味兒,真的是百感交匯。
文章的內容型別從來都是 Notes,這次對老本行進行回顧下。
努力呀,萬一一不小心優秀了呢?萬一一不小心和雞老大肩並肩了呢~
回顧 Android 佈局
曾經無論面試也好,閒聊也罷,談起 Android 佈局,總是不假思索直接說出五大布局。而到現在 2020 年末了,依然還是曾經的五大布局嗎?
這裡簡單的整理了一部分,按照個人使用頻率排序:
- ConstraintLayout: 約束佈局
- LinearLayout: 線性佈局
- RelativeLayout: 相對定位佈局
- FrameLayout: 幀佈局
- CoordinatorLayout: 協調佈局
- 百分比佈局: PercentRelativeLayout、PercentFrameLayout
- GridLayout: 網格佈局
- TableLayout: 表格佈局
- AbsoluteLayout(已棄用): 絕對定位佈局
- BlinkLayout(私有類): 布靈布靈閃動佈局
這裡說下我是怎麼找的這些佈局,方便和我一樣小白舉一反三。
引用 Flutter 一句話,萬物皆為 Weight。而在 Android 中,直觀而言,能看到的都是 View,而 View 也分不同的作用,例如 TextView、ImageView 等基礎常用 View,僅僅為了展示或者間接響應使用者操作。而基於 View 衍生出的 ViewGroup 則是通過包裹各種 View,最終呈現特有的效果。例如 LinearLayout 在原有 ViewGroup 基礎上新增水平/垂直排列方式、RelativeLayout 在原基礎上新增基於某個控制元件進行排列等。所以說直接在 Android API reference 搜尋 ViewGroup,檢視直接子類以及間接子類即可,如下所示:
文末已附上對應的連結,歡迎各位大佬指點~
五個星星我認為是必須要掌握的,比較實戰中出現評率很高了。一星簡單瞭解,面試和麵試官吹個水就好~
篇幅有限,就不一一舉例了~
反正知道肯定要比什麼都不知道要強很多的~
文中借用圖片,文末均以附上地址連結~
一、ConstraintLayout ⭐️⭐️⭐️⭐️⭐️
- ConstraintLayout 通過各種約束進行排列子 View 的佈局。
這個東西最牛掰的一點就是,支援視覺化工具操作,及其方便。在下面的事例中也會多多少少體驗一波~
使用方式:
- 新增 Maven 庫
repositories {
google()
}
- 新增 ConstraintLayout 依賴
dependencies {
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
}
當然如果你的 Android Studio 升級到最新版本,預設佈局便是 ConstraintLayout,還是要去 build 中檢視下版本。我也忘記是哪兒個版本設定預設根佈局了。
當然,貼心的 Android Studio 也提供一鍵轉化根佈局功能,如下圖:
1.相對定位 layout_constraintXXX
相對定位是在 ConstraintLayout 中建立佈局基本構建塊之一。這些約束允許一個 View 基於某個 View 進行定位,同樣我們可以在水平方向以及垂直方向進行約束 View:
- 水平軸: 左,右,起點和終點
- 垂直軸: 頂部,底部和文字基線
如下,實現將 B 按鈕定位在 A 按鈕右側:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A" />
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintStart_toEndOf="@+id/buttonA" />
</androidx.constraintlayout.widget.ConstraintLayout>
下面借用官方圖,為了更好的理解下面的屬性:
屬性 | 作用 |
---|---|
layout_constraintLeft_toLeftOf | 當前 View 左側對標目標 View 左側 |
layout_constraintLeft_toRightOf | 當前 View 左側對標目標 View 右側 |
layout_constraintRight_toLeftOf | 當前 View 右側對標目標 View 左側 |
layout_constraintRight_toRightOf | 當前 View 右側對標目標 View 右側 |
layout_constraintTop_toTopOf | 當前 View 頂部對標目標 View 頂部 |
layout_constraintTop_toBottomOf | 當前 View 頂部對標目標 View 底部 |
layout_constraintBottom_toTopOf | 當前 View 底部對標目標 View 頂部 |
layout_constraintBottom_toBottomOf | 當前 View 底部對標目標 View 底部 |
layout_constraintBaseline_toBaselineOf | 當前 View 與目標 View 文字基線對齊 |
layout_constraintStart_toEndOf | 當前 View 起點對標目標 View 終點 |
layout_constraintStart_toStartOf | 當前 View 起點對標目標 View 起點 |
layout_constraintEnd_toStartOf | 當前 View 終點對標目標 View 起點 |
layout_constraintEnd_toEndOf | 當前 View 終點對標目標 View 終點 |
2.邊距 Margins
屬性 | 作用 |
---|---|
android:layout_marginStart | 當前 View 距離目標 View 左側間距 |
android:layout_marginEnd | 當前 View 距離目標 View 右側間距 |
android:layout_marginLeft | 當前 View 距離目標 View 左側間距 |
android:layout_marginTop | 當前 View 距離目標 View 頂部間距 |
android:layout_marginRight | 當前 View 距離目標 View 右側間距 |
android:layout_marginBottom | 當前 View 距離目標 View 底部間距 |
3.目標 View 隱藏時,當前 View 邊距 Margins
當目標 View 的可見性為 View.GONE 時,還可以使用以下屬性設定當前 View 在前者 GONE 情況下的 margin。
屬性 | 作用 |
---|---|
layout_goneMarginStart | 目標 View 隱藏時,當前 View 距離左側間距 |
layout_goneMarginEnd | 目標 View 隱藏時,當前 View 距離右側間距 |
layout_goneMarginLeft | 目標 View 隱藏時,當前 View 距離左側間距 |
layout_goneMarginTop | 目標 View 隱藏時,當前 View 距離頂部間距 |
layout_goneMarginRight | 目標 View 隱藏時,當前 View 距離右側間距 |
layout_goneMarginBottom | 目標 View 隱藏時,當前 View 距離底部間距 |
如下效果:
預設 A、B 按鈕 Margin 為 50dp,在 A 按鈕隱藏狀態下,B 按鈕距離 A 的邊距變為 30dp:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="50dp"
android:text="A"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="50dp"
android:text="B"
app:layout_constraintStart_toEndOf="@+id/button"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginStart="30dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
4.居中定位和偏向比例
很多時候,我們需要的效果為居中,同時某些情況下也需要去設定比例,比如寬度百分比,下面直接上效果圖:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-s4DniE61-1607305113338)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c54c8217af1c46eab864e47130655357~tplv-k3u1fbpfcp-watermark.image)]
程式碼如下:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:layout_width="180dp"
android:layout_height="180dp"
android:scaleType="fitXY"
android:src="@drawable/img"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.19"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.16000003" />
</androidx.constraintlayout.widget.ConstraintLayout>
這裡再次回顧下當前例子中關鍵內容:
屬性 | 作用 |
---|---|
layout_constraintStart_toStartOf | 當取值為 parent 代表與父容器對齊 |
layout_constraintEnd_toEndOf | |
layout_constraintTop_toTopOf | |
layout_constraintBottom_toBottomOf |
下面是各個組合方式對應的效果:
- start 和 end 組合,便是水平居中
- top 和 bottom 組合,便是垂直居中
- start、end、top、bottom 組合便是水平/垂直居中
屬性 | 作用 |
---|---|
layout_constraintVertical_bias | 垂直方式佔比 |
layout_constraintHorizontal_bias | 水平方式佔比 |
5.圓形定位
這裡為了方便,我就直接截圖了:
下面著手實現如下效果:
程式碼如下:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是中心"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonB"
app:layout_constraintCircle="@id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="100dp"
android:text="我是花兒" />
</androidx.constraintlayout.widget.ConstraintLayout>
屬性 | 作用 |
---|---|
layout_constraintCircle | 指定圓心 View ID |
layout_constraintCircleAngle | 設定當前 View 角度 |
layout_constraintCircleRadius | 設定半徑 |
6.尺寸限制
也可以為 ConstraintLayout 自身定義最小和最大大小:
屬性 | 作用 |
---|---|
android:minWidth | 設定佈局的最小寬度 |
android:minHeight | 設定佈局的最小高度 |
android:maxWidth | 設定佈局的最大寬度 |
android:maxHeight | 設定佈局的最大高度 |
當 ConstraintLayout 內部子 View 寬度/高度為 0dp,則同等於 match_parent。
7.尺寸百分比
這個其實我蠻喜歡的,類似百分比佈局,爽的很。
使用這塊需要注意:
- 設定寬度/高度百分比時,需要先將對應的寬/高設定為 0dp;
- 預設值應設定為百分比 app:layout_constraintWidth_default=“percent” 或 app:layout_constraintHeight_default=“percent” ;(這點感覺沒啥用,不信你看下面)
- layout_constraintWidth_percent 或者 layout_constraintHeight_percent 屬性設定為介於 0 和 1 之間的值;
下面著手實現如下效果:
第一個 View 寬高佔比為:0.3:0.2,第二個 View 寬度佔比為 1:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/buttonA"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="我是中心"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.2"
app:layout_constraintWidth_percent="0.3"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/buttonB"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="我是花兒"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.32"
app:layout_constraintWidth_percent="1" />
</androidx.constraintlayout.widget.ConstraintLayout>
屬性 | 作用 |
---|---|
layout_constraintHeight_percent | 高度佔比 |
layout_constraintWidth_percent | 寬度佔比 |
作為一枚不折不扣的程式設計師而言,能省事兒絕對省事兒,上面寬高還得寫兩次,能不能一次搞定呢?
下面實現一個寬高比為 16:9 :
<Button
android:id="@+id/buttonA"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="我是中心"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
效果如下:
8.鏈式
這個效果也是蠻不錯的,有些類似前端的 Flex,感覺還是不錯的。
設定屬性 layout_constraintHorizontal_chainStyle 或 layout_constraintVertical_chainStyle 在鏈的第一個元素上時,鏈的行為將根據指定的樣式而改變(預設為 CHAIN_SPREAD )。
演示圖如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-xPOChQJB-1607305113342)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/96ac4517fa63420883e536a5f6d00f8a~tplv-k3u1fbpfcp-watermark.image)]
程式碼如下:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="130dp">
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintEnd_toStartOf="@+id/button3"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button1" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="C"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button2" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
9.輔助物件 Guideline
據官方所言,此為 ConstraintLayout 輔助工具,預設為 View.GONE。
使用方式主要分為兩種情況:
- 百分比定位: layout_constraintGuide_percent
- 絕對定位: layout_constraintGuide_begin / layout_constraintGuide_end
最後我們可以通過 orientation 去設定當前輔助線的顯示方式,水平/垂直。
我個人蠻喜歡百分比方式,先來個效果:
如何確保圖片在每種機型上都位於螢幕百分之 15 高度的位置呢?通過輔助線百分比分分鐘的事兒。
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="fitXY"
android:src="@drawable/img"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline4" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.15" />
</androidx.constraintlayout.widget.ConstraintLayout>
而關於絕對定位更好理解啦。這裡直接錄製效果圖咯,大家注意觀察點選 Icon 後程式碼以及效果變化:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-C4LZLV2M-1607305113343)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5c2d211078254adea2af7301209ea12e~tplv-k3u1fbpfcp-watermark.image)]
番外:瞭解約束佈局效能優勢
文末已附上鍊接地址,這裡只對個人感興趣的部分做出節選。
藉助 Google 翻譯學習,配合自己理解,如錯誤,歡迎指正~
針對傳統佈局以及約束佈局的優勢,這裡以下面效果為例,簡單進行對比:
傳統佈局繪製層級:
<RelativeLayout>
<ImageView />
<ImageView />
<RelativeLayout>
<TextView />
<LinearLayout>
<TextView />
<RelativeLayout>
<EditText />
</RelativeLayout>
</LinearLayout>
<LinearLayout>
<TextView />
<RelativeLayout>
<EditText />
</RelativeLayout>
</LinearLayout>
<TextView />
</RelativeLayout>
<LinearLayout >
<Button />
<Button />
</LinearLayout>
</RelativeLayout>
約束佈局繪製層級:
<android.support.constraint.ConstraintLayout>
<ImageView />
<ImageView />
<TextView />
<EditText />
<TextView />
<TextView />
<EditText />
<Button />
<Button />
<TextView />
</android.support.constraint.ConstraintLayout>
直觀上從兩種方案繪製層級相比,明顯約束佈局優勢更大。至少相比傳統 RelativeLayout 少繪製幾個 ViewGroup。
這裡從官方博文中可以得知 Android 繪製檢視過程包括如下三個階段:
-
測量(Measure)
- 系統從檢視樹自頂向下遍歷,以確定每個 ViewGroup 和 View 元素大小。而測量 ViewGroup 時,還將測量其子集 View。
-
佈局(Layout)
- 從上到下的遍歷,通過在測量階段確定的大小來確定子 View 的位置。
-
繪製(Draw)
- 系統執行的一個自上而下的遍歷,對於檢視樹中的每個物件,都會建立一個 Canvas 物件,已將繪圖命令傳送 GPU。這些命令包括 ViewGroup 和 View 大小、位置,這是系統在前兩個階段中確定的內容。
所以,我們可以得出一個概念,繪製層級越深,消耗越大。反之,消耗則低,效能越高。
測量結果:ConstraintLayout更快。
ConstraintLayout 在測量/佈局階段的效能比 RelativeLayout 好約 40%:
二、LinearLayout ⭐️⭐️⭐️⭐️
- LinearLayout 是行內以水平方式/垂直方式排列的佈局容器。
常用屬性一覽:
屬性 | 作用 |
---|---|
android:orientation | 行內排列方式(horizontal/vertical),預設水平排列 |
android:gravity | 行內 View 對齊方式 |
android:weightSum | 行內可設定的最大佔比權重 |
android:layout_weight | 當前 View 佔比權重 |
android:baselineAligned | 父容器佈局是否對齊子 View 基線 |
android:baselineAlignedChildIndex | 指定基線對齊的子 View |
來個簡單的效果:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="true"
android:measureWithLargestChild="true"
android:padding="15dp"
android:weightSum="1"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="取消" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="確定" />
</LinearLayout>
三、RelativeLayout ⭐️⭐️⭐️⭐️
- RelativeLayout 是一個以相對位置顯示子檢視的檢視組。
常用屬性:
屬性 | 作用 |
---|---|
android:layout_alignParentTop | 當前 View 上邊緣和父容器上邊緣對齊 |
android:layout_alignParentEnd | 當前 View 上邊緣和父容器右邊緣對齊 |
android:layout_alignParentBottom | 當前 View 上邊緣和父容器下邊緣對齊 |
android:layout_alignParentStart | 當前 View 上邊緣和父容器左邊緣對齊 |
android:layout_centerHorizontal | 當前 View 基於父容器水平居中 |
android:layout_centerVertical | 當前 View 基於父容器垂直居中 |
android:layout_centerInParent | 當前 View 基於父容器水平居中並垂直居中 |
android:layout_alignTop | 當前 View 位於目標 View 頂部 |
android:layout_toEndOf | 當前 View 位於目標 View 右側 |
android:layout_below | 當前 View 位於目標 View 底部 |
android:layout_toStartOf | 當前 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="130dp"
android:padding="15dp">
<ImageView
android:id="@+id/ivAvatar"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:scaleType="fitXY"
android:src="@drawable/img" />
<TextView
android:id="@+id/tvNickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_toEndOf="@id/ivAvatar"
android:text="暱稱:HLQ_Struggle" />
<TextView
android:id="@+id/tvLevel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tvNickname"
android:layout_marginStart="12dp"
android:layout_marginTop="15dp"
android:layout_toEndOf="@id/ivAvatar"
android:text="等級:V1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tvLevel"
android:layout_alignParentBottom="true"
android:layout_marginStart="12dp"
android:layout_marginTop="15dp"
android:layout_toEndOf="@id/ivAvatar"
android:text="性別:男" />
</RelativeLayout>
四、FrameLayout ⭐️⭐️⭐️⭐️
- FrameLayout 預設將控制元件層疊放置螢幕左上角。子 View 通過 android:layout_gravity 去設定自身顯示位置。
比較重要的幾個屬性:
- android:layout_gravity: 子 View 對齊方式
- android:foreground: 前景圖
- android:foregroundGravity: 前景圖位置
下面開始實現如下效果:
<?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="wrap_content"
android:foreground="@android:drawable/btn_star"
android:foregroundGravity="right|bottom"
android:padding="30dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="< 首頁" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="更多" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="首頁" />
</FrameLayout>
五、GridLayout ⭐️
- GridLayout 是以網格形式顯示子級 View 元素的 ViewGroup。
先來看看關鍵屬性:
- android:columnCount: 列數
- android:rowCount: 行數
GridLayout 子 View 屬性:
- android:layout_column: 當前 View 從第幾列開始顯示
- android:layout_columnSpan: 當前 View 佔據列數
- android:layout_row: 當前 View 從第幾行開始顯示
- android:layout_rowSpan: 當前 View 所佔行數
- android:layout_gravity: 對齊方式
比較典型的例子就是計算器了吧:
程式碼如下:
<?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="6">
<TextView
android:layout_columnSpan="4"
android:layout_gravity="fill"
android:layout_margin="6dp"
android:background="#f5f5f5"
android:text="0"
android:textSize="50sp" />
<Button
android:layout_columnSpan="2"
android:layout_gravity="fill"
android:text="回退" />
<Button
android:layout_columnSpan="2"
android:layout_gravity="fill"
android:text="清空" />
<Button android:text="+" />
<Button android:text="1" />
<Button android:text="2" />
<Button android:text="3" />
<Button android:text="-" />
<Button android:text="4" />
<Button android:text="5" />
<Button android:text="6" />
<Button android:text="*" />
<Button android:text="7" />
<Button android:text="8" />
<Button android:text="9" />
<Button android:text="/" />
<Button
android:layout_width="wrap_content"
android:text="." />
<Button android:text="0" />
<Button android:text="=" />
</GridLayout>
六、TableLayout ⭐️
- TableLayout 是以行和列顯示子級 View 元素的 ViewGroup。
來個效果實際說明:
TableLayout 行內 View 預設佔據一行的寬度。如果想一行包含多列,則需要用 TableRow 包裹,如下部分程式碼:
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:text="9*9=81" />
<TableRow>
<TextView
android:text="9*8=72" />
<TextView
android:text="8*8=64" />
</TableRow>
<TableRow>
<TextView
android:text="9*8=72" />
<TextView
android:text="8*8=64" />
<TextView
android:text="8*8=64" />
</TableRow>
</TableLayout>
- android:stretchColumns: 設定某列寬度為剩餘行寬度
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="0"> <!-- 第一列寬度為剩餘行寬度 -->
<TableRow>
<Button
android:text="我是第一列" />
<Button
android:text="我是第二列" />
</TableRow>
</TableLayout>
- android:collapseColumns: 隱藏某列
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:collapseColumns="0,2">
<TableRow>
<Button
android:text="我是第一列" />
<Button
android:text="我是第二列" />
<Button
android:text="我是第三列" />
<Button
android:text="我是第四列" />
</TableRow>
</TableLayout>
- android:shrinkColumns: 收縮某列
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:shrinkColumns="0">
<!-- ... -->
</TableLayout>
谷歌這裡提供了一個不錯的效果,感興趣的可以自己嘗試一下,如下:
七、AbsoluteLayout ⭐️
使用方式:
- 根據子級的 x/y 座標確定自身位置。靈活性較差,後續不易維護。
且在 Api 30 中已棄用。
下面實現如下效果:
第二個 TextView 位於第一個 TextView x/y 軸距離分別為 100dp:
<AbsoluteLayout
android:layout_width="0dp"
android:layout_height="300dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="世界是美好的~" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="100dp"
android:layout_y="100dp"
android:text="你在哪兒~" />
</AbsoluteLayout>
八、BlinkLayout ⭐️
這個東西就比較神奇了,一閃一閃,布靈布靈。先來個效果:
作用就是每隔 500ms 執行一次繪製,呈現的效果就是布靈布靈一閃一閃的。
使用方式也是比較 easy:
<blink
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="世界是美好的~" />
</blink>
原始碼相對比較少,下面貼一下,方便以後想看隨時看? :
private static class BlinkLayout extends FrameLayout {
private static final int MESSAGE_BLINK = 0x42;
private static final int BLINK_DELAY = 500;
private boolean mBlink;
private boolean mBlinkState;
private final Handler mHandler;
public BlinkLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.what == MESSAGE_BLINK) {
if (mBlink) {
mBlinkState = !mBlinkState;
makeBlink();
}
invalidate();
return true;
}
return false;
}
});
}
private void makeBlink() {
Message message = mHandler.obtainMessage(MESSAGE_BLINK);
mHandler.sendMessageDelayed(message, BLINK_DELAY);
}
/**
* View 附加到 window 上的時候進行回撥 適合初始化一些操作
*/
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mBlink = true;
mBlinkState = true;
makeBlink();
}
/**
* View 分離 window 的時候進行回撥 適合銷燬,重置一些操作
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mBlink = false;
mBlinkState = true;
mHandler.removeMessages(MESSAGE_BLINK);
}
/**
* 分發子元件進行繪製
* @param canvas
*/
@Override
protected void dispatchDraw(Canvas canvas) {
if (mBlinkState) {
super.dispatchDraw(canvas);
}
}
}
The end
永遠不要停止探索。
很多時候,十分鐘的探索會給你帶來不一樣的世界。
一起努力,一起期待,一起努力為了未來變得優秀吧~
如有筆誤或者理解錯誤,歡迎交流~
Thanks
- Android API reference
- Build a Responsive UI with ConstraintLayout
- ConstraintLayout
- Build a Responsive UI with ConstraintLayout
- Guideline
- Understanding the performance benefits of ConstraintLayout
- LinearLayout
- 相對佈局
- FrameLayout
- GridLayout
- 表格
- The curious BlinkLayout
- 每日一問:淺談 onAttachedToWindow 和 onDetachedFromWindow
- ondraw() 和dispatchdraw()的區別
相關文章
- Android Drawable的那些事兒Android
- Android資源那些事兒(詳)Android
- babel那些事兒Babel
- PHP那些事兒PHP
- OAuth那些事兒OAuth
- Git那些事兒Git
- webpack的那些事兒Web
- 聊聊viewport那些事兒View
- Java字串那些事兒Java字串
- Ubuntu的那些事兒Ubuntu
- Flutter 中“倒數計時”的那些事兒Flutter
- C語言那些事兒C語言
- MySQL優化那些事兒MySql優化
- https的那些事兒HTTP
- PHP 閉包那些事兒PHP
- 字元編碼那些事兒字元
- 面試的那些事兒--01面試
- 網路安全那些事兒
- TCP 的那些事兒(下)TCP
- TCP 的那些事兒(上)TCP
- 依賴注入那些事兒依賴注入
- Rest API 的那些事兒RESTAPI
- IT專案管理那些事兒專案管理
- Hadoop搭建那些事兒Hadoop
- MVP那些事兒 (4) 在Android中使用MVC(下)MVPAndroidMVC
- MVP那些事兒 (3)……在Android中使用MVC(上)MVPAndroidMVC
- 關於Android訊息機制的那些事兒Android
- Android 應用啟動那些事兒,Application? Context?AndroidAPPContext
- 漏洞檢測的那些事兒
- 雲原生java的那些事兒Java
- 「前端那些事兒」④ 效能監控前端
- 程式碼重構那些事兒
- HTTP 快取的那些事兒HTTP快取
- iOS 截圖的那些事兒iOS
- Node檔案操作那些事兒
- 物件導向 - Java那些事兒物件Java
- 檔案上傳那些事兒
- Java日誌框架那些事兒Java框架