Android中关于CoordinatorLayout的⼀些实⽤布局技巧介绍
CoordinatorLayout是⼀个“加强版”的 FrameLayout,它主要有两个⽤途:
(1)⽤作应⽤的顶层布局管理器
(2)通过为⼦View指定 behavior 实现⾃定义的交互⾏为。
在我们做 Material Design 风格的app时通常都使⽤ CoordinatorLayout 作为布局的根节点,以便实现特定的UI交互⾏为。
那么现在我们来看看如何⽤已有的⼀些控件实现⼀些常见的布局。
Toolbar + TabLayout 实现 TabLayout 置顶效果
很常见的⼀种模式是 TabLayout 放在 ToolBar 布局中与其⼀起置顶在界⾯上⽅,⽽现在的效果是将ToolBar 隐藏⽽TabLayout⼀直置顶在界⾯上⽅。
tablayout
如何实现呢?⾸先所在的 Activity 要使⽤ AppTheme.NoActionBar 风格主题,之后再编写布局⽂件。
<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内部布局⽂件 -->
</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>
很重要的两点:
设置 Toolbar 的layout_scrollFlags="scroll|enterAlways|snap"保证 Toolbar 能随界⾯滑动向上隐藏。
TabLayout 与 Toolbar 同级,⽗节点为 AppBarLayout ,保证 TabLayout 能够能够显⽰在 Toolbar 外⾯⽽不随其⼀起隐藏。
浸⼊式 + CollapsingToolbarLayout
CollapsingToolbarLayout 可以包裹 Toolbar , 当其显⽰完收缩动画时使 Toolbar 显⽰在顶端。⽽我们可以再加⼊浸⼊式的效果让 CollapsingToolbarLayout 的背景图突破系统的状态栏使界⾯更加美观同时也不影响 Toolbar 的显⽰效果。
浸⼊式布局
在实现布局⽂件前要赋予当前的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">
<!--透明导航栏-->
<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="schemas.android/apk/res/android"
xmlns:app="schemas.android/apk/res-auto"
xmlns:tools="schemas.android/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="schemas.android/apk/res/android"
xmlns:app="schemas.android/apk/res-auto"
xmlns:tools="schemas.android/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>
那么重点在哪⾥呢?
设置你当前的 Activity 的状态栏为透明,4.4之前的机型则⽆法适配。
注意每个控件下的 fitsSystemWindows 属性,使系统能够调整 view 的 padding 值使其适配。
设置 CollapsingToolbarLayout 为可滚动(scroll),滚动结束后可以设置 statusBarScrim 作为覆盖⾊。
背景布局与 Toolbar 同级,布局⽂件上可以设置滚动的模式,如视差滚动及相应的值。
注意到 v19 的布局⽂件上的 Toolbar ,给它赋予了⼀个 android:layout_marginTop="25dp"的属性,以便在Android 4.4上时防⽌被系统的状态栏所覆盖。当然这个值可以在代码中获取到系统状态栏⾼度再进⾏设置。
fitsSystemWindows详解:这个⼀个boolean值的内部属性,让view可以根据系统窗⼝(如status bar)来调整⾃⼰的布局,如果值为true,就会调整view的paingding属性来给system windows留出空间。
Fragment + 不同风格布局
有时候产品要求在⼀个 Activity 上显⽰不同的 Fragment 界⾯,且 Fragment 上的每⼀个头部样式都不⼀样,⽐如说⼀个是普通情况下的 Toolbar,另⼀个却是浸⼊式的可伸缩头部,像简书app的⾸页
额,我们先不提图中的那个bug,图中的界⾯主要是两种效果,⼀个为普通的标题栏+正⽂,另⼀个则是浸⼊式的图⽚背景+正⽂。我们也可以利⽤浸⼊式的主题来仿照出简书的效果。
各个页⾯不同样式
第⼀步要做的是给 Fragment 所在的 Activity 套上 AppTheme.Immersive 浸⼊式主题样式,之后为 Activity 加上布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="schemas.android/apk/res/android"
xmlns:app="schemas.android/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">
android layout布局</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="schemas.android/apk/res/android"
xmlns:app="schemas.android/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 会显⽰在系统的状态栏下。所以我们要修正
Toolbar 的摆放位置,即⼈为的为其设置 MarginTop 距离。
/**
* 修正 Toolbar 的位置
* 在 Android 4.4 版本下⽆法显⽰内容在 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) LayoutParams();
layoutParams.setMargins(0, statusHeight, 0, 0);
}
}
/**
* 获取系统状态栏⾼度
*
* @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.(obj).toString());
statusBarHeight = Resources().getDimensionPixelSize(x);
} catch (Exception e1) {
e1.printStackTrace();
}
return statusBarHeight;
}
在每个 Fragment 初始化 Toolbar 时都需要调⽤这个⽅法来修正位置。
重点⼜来了:
修改为浸⼊式样式主题,要点见上⼀个案例。
⼈为修正 Toolbar 的距离,保证位置摆放正确。
注意 Fragment 切换时偶尔出现的⼀些 Toolbar 问题。
Fragment 与 Toolbar 的选项菜单问题
在 Fragment 之间切换的时候很容易遇到 Toolbar 上的菜单⽆法正确的显⽰的问题,解决⽅法也很简单,在 Fragment 的onCreateView() ⽅法中添加⼀⾏代码:
toolbar.setTitle("title");
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
fixToolbar(toolbar);
setHasOptionsMenu(true); //重要的⼀⾏代码,防⽌选项菜单错乱
总结
⾃从 Google 出了 com.android.support:design 包之后,其多样化的定制给 App 应⽤带来更加酷炫的效果,布局的变化只不过是其中的⼀部分⽽已。⽂章的开头也说了, CoordinatorLayout 不⽌是带来了布局的变化,也带给了控件更多的UI交互动作。
好了,以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作能带来⼀定的帮助,如果有疑问⼤家可以留⾔交流,谢谢⼤家对的⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论