×

AndroidStudyDemo之Android6.x新控件介绍(三)

96
diygreen
2016.04.23 22:52* 字数 2788
Android6.x介绍(三)

作者:李旺成

时间:2016年4月23日


接上篇:AndroidStudyDemo之Android6.x新控件介绍(二)

六、CoordinatorLayout

先看效果:

CoordinatorLayout 效果演示

简介

CoordinatorLayout 命名中带有协调的意思,它的作用正是协调(Coordinate)其他组件, 实现联动,CoordinatorLayout 实现了多种 Material Design 中提到的滚动效果。

  • 超级 FrameLayout
  • CoordinatorLayout 使用新的思路通过协调调度子布局的形式实现触摸影响布局的形式产生动画效果
  • 提供了几种不用写动画代码就能工作的动画效果,如下:
    1.让浮动操作按钮上下滑动,为Snackbar留出空间
    2.扩展或者缩小 Toolbar 或者头部,让主内容区域有更多的空间
    3.控制哪个 View 应该扩展还是收缩,以及其显示大小比例,包括视差滚动效果动画

看下官方的介绍:

CoordinatorLayout 类

上图圈出了几个关键点,有两个相对来说“较新的概念”,从这看出 CoordinatorLayout 控件可能比较复杂的,不过不用着急,我们可以抽丝剥茧,逐步深入的去学习它。

CoordinatorLayout 继承自 ViewGroup,官方介绍的第一句话就是:“CoordinatorLayout is a super-powered FrameLayout .”。从继承结构来看,收获不大,不过有个地方要注意,那就是它实现了一个接口:NestedScrollingParent

简单介绍下 NestedScrolling

在 Android L 中提供了一套 API 来支持嵌套(或者说嵌入)的滑动效果(Support V 4 提供了兼容 API),可以称之为嵌套滑动机制(NestedScrolling)。通过 NestedScrolling,能实现很多很复杂的滑动效果。

NestedScrolling 提供了一套父 View 和子 View 滑动交互机制。要完成这样的交互,父 View 需要实现 NestedScrollingParent 接口,而子 View 需要实现 NestedScrollingChild 接口。

关于 NestedScrolling,有兴趣的可以去看看这篇文章:Android NestedScrolling 实战,这里就不展开了。

CoordinatorLayout 实现了 NestedScrollingParent 接口,其包裹的子控件如果要想能更好的配合 CoordinatorLayout,就需要实现 NestedScrollingChild 接口。

简单使用

1、Snackbar 与 FAB 浮动效果
先看效果:

Snackbar 与 FAB 浮动效果

上图演示的效果,可以说是 CoordinatorLayout 最简单的一种使用了。

Snackbar 一般出现在屏幕的底部,这容易覆盖住靠近底部的 FAB(FloatingActionButton)。为了给 Snackbar 留出空间,FAB 需要向上移动。

实现这种效果很简单(其实在 Snackbar 中已经用了,这里再稍微说两句),只要将 FAB 放到 CoordinatorLayout 布局中,FAB 就将自动产生向上移动的动画。FAB 有一个默认的 behavior来检测 Snackbar 的添加并让按钮在 Snackbar 之上呈现上移与 Snackbar 等高的动画。

看代码:

<?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:id="@+id/cl_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- 任何其他布局 -->
    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:layout_margin="16dp"
        android:clickable="true"
        android:onClick="onClick"
        android:src="@mipmap/ic_check_white"
        app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>
// 点击回调
public void onClick(View v) {
    Snackbar snackbar = Snackbar.make(mRootCL,
            "我是普通 Snackbar", Snackbar.LENGTH_SHORT);
    snackbar.show();
}

2、Toolbar 的显示与隐藏
先看效果:

Toolbar 的显示与隐藏效果

为了让 Toolbar 能够响应滚动事件,这里要用到一个新控件 AppBarLayout,该控件会在下面介绍,这里先不讨论,直接用。

来看 Layout 中是如何使用的:

<?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:id="@+id/cl_root"
    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"
        android:theme="@style/ThemeOverlay.AppCompat">
        <android.support.v7.widget.Toolbar
            android:id="@+id/tb_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways" />
    </android.support.design.widget.AppBarLayout>
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_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:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:layout_margin="16dp"
        android:clickable="true"
        android:onClick="onClick"
        android:src="@mipmap/ic_check_white"
        app:layout_anchor="@id/rv_content"
        app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>

首先,让 AppBarLayout 作为 CoordinatorLayout 的第一个子 View,将 Toolbar 包裹在其中。
AppBarLayout 里面定义的 Toolbar 需要设置 app:layout_scrollFlags 属性,app:layout_scrollFlags 属性里面必须至少启用scroll 这个 flag,这样这个 View 才会滚动出屏幕,否则它将一直固定在顶部。

app:layout_scrollFlags 属性可以使用如下 flag:

  • scroll:所有想滚动出屏幕的 View 都需要设置这个 flag,没有设置这个 flag 的 View 将被固定在屏幕顶部
  • enterAlways:一旦向上滚动这个 View 就可见,这个 flag 让任意向下的滚动都会导致该 View 变为可见,启用快速“返回模式”
  • enterAlwaysCollapsed:顾名思义,这个 flag 定义的是何时进入(已经消失之后何时再次显示)。假设你定义了一个最小高度(minHeight)同时 enterAlways 也定义了,那么 View 将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完
  • exitUntilCollapsed:同样顾名思义,这个 flag 定义何时退出,当你定义了一个 minHeight,这个 View 将在滚动到达这个最小高度的时候消失。

特别注意:所有使用 scroll flag 的 View 都必须定义在没有使用 scroll flag 的 View 前面,这样才能确保所有的 View 从顶部退出,留下固定的元素。

PS:CoordinatorLayout 还提供了 layout_anchor 和 layout_anchorGravity 属性一起配合使用,可以用于放置 floating view,比如FloatingActionButton 与其他 View 的相对位置。
(参考自:Android应用Design Support Library完全使用实例

然后,定义 AppBarLayout 与 RecyclerView 之间的联系(可以使用任意支持嵌套滚动的 View 都可以,在这里使用了 RecyclerView 来演示)。在 RecyclerView 中添加属性 app:layout_behavior。

support library 包含了一个特殊的字符串资源 @string/appbar_scrolling_view_behavior,它和 AppBarLayout.ScrollingViewBehavior 相匹配,用来通知 AppBarLayout 这个特殊的 View 何时发生了滚动事件,这个 Behavior 需要设置在触发事件(滚动)的 View 之上。
(参考自:Android应用Design Support Library完全使用实例

最后,其实在完成上面两步之后,就已经完成了 Toolbar 随着 RecyclerView 显示隐藏的功能,剩下的就只需要为 RecyclerView 填充数据即可:

private void initData() {
    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(OrientationHelper.VERTICAL);
    // 设置布局管理器
    mContentRV.setLayoutManager(layoutManager);
    ArrayList dataList = new ArrayList<>(100);
    for (int i = 0; i < 100; i++) {
        dataList.add("DIY-ITEM:" + i);
    }
    RecyclerAdapter adapter = new RecyclerAdapter(dataList);
    mContentRV.setAdapter(adapter);
}

为了使 Toolbar 有滑动效果,必须做到如下三点:

  1. CoordinatorLayout 作为布局的父布局容器
  2. 给需要滑动的组件设置 app:layout_scrollFlags=”scroll|enterAlways” 属性
  3. 给滑动的组件设置 app:layout_behavior 属性
    (参考自:android CoordinatorLayout使用

小结

CoordinatorLayout 还可以结合其他控件实现很多很炫的效果,接下来要介绍的这两个控件就需要和 CoordinatorLayout,所以,这里不继续展开 CoordinatorLayout 的相关内容了。

七、AppBarLayout

先看效果:

AppBarLayout 效果演示1
AppBarLayout 效果演示2

简介

AppBarLayout 是 Design Support Library 中提供的一个容器控件,是为了 Material Design 设计的 App Bar。

  • MD风格的滑动Layout
  • 把容器内的组件全部作为 AppBar
  • 就是一个 纯容器类,配合 ToolBar 与 CollapsingToolbarLayout 等使用

看下官方介绍:

AppBarLayout 类

继承自 LinearLayout,并且默认是垂直方向的 —— “ AppBarLayout is a vertical LinearLayout ...”。从官方的示例代码中可以看到,它的使用方式和 LinearLayout 没什么区别。

那看看它的属性:

AppBarLayout 属性

注意属性介绍里面的这句话:This only takes effect when this view is a direct child of a CoordinatorLayout.

也就是说 AppBarLayout 必须是第一个嵌套在 CoordinatorLayout 里面的子View,该属性才能起作用(-_-',貌似示例代码就不是这样的,这要闹哪样...)。

简单使用

1、单独使用
单独使用,把它当作 LinearLayout 就可以了,来看下效果:

AppBarLayout 直接使用效果

当 RecyclerView 滑动的时候,Toolbar 并没有任何反应。AppBarLayout 与 LinearLayout 在这里没什么区别,所以一般也不会单独使用 AppBarLayout。

上代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/rl_root"
    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"
        android:theme="@style/ThemeOverlay.AppCompat">
        <android.support.v7.widget.Toolbar
            android:id="@+id/tb_title"
            app:layout_scrollFlags="scroll|enterAlways"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:minHeight="?attr/actionBarSize" />
        <android.support.design.widget.TabLayout
            android:id="@+id/tl_tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </android.support.design.widget.AppBarLayout>
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/appbar" />
    <android.support.design.widget.FloatingActionButton
        app:layout_anchor="@id/rv_content"
        app:layout_anchorGravity="bottom|right|end"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="16dp"
        android:clickable="true"
        android:onClick="onClick"
        android:src="@mipmap/ic_check_white" />
</RelativeLayout>

2、CoordinatorLayout 与 AppBarLayout配合
先看效果:

CoordinatorLayout与AppBarLayout配合
Toolbar与TabLayout都隐藏

与 1、 中的效果对比,可以发现 AppBarLayout 中的控件可以随着 RecyclerView 的滑动而显示或隐藏。代码和简单:

<?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:id="@+id/cl_root"
    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"
        android:theme="@style/ThemeOverlay.AppCompat">
        <android.support.v7.widget.Toolbar
            android:id="@+id/tb_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways" />
        <android.support.design.widget.TabLayout
            android:id="@+id/tl_tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </android.support.design.widget.AppBarLayout>
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_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:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:layout_margin="16dp"
        android:clickable="true"
        android:onClick="onClick"
        android:src="@mipmap/ic_check_white"
        app:layout_anchor="@id/rv_content"
        app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>

在 Java 代码里面没什么可说的,这里就不列代码了,有需要的可从文末链接自行下载 Demo。

注意: AppBarLayout 中的子控件必须设置了 app:layout_scrollFlags 属性,而且该属性至少设置了 ”scroll“(原因前面说过),才有可能实现随着 RecyclerView 的滑动而显示隐藏。

注意事项

  1. 注意 AppBarLayout 的 expanded 属性的使用特性
  2. 就是 ”六、“ 中所讲的,为了使 Toolbar 有滑动效果,必须做到那三点。这里就不再赘述,该控件的使用还是很简单的。

八、CollapsingToolbarLayout

先看看效果:

CollapsingToolbarLayout 使用演示
官方的实例

简介

CollapsingToolbarLayout,从名称上来看这是一个可折叠的 Toolbar 布局,确实名副其实。它可以控制包含在其内部的控件(如:ImageView、Toolbar)在响应 layout_behavior 事件时作出相应的 scrollFlags 滚动事件(移除屏幕或固定在屏幕顶端),形成各种视觉效果。

  • 可折叠MD风格ToolbarLayout
  • 可以折叠的Toolbar

来看看官方的介绍:

CollapsingToolbarLayout 类

继承自 Framelayout,这个哥们最近出镜率很高啊!文档上说,CollapsingToolbarLayout 是 Toolbar 的一个”包装“。不翻译文档了,Framelayout 很熟悉了,但作用不大,来看看 CollapsingToolbarLayout 提供的属性。

CollapsingToolbarLayout 属性

文档基本解释了,这里先不多说,先用起来。

简单使用

Toolbar 的折叠效果

先看效果:

折叠效果

要实现上述效果比较简单,主要是在布局中设置:

<?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:id="@+id/cl_root"
    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="150dp"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat">
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/ctl_title"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:title="DIY-Green"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="46dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
            <android.support.v7.widget.Toolbar
                android:id="@+id/tb_title"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_scrollFlags="scroll|enterAlways"/>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>

首先,使用 CollapsingToolbarLayout 包裹 Toolbar。
然后,设置 CollapsingToolbarLayout 的app:layout_scrollFlags 属性,如 "scroll|exitUntilCollapsed"。

注意,Title 要在 CollapsingToolbarLayout 上设置,而不能在 Toolbar 中设置了。

视差效果

先看效果:

视差效果1
视差效果2

这个效果看起挺炫的,其实也不难,看代码就明白了:

<?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:id="@+id/cl_root"
    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="240dp"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat">
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/ctl_title"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="46dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                android:src="@mipmap/bg_drawer_header"
                app:layout_collapseMode="parallax" />
            <android.support.v7.widget.Toolbar
                android:id="@+id/tb_title"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_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:layout_height="wrap_content"
        android:layout_width="wrap_content"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|right|end"
        android:src="@mipmap/ic_check_white"
        android:layout_margin="@dimen/activity_horizontal_margin"
        android:clickable="true"/>
</android.support.design.widget.CoordinatorLayout>

如示例中所示,为了图片在折叠的时候淡入淡出的效果,需要设置 app:layout_collapseMode 属性为 "parallax"。

CoordinatorLayout 还提供了一个 layout_anchor 的属性,连同 layout_anchorGravity 一起,可以用来放置与其他视图关联在一起的悬浮视图(如 FloatingActionButton)。(参考自:android CoordinatorLayout使用

小结

CoordinatorLayout 还有很多很炫的功能有待挖掘,这里不打算深入探讨了。还有一个比较重要的类没有介绍,那就是 Behavior,系统提供了一些 Behavior,我们也可以自定义。打算在讨论动画的时候再好好介绍下 Behavior,CoordinatorLayout 的介绍就到这里了。

对 Android 6.x 的新控件介绍就到这里了。关于有些控件可能不是 Android 6.x 提供这个问题,我这里想稍微说一下。请大家不要在意这些细节,写这一系列文章,我的初衷是想提供一个简明的示例供大家参考,能达到这个目的就足够了。本人能力和时间有限,不足和疏漏之处在所难免,请见谅。

项目地址

GitHub

附件

Andoid6思维导图

参考

CoordinatorLayout与滚动的处理
android CoordinatorLayout使用
Snackbar
浮动操作按钮
默认的 behavior
CoordinatorLayout 与浮动操作按钮
Android NestedScrolling 实战
Android Design Support Library使用详解
Android Material Design:CoordinatorLayout与NestedScrollView
Android Material Design:基于CoordinatorLayout实现向上滚动导航条ToolBar滚出、向下滚动导航条滚出
android CoordinatorLayout使用

AndroidStudyDemo系列
Web note ad 1