CoordinatorLayout自定义Behavior的简单总结
2017-02-13 16:11
423 查看
前言
CoordinatorLayout 是 Google 在 Design Support 包中提供的一个十分强大的布局视图,它可以说是Design库这种最重要的控件,虽说本质上类似于 FrameLayout,但是它允许开发者通过指定 Behavior 从而实现各种复杂的 UI 效果CoordinatorLayout与Behavior介绍
官方对CoordinatorLayout的描述:CoordinatorLayout is a super-powered FrameLayout. 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
官方对Behavior的描述:
Interaction behavior plugin for child views of CoordinatorLayout.
意思就是CoordinatorLayout是用来协调其子view们之间动作的一个父view,而Behavior就是用来给CoordinatorLayout的子view们实现交互的
注意:
使用Behavior需要注意的是 CoordinatorLayout 子视图的层级关系,如果想在子视图中使用 Behavior 进行控制,那么这个子视图一定是 CoordinatorLayout 的直接孩子,间接子视图是不具有 behavior 属性的,原因当然也很简单,behavior 是 LayoutParams 的一个属性,而间接子视图的 LayoutParams 根本不是 CoordinatorLayout 类型的
Behavior的一些重要回调方法介绍
一般自定义Behavior需要重写的几个重要方法:layoutDependsOn
/** * 表示是否给应用了Behavior 的View 指定一个依赖的布局,通常,当依赖的View 布局发生变化时 * 不管被依赖View 的顺序怎样,被依赖的View也会重新布局 * @param parent CoordinatorLayout对象 * @param child 绑定behavior的View * @param dependency 依赖的view * @return 如果child 是依赖的指定的View 返回true,否则返回false */ @Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { if (dependency != null && dependency.getId() == R.id.scrolling_header) { //do something return true; } return false; }
负责查询该 Behavior 是否依赖于某个视图,如果是则返回 true,那么之后其他操作就会围绕这个依赖视图而进行了
onDependentViewChanged
/** * 当被依赖的View 状态(如:位置、大小)发生变化时,这个方法被调用 * @param parent CoordinatorLayout对象 * @param child 绑定behavior的View * @param dependency 依赖的view * @return 当dependency发生改变,同样child也需要发生改变,这个时候需要返回true */ @Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { final float progress = Math.abs(dependency.getTranslationY() / (dependency.getHeight())); //do something return true; }
这段就是根据依赖视图进行调整的方法,当依赖视图发生变化时,这个方法就会被调用。在这里可以通过当前依赖视图的位移,计算出一个位移因数(取值 0 - 1),用该位移因数来做一些视图的位移,缩放等等的操作
onLayoutChild
//可以重写这个方法对子View 进行重新布局 @Override public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) { CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams(); if (lp.height == CoordinatorLayout.LayoutParams.MATCH_PARENT) { child.layout(0, 0, parent.getWidth(), (int) (parent.getHeight() - getDependencyViewHeight())); return true; } }
负责对被 Behavior 控制的视图进行布局,就是将 ViewGroup 的 onLayout 针对该视图的部分抽出来给 Behavior 处理。我们判断一下如果目标视图高度要填充父视图,我们就自己将其高度减去 Header View 折叠后的高度。为什么要这么做呢?因为 CoodinatorLayout 就是一个 FrameLayout,不像 LinearLayout 一样能自动分配各个 View 的高度,因此我们要自己实现大小控制
onStartNestedScroll
/** * 当coordinatorLayout 的子View试图开始嵌套滑动的时候被调用。当返回值为true的时候表明 * coordinatorLayout 充当nested scroll parent 处理这次滑动,需要注意的是只有当返回值为true * 的时候,Behavior 才能收到后面的一些nested scroll 事件回调(如:onNestedPreScroll、onNestedScroll等) * 这个方法有个重要的参数nestedScrollAxes,表明处理的滑动的方向。 * * @param coordinatorLayout 和Behavior 绑定的View的父CoordinatorLayout * @param child 和Behavior 绑定的View * @param directTargetChild * @param target * @param nestedScrollAxes 嵌套滑动 应用的滑动方向,看 {@link ViewCompat#SCROLL_AXIS_HORIZONTAL}, * {@link ViewCompat#SCROLL_AXIS_VERTICAL} * @return */ @Override public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; }
用户按下手指时触发,询问 NSP 是否要处理这次滑动操作,如果返回 true 则表示“我要处理这次滑动”,如果返回 false 则表示“我不 care 你的滑动,你想咋滑就咋滑”,后面的一系列回调函数就不会被调用了。它有一个关键的参数,就是滑动方向,表明了用户是垂直滑动还是水平滑动,本例子只需考虑垂直滑动,因此判断滑动方向为垂直时就处理这次滑动,否则就不 care
onNestedPreScroll
/** * 嵌套滚动发生之前被调用 * 一般可以用来处理向上滑动时的逻辑 * @param coordinatorLayout * @param child * @param target * @param dx 用户水平方向的滚动距离 * @param dy 用户竖直方向的滚动距离 * @param consumed 消费距离,[0]为水平距离,[1]为垂直距离 */ @Override public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) { super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); }
在nested scroll child 消费掉自己的滚动距离之前,嵌套滚动每次被nested scroll child更新都会调用onNestedPreScroll。注意有个重要的参数consumed,可以修改这个数组表示你消费了多少距离。假设用户滑动了100px,child 做了90px 的位移,你需要把 consumed[1]的值改成90,这样coordinatorLayout就能知道只处理剩下的10px的滚动
onNestedScroll
/** * 进行嵌套滚动时被调用 * 一般可以用来处理向下滑动时的逻辑 * @param coordinatorLayout * @param child * @param target * @param dxConsumed target 已经消费的x方向的距离 * @param dyConsumed target 已经消费的y方向的距离 * @param dxUnconsumed x 方向剩下的滚动距离 * @param dyUnconsumed y 方向剩下的滚动距离 */ @Override public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); }
上一个方法结束后,NSC 处理剩下的距离。比如上面还剩 10px,这里 NSC 滚动 2px 后发现已经到头了,于是 NSC 结束其滚动,调用该方法,并将 NSC 处理剩下的像素数作为参数(dxUnconsumed、dyUnconsumed)传过来,这里传过来的就是 8px。参数中还会有 NSC 处理过的像素数(dxConsumed、dyConsumed)。这个方法主要处理一些越界后的滚动
onStopNestedScroll
/** * 嵌套滚动结束时被调用,这是一个清除滚动状态等的好时机。 * @param coordinatorLayout * @param child * @param target */ @Override public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) { super.onStopNestedScroll(coordinatorLayout, child, target); }
一切滚动停止后调用,如果不会发生惯性滚动,fling 相关方法不会调用,直接执行到这里。这里我们做一些清理工作,当然有时也要处理中间态问题
onNestedScrollAccepted
/** * onStartNestedScroll返回true才会触发这个方法,接受滚动处理后回调,可以在这个 * 方法里做一些准备工作,如一些状态的重置等。 * @param coordinatorLayout * @param child * @param directTargetChild * @param target * @param nestedScrollAxes */ @Override public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); }
当 NSP 接受要处理本次滑动后,这个回调被调用,我们可以做一些准备工作,比如让之前的滑动动画结束
onNestedPreFling
/** * 用户松开手指并且会发生惯性动作之前调用,参数提供了速度信息,可以根据这些速度信息 * 决定最终状态,比如滚动Header,是让Header处于展开状态还是折叠状态。返回true 表 * 示消费了fling. * * @param coordinatorLayout * @param child * @param target * @param velocityX x 方向的速度 * @param velocityY y 方向的速度 * @return */ @Override public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY) { return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY); }
用户松开手指并且会发生惯性滚动之前调用。参数提供了速度信息,我们这里可以根据速度,决定最终的状态是展开还是折叠,并且启动滑动动画。通过返回值我们可以通知 NSC 是否自己还要进行滑动滚动,一般情况如果面板处于中间态,我们就不让 NSC 接着滚了,因为我们还要用动画把面板完全展开或者完全折叠
参考:
http://www.jianshu.com/p/82d18b0d18f4
http://www.jianshu.com/p/7f50faa65622
相关文章推荐
- CoordinatorLayout中Behavior介绍与简单使用
- CoordinatorLayout高级用法-自定义Behavior
- CoordinatorLayout高级用法-自定义Behavior
- CoordinatorLayout与Behavior总结
- CoordinatorLayout 自定义Behavior并不难,由简到难手把手带你撸三款!
- CoordinatorLayout高级用法-自定义Behavior
- Iwfu-CoordinatorLayout(2)自定义Behavior
- CoordinatorLayout高级用法-自定义Behavior
- Android CoordinatorLayout高级用法之自定义Behavior
- Android 自定义CoordinatorLayout.Behavior 实现悬浮控件动画
- CoordinatorLayout自定义Behavior的运用
- Android 利用CoordinatorLayout vs Behavior机制自定义滑动删除布局
- 自定义实现CoordinatorLayout.Behavior
- Android CoordinatorLayout 与自定义Behavior
- 简单分析一下CoordinatorLayout的Behavior机制以及其中方法的作用
- CoordinatorLayout 布局系列 Behavior 的自定义
- CoordinatorLayout+AppBarLayout+Toolbar简单玩法,MD的behavior简单尝试
- CoordinatorLayout自定义Behavior&源码分析
- CoordinatorLayout里Behavior简单分析
- CoordinatorLayout高级用法-自定义Behavior