CoordinatorLayout解析

简介: CoordinatorLayout作为“super-powered FrameLayout”基本实现两个功能: 1、作为顶层布局 2、调度协调子布局CoordinatorLayout使用新的思路通过协调调度子布局的形式实现触摸影响布局的形式产生动画效果。
CoordinatorLayout作为“super-powered FrameLayout”基本实现两个功能: 
1、作为顶层布局 
2、调度协调子布局

CoordinatorLayout使用新的思路通过协调调度子布局的形式实现触摸影响布局的形式产生动画效果。CoordinatorLayout使用的时候通常和AppBarLayout搭配使用。在AppBarLayout里面的View,通过app:layout_scrollFlags属性来控制滚动时候的表现,其中有4种Flag的类型:
 
  
  1. scroll: 所有想滚动出屏幕的view都需要设置这个flag,没有设置这个flag的view将被固定在屏幕顶部。例如,TabLayout 没有设置这个值,将会停留在屏幕顶部。
  2. enterAlways: 设置这个flag时,向下的滚动都会导致该view变为可见,启用快速“返回模式”。
  3. enterAlwaysCollapsed: 这个flag定义的是何时进入(已经消失之后何时再次显示)。当你的视图已经设置minHeight属性又使用此标志时,你的视图只能在到达这个最小高度的时候开始显示,只有当滚动视图到达顶部时才扩大到完整高度。
  4. exitUntilCollapsed: 当你定义了一个minHeight,这个view将在滚动到达这个最小高度的时候消失。
系统(Support V7)提供了AppBarLayout.Behavior、 AppBarLayout.ScrollingViewBehavior,、FloatingActionButton.Behavior和SwipeDismissBehavior<V extends View> 等。

使用CoordinatorLayout需要在Gradle加入Support Design Library,例如:

compile 'com.android.support:design:22.2.1'
CoordinatorLayout实现了多种Material Design中提到的滚动效果。目前这个框架提供了几种不用写动画代码就能工作的方法,这些效果包括:

一、CoordinatorLayout与FloatingActionButton让浮动操作按钮上下滑动,为Snackbar留出空间

FloatingActionButton是最简单的使用CoordinatorLayout的例子,FloatingActionButton默认使用FloatingActionButton.Behavior。
CoordinatorLayout可以用来配合浮动操作按钮的 layout_anchor 和 layout_gravity属性创造出浮动效果。

只要使用CoordinatorLayout作为基本布局,将自动产生向上移动的动画。浮动操作按钮有一个 默认的 behavior来检测Snackbar的添加并让按钮在Snackbar之上呈现上移与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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".activity.MainActivity1">

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
CoordinatorLayout作为“super-powered FrameLayout”,设置子视图的 android:layout_gravity属性控制位置。

MainActivity.java如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main1);

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab_main1);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

Snackbar.make(view, "FAB", Snackbar.LENGTH_LONG)
.setAction("cancel", new View.OnClickListener() {
@Override
public void onClick(View v) {
//这里的单击事件代表点击消除Action后的响应事件
}
})
.show();
}
});

}

效果如下:


二、CoordinatorLayout与AppBarLayout

2.1使用ToolBar
为了ToolBar可以滚动,我们必须使用容器布局 AppBarLayout来让Toolbar响应滚动事件。然后,我们需要定义AppBarLayout与滚动视图之间的联系。在RecyclerView或者任意支持嵌套滚动的view比如NestedScrollView上添加app:layout_behavior。support library包含了一个特殊的字符串资源@string/appbar_scrolling_view_behavior,它和AppBarLayout.ScrollingViewBehavior相匹配,用来通知AppBarLayout 这个特殊的view何时发生了滚动事件,这个behavior需要设置在触发事件(滚动)的view之上。
布局文件:
<?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"
tools:context=".activity.MainActivity2">

<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_main2"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />


</android.support.design.widget.AppBarLayout>

<android.support.v7.widget.RecyclerView
android:id="@+id/recycle_main2"
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_main2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
当CoordinatorLayout发现RecyclerView中定义了这个属性,它会搜索自己所包含的其他view,看看是否有设置了app:layout_scrollFlags属性与这个 behavior相关联。AppBarLayout.ScrollingViewBehavior描述了RecyclerView与 AppBarLayout之间的依赖关系。RecyclerView的任意滚动事件都将触发AppBarLayout或者AppBarLayout里面 view的改变。
AppBarLayout里面定义的view只要设置了app:layout_scrollFlags属性,就可以在RecyclerView滚动事件发生的时候被触发:
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_main2"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />


</android.support.design.widget.AppBarLayout>
app:layout_scrollFlags属性里面必须至少启用scroll这个flag,这样这个view才会滚动出屏幕,否则它将一直固定在顶部。

Activity类如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_main2);
setSupportActionBar(toolbar);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycle_main2);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(linearLayoutManager);
String[] titles = new String[20];
for (int i = 0; i < 20; i++)
titles[i] = "item " + i;

mAdapter=new RecyclerViewAdapter(this,titles);
recyclerView.setAdapter(mAdapter);

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab_main2);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

Snackbar.make(view, "FAB", Snackbar.LENGTH_LONG)
.setAction("cancel", new View.OnClickListener() {
@Override
public void onClick(View v) {
//这里的单击事件代表点击消除Action后的响应事件

}
})
.show();
}
});

}
效果如下:


2.2 AppBarLayout嵌套TabLayout
下面的例子用的是ViewPager,切记带有滚动属性的View需要设置app:layout_behavior属性。
support library包含了一个特殊的字符串资源@string/appbar_scrolling_view_behavior,它和AppBarLayout.ScrollingViewBehavior相匹配,用来通知AppBarLayout 这个特殊的view何时发生了滚动事件,这个behavior需要设置在触发事件(滚动)的view之上。而AppBarLayout里面定义的view只要设置了app:layout_scrollFlags属性,就可以在滚动事件发生的时候被触发。同时注意:根据官方的谷歌文档,AppBarLayout目前必须是第一个嵌套在CoordinatorLayout里面的子view。

布局文件:

<?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"
tools:context=".activity.MainActivity">

<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:popupTheme="@style/AppTheme.PopupOverlay"
app:layout_scrollFlags="scroll|enterAlways"/>

<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
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"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
具体代码就不再写了,想看的可以下载源码,效果如下:


2.3 AppBarLayout嵌套CollapsingToolbarLayout


CollapsingToolbarLayout还能让我们做出更高级的动画,比如在里面放一个ImageView,然后在它折叠的时候渐渐淡出。同时在用户滚动的时候title的高度也会随着改变。

<?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"
tools:context=".activity.MainActivity4">

<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">

<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@mipmap/smile"
app:layout_collapseMode="parallax" />

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_main4"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
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/recycle_main4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />


<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_main4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
 
     

现在效果就成了:

+
 
       

为了制造出这种效果,我们添加一个定义了app:layout_collapseMode="parallax" 属性的ImageView.

这种效果在详情页面用的较多,展示个性化内容,图像有强烈的吸引力。这个效果重点使用了CollapsingToolbarLayout 。
CollapsingToolbarLayout 提供以下属性和方法使用:

1. Collapsing title:ToolBar的标题,当CollapsingToolbarLayout全屏没有折叠时,title显示的是大字体,在折叠的过程中,title不断变小到一定大小的效果。通常,我们都是设置Toolbar的title,而现在,我们需要把title设置在CollapsingToolBarLayout上,而不是Toolbar。你可以调用setTitle(CharSequence)方法设置title。
2. Content scrim:ToolBar被折叠到顶部固定时候的背景,你可以调用setContentScrim(Drawable)方法改变背景或者 在属性中使用 app:contentScrim=”?attr/colorPrimary”来改变背景。
3. Status bar scrim:状态栏的背景,调用方法setStatusBarScrim(Drawable)。还没研究明白,不过这个只能在Android5.0以上系统有效果。
4. Parallax scrolling children:CollapsingToolbarLayout滑动时,子视图的视觉差,可以通过属性 app:layout_collapseParallaxMultiplier=”0.6”改变。值de的范围[0.0,1.0],值越大视察越大。
5. CollapseMode :子视图的折叠模式,在子视图设置,有两种“pin”:固定模式,在折叠的时候最后固定在顶端;“parallax”:视差模式,在折叠的时候会有个视差 折叠的效果。我们可以在布局中使用属性app:layout_collapseMode=”parallax”来改变。


三、自定义Behavior

CoordinatorLayout功能之所以如此强大,就在于Behavior对象,这个Behavior用于当滚动发生的时候让AppBarLayout发生改变。CoordinatorLayout自己并不控制View, 所有的控制权都在Behavior。前面写到了 FloatingActionButton.Behavior,AppBarLayout.Behavior, AppBarLayout.ScrollingViewBehavior。 AppBarLayout中有两个Behavior,一个是拿来给它自己用的,另一个是拿来给它的兄弟结点用的。这些Behavior实现了复杂的控制功能。但系统的Behavior毕竟有限,我们可以通过自定义的方式来实现自己的Behavior。
通过 CoordinatorLayout.Behavior(YourView.Behavior.class) 来定义自己的Behavior,并在layout 文件中设置 app:layout_behavior=”com.example.app.YourView$Behavior” 来达到效果。
自定义Behavior 需要重写两个方法:
publicbooleanlayoutDependsOn(CoordinatorLayout parent, View child, View dependency) 
publicbooleanonDependentViewChanged(CoordinatorLayout parent, View child, View dependency)
创建一个Behavior很简单,只要继承Behavior类即可
public class CustomBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
public CustomBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
在上面这段代码中使用了范型,此时CustomBehavior可以被添加到任何View上,如果希望CustomBehavior只被添加到特定的View子类上,可以采用如下写法:
publicclassCustomBehaviorextendsCoordinatorLayout.Behavior<FloatingActionButton>
另外在Behavior的使用中,可以使用Behavior.setTag()/Behavior.getTag()来保存临时性的变量,另外也可以使用onSaveInstanceState()/onRestoreInstanceState()进行数据保存。善用这些方法可以让Behavior更具状态性。
添加Behavior
Behavior本身并不做任何事情,它们需要被添加到CoordinatorLayout的直接子类中才能被使用。主要有三种方法来将Behavior添加进子类,分别是程序中动态添加,Xml布局文件添加使用注解添加
1、程序中动态添加
CustomBehaviorcustomBehavior = new
CustomBehavior
(); CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) yourView.getLayoutParams();params.setBehavior(customBehavior);
在上面的这个例子中,我们在代码中添加了customBehavior,同时也是使用了CustomBehavior()这个构造函数,如果对CustomBehavior的构造过程需要额外的参数,可以自行重载构造函数。

2、Xml布局文件中添加
<FrameLayout
  android:layout_height=”wrap_content”
  android:layout_width=”match_parent”
  app:layout_behavior=”.CustomBehavior” />
使用layout_behavior属性进行添加可以让代码更简洁些
,属性内容是你的类名。需要注意的是使用这种方法,CustomBehavior(Context context, AttributeSet attrs)这个构造函数会被默认调用,这样我们就可以为其自定义一些xml属性,以保证其他开发者可以通过xml来修改CustomBehavior的行为。

3、使用注解添加如果你构建了一个自己的视图,并且这个视图需要一个自定义的Behavior,那么你就可以使用下面这种方式:
@CoordinatorLayout.DefaultBehavior(CustomBehavior.class) 
publicclassMyFloatingActionButton extendsFloatingActionButton{
}
使用这种方式添加的Behavior被设置成了DefaultBehavior,如果这时在Xml中使用layout_behavior的话,这个DefaultBehavior会被覆盖。

因为个人能力有限,对CoordinatorLayout的介绍就这么多吧,希望各位大神能不吝赐教


源代码

参考:



相关文章
|
24天前
|
XML Java Android开发
Android实现自定义进度条(源码+解析)
Android实现自定义进度条(源码+解析)
51 1
|
4月前
|
Android开发 容器
[Android]View的事件分发机制(源码解析)
[Android]View的事件分发机制(源码解析)
36 0
|
存储 Android开发
android ViewPager + Fragment + Tablayout 实现嵌套页面导航(二)
android ViewPager + Fragment + Tablayout 实现嵌套页面导航
android ViewPager + Fragment + Tablayout 实现嵌套页面导航(二)
|
编译器 Android开发 容器
android ViewPager + Fragment + Tablayout 实现嵌套页面导航(一)
android ViewPager + Fragment + Tablayout 实现嵌套页面导航
android ViewPager + Fragment + Tablayout 实现嵌套页面导航(一)
|
Android开发
CoordinatorLayout使用浅析
CoordinatorLayout使用浅析
190 0
CoordinatorLayout使用浅析
|
Android开发
在项目中运用使用CoordinatorLayout
在 2015 年的 I/O 开发者大会上,Google 介绍了一个新的 Android Design Support Library,该库可以帮助开发者在应用上使用 meterial design。以前在自己公司的项目上,有用过,最近把这个库中的 CoordinatorLayout单独拿出来做了个小例子写篇博文,纯粹当成整理复习笔记,下次如果需求再碰到这个,直接用上 。
2456 0
CoordinatorLayout 之深入理解
上篇在对 CoordinatorLayout 作了一些简单介绍,以了解 CoordinatorLayout 带来的一些特性和常见用途。本篇将对 CoordinatorLayout 的源码进行一些分析,以了解它的相关特性的运行原理,以及 Behavior 的执行过程。
1290 0