目标
本篇是RecyclerView的重构之路系列文章的第五篇, 讲解的是IDouban项目 电影详情界面展示以及相关控件的使用:CollapsingToolbarLayout
, CoordinatorLayout
, AppBarLayout
, Toolbar
效果动图
注意,其中这些转场动画效果以及详情信息界面动画效果,都是Android MD(Material Design)
自带的动画效果。只需要几个步骤就能实现。
实现步骤
本篇重点有2个, 如gif图展示
1 上下滑动隐藏&显示图片
2 点击 泰山归来 Item后的动画效果
在讲解具体的步骤之前,先来简单看下上述几个控件说明。
控件说明
CoordinatorLayout
/**
* CoordinatorLayout is a super-powered {@link android.widget.FrameLayout FrameLayout}.
*
* <p>CoordinatorLayout is intended for two primary use cases:</p>
* <ol>
* <li>As a top-level application decor or chrome layout</li>
* <li>As a container for a specific interaction with one or more child views</li>
* </ol>
**/
CoordinatorLayout
是一个super-powered
FrameLayout, 专门应对2中case:
- 作为App或者chrome布局的顶层布局
- 作为容器,用于和某个或某几个view的相互交互
从字面意思理解,是一个协调者布局, 查看源码发现是个ViewGroup
public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent {
使用的时候跟其他控件无区别, 作为xml布局的最外层标签使用。
注意,在本作的CoordinatorLayout
中使用了 属性: fitsSystemWindows
, 至于这个有什么作用,看图可知答案。
上面的不同点是在 状态栏,
fitsSystemWindows=true
表示该CoordinatorLayout
中的内容会扩展到状态栏底部,并且状态栏变为透明。false表示不可以扩展到状态栏。
AppBarLayout
AppBarLayout is a vertical LinearLayout which implements many of the features of material designs app bar concept, namely scrolling gestures.
Children should provide their desired scrolling behavior through setScrollFlags(int) and the associated layout xml attribute:app:layout_scrollFlags.
This view depends heavily on being used as a direct child within a CoordinatorLayout. If you use AppBarLayout within a different ViewGroup, most of it's functionality will not work.
也就是说AppBarLayout
本质是线性布局, 并实现许多MD特性, 即手势滚动。需要跟CoordinatorLayout
搭配使用,否则没有效果。 在使用过程中,需要在其嵌套子类中添加 属性app:layout_scrollFlags.
Flags包括:
scroll: 所有想滚动出屏幕的view都需要设置这个flag- 没有设置这个flag的view将被固定在屏幕顶部。
enterAlways: 这个flag让任意向下的滚动都会导致该view变为可见,启用快速“返回模式”。
enterAlwaysCollapsed: 顾名思义,这个flag定义的是何时进入(已经消失之后何时再次显示)。假设你定义了一个最小高度(minHeight)同时enterAlways也定义了,那么view将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。
exitUntilCollapsed: 同样顾名思义,这个flag时定义何时退出,当你定义了一个minHeight,这个view将在滚动到达这个最小高度的时候消失。
注意一点:所有使用scroll flag的view都必须定义在没有使用scroll flag的view的前面,这样才能确保所有的view从顶部退出,留下固定的元素。
经常会听得到 ActionBar
,AppBar
, Toolbar
, 这里给出官方的说明。
ActionBar
历史的产物, Android 3.0 Android
推了 ActionBar
这个控件, 可以简单理解为顶部标题栏。可以显示标题,菜单以及图片 Logo之类的。有自己一套的写法,但是google在推出MD设计之后就慢慢抛弃了这种设计。
AppBar
换了马甲,叫AppBar
, 来看下App Bar
的MD结构图。注意App Bar
仅仅是MD概念上的东西, SDK里是没有AppBar这个类的。
The app bar, formerly known as the action bar in Android, is a special kind of toolbar that’s used for branding, navigation, search, and actions.
The nav icon at the left side of the app bar can be:
- A control to open a navigation drawer.
- An up arrow for navigating upward through your app’s hierarchy.
- Omitted entirely if no navigation is required from this screen.
The title in the app bar reflects the current page. It can be an app title, page title, or a page filter.
Icons on the right side of the app bar are app-related actions. The menu icon opens the overflow menu, which contains secondary actions and menu items like help, settings, and feedback.
Toolbar
可能大家会混淆 AppBar
& Toolbar
, 如上所说,AppBar
是MD概念上的东西,而不是实实在在存在的类(相关布局类是AppBarLayout.java), Toolbar
才是实体类上替代ActionBar
的类。
A standard toolbar for use within application content.
A Toolbar is a generalization of {@link ActionBar action bars} for use
within application layouts. While an action bar is traditionally part of an
{@link android.app.Activity Activity's} opaque window decor controlled by the framework,
a Toolbar may be placed at any arbitrary level of nesting within a view hierarchy.
An application may choose to designate a Toolbar as the action bar for an Activity
using the {@link android.support.v7.app.AppCompatActivity#setSupportActionBar(Toolbar)
setSupportActionBar()} method.
简单一点, 以前是用ActionBar
来做,现在使用AppBarLayout
+ ToolBar
来做,而且能实现更加丰富、酷炫的效果。
参考:
AppBarLayout
Android的材料设计兼容库
ToolBar详解(手把手教程)强烈推荐
实现目标(一) 上下滑动隐藏、显示图片
对应的实体效果如下:
详细xml 01
<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:layout_width="match_parent"
android:layout_height="256dp"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/movie_collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/movie_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:transitionName="cover"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7" />
<android.support.v7.widget.Toolbar
android:id="@+id/movie_toolbar"
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.design.widget.CoordinatorLayout>
上述布局,挨个看:
CoordinatorLayout
以及 属性 android:fitsSystemWindows="true"
已经说明。
AppBarLayout
它是什么,前文做了说明。它如何使用,这里嵌套控件: CollapsingToolbarLayout
, 一个可以伸缩的控件。这里需要注意,android:layout_height="256dp"
高度就是前文图片中的红色部分,可以按照自己需求调整。注意theme
的选择。
CollapsingToolbarLayout
/**
* CollapsingToolbarLayout is a wrapper for {@link Toolbar} which implements a collapsing app bar.
* It is designed to be used as a direct child of a {@link AppBarLayout}.
* CollapsingToolbarLayout contains the following features:
... ...
**/
要实现可折叠的效果, 需要使用到CollapsingToolbarLayout
, 其中嵌套2个View
, ImageView
, Toolbar
。
注意其中的属性:
app:contentScrim="?attr/colorPrimary", 这个表示
AppBarLayout
滑动过程中, 标题栏的颜色, 如修改为app:contentScrim="#00ff00", 测试结果会变成绿颜色。app:expandedTitleMarginStart="48dp", 表示,
AppBarLayout
展开后, 标题左边距的大小。app:layout_scrollFlags="scroll|exitUntilCollapsed", 此属性必须要有。已经在上述 讲解AppBarLayout有过说明。
app:layout_collapseMode="parallax", 折叠模式是视差模式, 并且设置视差因子为0.7
这个怎么理解呢?
最大区别在于,有视差的,上滑过程中,电影海报中的“泰山归来”是慢慢被覆盖的效果。而没有视差的,上滑过程中, 电影海报是整体往上慢慢顶出去。
详细xml 02
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.design.widget.TabLayout
android:id="@+id/movie_sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabMode="fixed" />
<android.support.v4.view.ViewPager
android:id="@+id/movie_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
以上xml是电影详情界面的下部分内容, 主要是TabLayout
& ViewPager
。 那其中关键的属性是:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
, 这是CoordinatorLayout
内嵌套中必须要有的属性, 这里使用默认的behavior。
CoordinatorLayout并不知道FloatingActionButton或者AppBarLayout的内部工作原理 - 它只是以Coordinator.Behavior的形式提供了额外的API,该API可以使子View更好的控制触摸事件与手势以及声明它们之间的依赖,并通过onDependentViewChanged()接收回调。
可以使用 CoordinatorLayout.DefaultBehavior(你的View.Behavior.class)注解或者在布局中使用app:layout_behavior="com.example.app.你的View$Behavior"属性来定义view的默认行为。framework让任意view和CoordinatorLayout结合在一起成为了可能。
实现目标(二) 点击电影某个Item后的动画效果
这个是什么呢? MD现在提供了Activity之间一种顺滑过度动画。仔细看动图。
当点击泰山归来这部电影, 在跳转之前,电影图片会扩展到整个界面上部分,当扩展完成的时候,就顺畅转到电影详情界面。这个效果该如何实现呢?
上文,在讲解到 CollapsingToolbarLayout
的时候,有意忽略了 android:transitionName="cover"
这个就是我们的女主角, 属性android:transitionName
表示我们使用过渡动画的名称,cover
随意取。 这里使用的是MD中的 共享元素的过渡。
在跳转代码中需要添加如下代码:
Intent intent = new Intent(context, MovieDetailActivity.class);
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, mMovieImage, "cover").toBundle();
ActivityCompat.startActivity(activity, intent, bundle);
都知道启动某个Activity
方法很简单, startActivity(Intent intent)
, 但是要有MD那样的转场动画,启动方式,需要按照上述代码编写。其中, ActivityCompat, ActivityOptionsCompat
是为了向下兼容, 也可以考虑使用ActivityOptions
; makeSceneTransitionAnimation
方法中的参数:
public static ActivityOptionsCompat makeSceneTransitionAnimation(Activity activity,
View sharedElement,
String sharedElementName)
{... ...}
sharedElement
表示需要共享动画的view, 这里是电影海报Imageview
, sharedElementName
对应在电影详情界面的布局文件中属性value。
<ImageView
android:id="@+id/movie_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:transitionName="cover" />
详细的可以参考这篇blog:Android 5.0学习之Activity过渡动画
github代码
欢迎大家fork IDouban源码,觉得好,顺手点下星星。嗯,让我有动力完成这系列的文章。
参考文档
AppBarLayout
Android的材料设计兼容库
ToolBar详解(手把手教程)强烈推荐
Android 5.0学习之Activity过渡动画
Demos the new Android Design library
Android 官方开发者blog