Android中關(guān)于CoordinatorLayout的一些實用布局技巧
介紹
CoordinatorLayout是一個“加強(qiáng)版”的 FrameLayout,它主要有兩個用途:
(1) 用作應(yīng)用的頂層布局管理器
(2) 通過為子View指定 behavior 實現(xiàn)自定義的交互行為。
在我們做 Material Design 風(fēng)格的app時通常都使用 CoordinatorLayout 作為布局的根節(jié)點(diǎn),以便實現(xiàn)特定的UI交互行為。
那么現(xiàn)在我們來看看如何用已有的一些控件實現(xiàn)一些常見的布局。
Toolbar + TabLayout 實現(xiàn) TabLayout 置頂效果
很常見的一種模式是 TabLayout 放在 ToolBar 布局中與其一起置頂在界面上方,而現(xiàn)在的效果是將ToolBar 隱藏而 TabLayout一直置頂在界面上方。
tablayout
如何實現(xiàn)呢?首先所在的 Activity 要使用 AppTheme.NoActionBar 風(fēng)格主題,之后再編寫布局文件。
<android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways|snap" app:popupTheme="@style/AppTheme.PopupOverlay"> <!-- toolbar內(nèi)部布局文件 --> </android.support.v7.widget.Toolbar> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="@dimen/tab_height" app:tabIndicatorColor="@color/white" app:tabTextColor="@color/white_normal"> </android.support.design.widget.TabLayout> </android.support.design.widget.AppBarLayout> <!-- 主界面布局文件 --> </android.support.design.widget.CoordinatorLayout>
很重要的兩點(diǎn):
- 設(shè)置 Toolbar 的
layout_scrollFlags="scroll|enterAlways|snap"
保證 Toolbar 能隨界面滑動向上隱藏。 - TabLayout 與 Toolbar 同級,父節(jié)點(diǎn)為 AppBarLayout ,保證 TabLayout 能夠能夠顯示在 Toolbar 外面而不隨其一起隱藏。
浸入式 + CollapsingToolbarLayout
CollapsingToolbarLayout 可以包裹 Toolbar , 當(dāng)其顯示完收縮動畫時使 Toolbar 顯示在頂端。而我們可以再加入浸入式的效果讓 CollapsingToolbarLayout 的背景圖突破系統(tǒng)的狀態(tài)欄使界面更加美觀同時也不影響 Toolbar 的顯示效果。
浸入式布局
在實現(xiàn)布局文件前要賦予當(dāng)前的Activity主題為AppTheme.Immersive。
其樣式要在 v19 與 v21 分別處理,至于v19之前的 android 版本那就無能為力了。
v19
<style name="AppTheme.Immersive" parent="AppTheme.NoActionBar"> <item name="android:windowTranslucentStatus">true</item> </style>
v21
<style name="AppTheme.Immersive" parent="AppTheme.NoActionBar"> <!--透明導(dǎo)航欄--> <item name="android:statusBarColor">@android:color/transparent</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item> </style>
之后再來看布局文件,包括了 AppBarLayout,CollapsingToolbarLayout 和 Toolbar 這些控件。
同樣也是要分為 v19 和 v21 兩種布局
v19
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout 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"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="220dp" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap" app:statusBarScrim="@android:color/transparent" app:titleEnabled="false"> <RelativeLayout android:id="@+id/anime_root" android:layout_width="match_parent" android:layout_height="220dp" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7"> <!-- 可伸縮背景圖布局文件 --> </RelativeLayout> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:layout_marginTop="25dp" app:layout_collapseMode="pin" app:popupTheme="@style/AppTheme.PopupOverlay" app:titleMarginTop="15dp" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <!-- 界面布局文件 --> </android.support.design.widget.CoordinatorLayout>
v21
<android.support.design.widget.CoordinatorLayout 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" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="220dp" android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap" app:statusBarScrim="@android:color/transparent" app:titleEnabled="false"> <RelativeLayout android:id="@+id/anime_root" android:layout_width="match_parent" android:layout_height="220dp" android:fitsSystemWindows="true" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7"> <!-- 可伸縮背景圖布局文件 --> </RelativeLayout> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/AppTheme.PopupOverlay" app:titleMarginTop="15dp" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <!-- 界面布局文件 --> </android.support.design.widget.CoordinatorLayout>
那么重點(diǎn)在哪里呢?
- 設(shè)置你當(dāng)前的 Activity 的狀態(tài)欄為透明,4.4之前的機(jī)型則無法適配。
- 注意每個控件下的 fitsSystemWindows 屬性,使系統(tǒng)能夠調(diào)整 view 的 padding 值使其適配。
- 設(shè)置 CollapsingToolbarLayout 為可滾動(scroll),滾動結(jié)束后可以設(shè)置 statusBarScrim 作為覆蓋色。
- 背景布局與 Toolbar 同級,布局文件上可以設(shè)置滾動的模式,如視差滾動及相應(yīng)的值。
- 注意到 v19 的布局文件上的 Toolbar ,給它賦予了一個 android:layout_marginTop="25dp"的屬性,以便在Android 4.4上時防止被系統(tǒng)的狀態(tài)欄所覆蓋。當(dāng)然這個值可以在代碼中獲取到系統(tǒng)狀態(tài)欄高度再進(jìn)行設(shè)置。
fitsSystemWindows詳解:這個一個boolean值的內(nèi)部屬性,讓view可以根據(jù)系統(tǒng)窗口(如status bar)來調(diào)整自己的布局,如果值為true,就會調(diào)整view的paingding屬性來給system windows留出空間。
Fragment + 不同風(fēng)格布局
有時候產(chǎn)品要求在一個 Activity 上顯示不同的 Fragment 界面,且 Fragment 上的每一個頭部樣式都不一樣,比如說一個是普通情況下的 Toolbar,另一個卻是浸入式的可伸縮頭部,像簡書app的首頁
額,我們先不提圖中的那個bug,圖中的界面主要是兩種效果,一個為普通的標(biāo)題欄+正文,另一個則是浸入式的圖片背景+正文。我們也可以利用浸入式的主題來仿照出簡書的效果。
各個頁面不同樣式
第一步要做的是給 Fragment 所在的 Activity 套上 AppTheme.Immersive 浸入式主題樣式,之后為 Activity 加上布局
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.ashokvarma.bottomnavigation.BottomNavigationBar android:id="@+id/bottom_navigation_bar" android:layout_width="match_parent" android:layout_height="56dp" android:layout_gravity="bottom" android:fitsSystemWindows="true"> </com.ashokvarma.bottomnavigation.BottomNavigationBar> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="56dp" /> </android.support.design.widget.CoordinatorLayout>
無他,就是一個 ViewPager 容器用來加載 Fragment。
書城所在的 Fragment 布局如下:
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.design.widget.CollapsingToolbarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap" app:statusBarScrim="@android:color/transparent" app:titleEnabled="false"> <!-- 背景布局 --> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="36dp" android:minHeight="36dp" app:layout_collapseMode="pin" app:popupTheme="@style/AppTheme.PopupOverlay"> <!-- 搜索框布局 --> </android.support.v7.widget.Toolbar> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <!-- 界面主布局 --> </android.support.design.widget.CoordinatorLayout>
布局跟之前的浸入式布局相同,但單單這樣布局是有問題的,此時的 Toolbar 會顯示在系統(tǒng)的狀態(tài)欄下。所以我們要修正 Toolbar 的擺放位置,即人為的為其設(shè)置 MarginTop 距離。
/** * 修正 Toolbar 的位置 * 在 Android 4.4 版本下無法顯示內(nèi)容在 StatusBar 下,所以無需修正 Toolbar 的位置 * * @param toolbar */ protected void fixToolbar(Toolbar toolbar) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { int statusHeight = getStatusBarHeight(getActivity()); ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); layoutParams.setMargins(0, statusHeight, 0, 0); } } /** * 獲取系統(tǒng)狀態(tài)欄高度 * * @param context * @return */ public int getStatusBarHeight(Context context) { Class<?> c = null; Object obj = null; Field field = null; int x = 0, statusBarHeight = 0; try { c = Class.forName("com.android.internal.R$dimen"); obj = c.newInstance(); field = c.getField("status_bar_height"); x = Integer.parseInt(field.get(obj).toString()); statusBarHeight = context.getResources().getDimensionPixelSize(x); } catch (Exception e1) { e1.printStackTrace(); } return statusBarHeight; }
在每個 Fragment 初始化 Toolbar 時都需要調(diào)用這個方法來修正位置。
重點(diǎn)又來了:
- 修改為浸入式樣式主題,要點(diǎn)見上一個案例。
- 人為修正 Toolbar 的距離,保證位置擺放正確。
- 注意 Fragment 切換時偶爾出現(xiàn)的一些 Toolbar 問題。
Fragment 與 Toolbar 的選項菜單問題
在 Fragment 之間切換的時候很容易遇到 Toolbar 上的菜單無法正確的顯示的問題,解決方法也很簡單,在 Fragment 的 onCreateView() 方法中添加一行代碼:
toolbar.setTitle("title"); ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar); fixToolbar(toolbar); setHasOptionsMenu(true); //重要的一行代碼,防止選項菜單錯亂
總結(jié)
自從 Google 出了 com.android.support:design 包之后,其多樣化的定制給 App 應(yīng)用帶來更加酷炫的效果,布局的變化只不過是其中的一部分而已。文章的開頭也說了, CoordinatorLayout 不止是帶來了布局的變化,也帶給了控件更多的UI交互動作。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
Android自定義DataTimePicker日期時間選擇器使用詳解
這篇文章主要為大家詳細(xì)介紹了Android自定義DataTimePicker日期時間選擇器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-09-09ListView實現(xiàn)下拉刷新加載更多的實例代碼(直接拿來用)
這篇文章主要介紹了ListView實現(xiàn)下拉刷新加載更多的實例代碼(直接拿來用)的相關(guān)資料,需要的朋友可以參考下2016-07-07Android自定義View的三種實現(xiàn)方式總結(jié)
本篇文章主要介紹了Android自定義View的三種實現(xiàn)方式總結(jié),非常具有實用價值,需要的朋友可以參考下。2017-02-02Jetpack Compose自定義動畫與Animatable詳解
在今年的Google/IO大會上,亮相了一個全新的 Android 原生 UI 開發(fā)框架-Jetpack Compose, 與蘋果的SwiftIUI一樣,Jetpack Compose是一個聲明式的UI框架,這篇文章主要介紹了Jetpack Compose自定義動畫與Animatable2022-10-10Android 中RecyclerView頂部刷新實現(xiàn)詳解
這篇文章主要介紹了Android 中RecyclerView頂部刷新實現(xiàn)詳解的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-10-10Android實現(xiàn)進(jìn)度條(ProgressBar)的功能與用法
這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)進(jìn)度條(ProgressBar)的功能與用法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-08-08Android中Fragment相互切換間不被回收的實現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Android中Fragment相互切換間不被回收的實現(xiàn)方法,文中給出了詳細(xì)的示例代碼和注釋供大家參考學(xué)習(xí),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-08-08