Android CoordinatorLayout实战案例学习《
在上篇文章中,和大家一起聊了聊AppBarLayout和CoordinatorLayout两个新控件,以及CoordinatorLayout与FloatingActionButton、Snackbar的使用注意事项。至此,Android Material Design系列的学习已进行到第五篇,大家可以点击以下链接查看之前的文章:
- Android TabLayout 分分钟打造一个滑动标签页
- Android 一文告诉你到底是用Dialog,Snackbar,还是Toast
- Android FloatingActionButton 重要的操作不要太多,一个就好
- Android 初识AppBarLayout 和 CoordinatorLayout
本文继续以案例的形式学习CoordinatorLayout的使用,配合者为AppBarLayout。文中会介绍一些这种搭配使用的案例下可能出现的问题以及解决方案,目的还是一句话,将我所知的分享出来,让正在摸索的你少走一些弯路。老路子,先看一下本文要实现的效果图:
Samples.gif简单介绍下,这种设计经常会出现在各个app中,作为主页显示,其中主要包含了三个效果:
-
侧拉导航菜单,这个是用v7包中的控件DrawerLayout实现的,不是本文重点,就不作过多说明了;
-
FAB与Snackbar的协调交互,在上篇文章中已经介绍的很详细了,大家可以另行查看;
-
列表向上滑动,Toolbar向上隐藏,TabLayout固定于顶部,给内容区域留下更多的展示空间,本文着重讲述这种实现。
知识点比较零碎,还是配合着代码讲解比较容易,思路也会比较清晰一些,主要布局文件的实现:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/dl_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/include_toolbar" />
<android.support.design.widget.TabLayout
android:id="@+id/tl_indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vp_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_16"
android:onClick="onClickFab"
android:src="@mipmap/ic_toolbar_add"
app:backgroundTint="@color/fab_ripple"
app:layout_anchor="@id/vp_content"
app:layout_anchorGravity="bottom|right|end" />
</android.support.design.widget.CoordinatorLayout>
<LinearLayout
android:id="@+id/ll_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:orientation="vertical"
android:gravity="center"
android:background="@color/white">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Menu Content"
android:textColor="@color/black"
android:textSize="@dimen/sp_16"/>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
Android Developer官网中在介绍CoordinatorLayout时有这么一段话:
CoordinatorLayout is intended for two primary use cases:
- As a top-level application decor or chrome layout
- As a container for a specific interaction with one or more child views
也就是说CoordinatorLayout主要有两种使用场景,在我理解过来就是,作为Activity布局中的最外层容器和作为指定交互行为的多个子控件的父容器来使用。而本文中的案例就属于第二种。
要实现这种滑动交互效果,必须要满足这么几点:
-
CoordinatorLayout作为容器布局,来协调children view之间的交互行为;
-
使用AppBarLayout并设置其内部需要移出屏幕的View的scrollFlags属性,在这个例子中也就是给Toolbar设置。由于Toolbar是通用布局代码,这里我用了include标签,其包含的布局代码为:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tb_toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_56"
app:titleTextColor="@color/white"
app:title="@string/app_name"
app:theme="@style/OverFlowMenuTheme"
app:popupTheme="@style/AppTheme"
android:background="@color/blue"
app:layout_scrollFlags="scroll|enterAlways"/>
可以看到,我添加了app:layout_scrollFlags
这个属性,并将其值设为scroll|enterAlways
,scroll
表示滑动型控件向上滑动时toolbar将移出屏幕,enterAlways
表示向下滑动时toolbar将重新进入屏幕。由于TabLayout不需要移出屏幕,所以这里就不需要给它设置这个属性了。需要注意的是:不要将app:layout_scrollFlags
属性单独设置子include标签里,而是要放在include所加载的layout布局中,否则这个scrollFlags将失去作用,这与include标签的使用有关。
- 一个特殊的滑动型控件并设置
layout_behavior
属性,这里用的是ViewPager。注意,layout_behavior
的属性值用的是系统定义好的固定字符串@string/appbar_scrolling_view_behavior
,大家感兴趣的自己去翻阅源码看看,后续介绍behavior时,我再仔细讲解。
对于第三点,这里拿出来单独强调一下,有没有发现滑动型控件前我用了“特殊”两个字来修饰!CoordinatorLayout之所以能够协调Children View之间的交互行为,主要就是依赖于NestedScrolling
这个东西,这里涉及到两个接口类NestedScrollingParent
和NestedScrollingChild
。CoordinatorLayout实现了前者,而CoordinatorLayout的Children核心之一,滑动型控件,实现了后者,所以才能够做出这个交互行为。关于NestedScrolling
,后续再写文单独介绍。所以,这个特殊的滑动型控件必须是实现了NestedScrollingChild
接口的控件,比如v7包中的RecyclerView,看一下它的定义就知道了:
public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild
故,本文中的ViewPager里面的列表控件必须是RecyclerView。如果你仅仅是简单地使用ListView,还是达不到这样的效果。聪明如你,肯定又看出了我的措辞,对的,我又用了一个词:“简单地使用”,那就说明其实稍作处理,复杂点使用,也能够使用ListView的。
在API Level 21及更高版本,为了支持NestedScrolling
,所有控件的基类View对外新增了一个方法setNestedScrollingEnabled(boolean enabled)
,所以,我们可以对ListView稍作处理,就能在Android L及以上版本的系统中使用了:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
listView.setNestedScrollingEnabled(true);
}
或者借助 v4 包中的 ViewCompat
类为 ListView 添加设置,避免版本判断:
ViewCompat.setNestedScrollingEnabled(listView, true);
但是,这两种方法均只支持 Android Lollipop 及更高版本,在 pre-lollipop 上是没有效果的。其实,ListView真的已经过气了,我们应该全方位掌握RecyclerView的使用,就像Android Studio取代Eclipse一样。
其他的代码就很简单了,就是给DrawerLayout设置ActionBarDrawerToggle
,就是图中ToolBar左侧的菜单按钮。然后用Fragment填充ViewPager,这里就不贴代码了,工程Demo都在GitHub上,大家可以自己下载参考。
其实这个案例的实现还是蛮简单的,文中零零碎碎地讲述了很多使用过程中的细节技巧,帮助大家解决实际问题。下篇文章继续使用案例,介绍CoordinatorLayout的使用方法,同时引入另一个控件的使用,欢迎关注!
示例源码
我在GitHub上建立了一个Repository,用来存放整个Android Material Design系列控件的学习案例,会伴随着文章逐渐更新完善,欢迎大家补充交流,Star地址: