安卓behavior详解3--自定义behavior详解
来源:互联网 发布:指定dns解析域名 编辑:程序博客网 时间:2024/05/21 06:19
一.前言
官方定义:
A Behavior implements one or more interactions that a user can take on a child view. These interactions may include drags, swipes, flings, or any other gestures.
中文:
一个Behavior实现了一个或多个用户可以采取的交互视图。这些相互作用可能包括拖动,滑动,快速滑动,或任何其他的手势。
二.类似观察者概念
其实Behavior就是一个应用于View的观察者模式,一个View跟随者另一个View的变化而变化,或者说一个View监听另一个View。
在Behavior中,被观察的View 也就是事件源被称为denpendcy,而观察View,则被称为child
Behavior内部的方法当在CoordinatorLayout上发生触摸事件的时候,CoordinatorLayout会处理触摸事件,并回调Behavior中的部分方法,我们可以通过处理这些回调方法来实现需求
三.Behavior中的几个重要方法
Behavior 是一个顶层抽象类,其他的一些具体行为的Behavior 都是继承自这个类。它提供了几个重要的方法:
layoutDependsOn
onDependentViewChanged
onStartNestedScroll
onNestedPreScroll
onNestedScroll
onStopNestedScroll
onNestedScrollAccepted
onNestedPreFling
onLayoutChild
/** * 表示是否给应用了Behavior 的View 指定一个依赖的布局,通常,当依赖的View 布局发生变化时,不管被被依赖View 的顺序怎样,被依赖的View也会重新布局 * @param parent * @param child 绑定behavior 的View * @param dependency 依赖的view * @return 如果child 是依赖的指定的View 返回true,否则返回false */ @Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return super.layoutDependsOn(parent, child, dependency); } /** * 当被依赖的View 状态(位置、大小等)发生变化时,这个方法被调用 * @param parent * @param child * @param dependency * @return */ @Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { return super.onDependentViewChanged(parent, child, dependency); } /** * 当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 super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); } /** * 嵌套滚动发生之前被调用 在nested scroll child 消费掉自己的滚动距离之前,嵌套滚动每次被nested scroll child 更新都会调用onNestedPreScroll。注意有个重要的参数consumed,可以修改这个数 组表示你消费了多少距离。假设用户滑动了100px,child 做了90px 的位移,你需要 把 consumed[1]的值改成90, * 这样coordinatorLayout就能知道只处理剩下的10px的滚动。 * @param coordinatorLayout * @param child * @param target * @param dx 用户水平方向的滚动距离 * @param dy 用户竖直方向的滚动距离 * @param consumed */ @Override public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) { super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); } /** * 进行嵌套滚动时被调用 * @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); } /** * 嵌套滚动结束时被调用,这是一个清除滚动状态等的好时机。 * @param coordinatorLayout * @param child * @param target */ @Override public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) { super.onStopNestedScroll(coordinatorLayout, child, target); } /** * 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); } /** * 用户松开手指并且会发生惯性动作之前调用,参数提供了速度信息,可以根据这些 速度信息决定最终状态,比如滚动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); }/* * 可以重写这个方法对子View 进行重新布局 * @param coordinatorLayout * @param child * @param layoutDirection 布局的方向 */@Override public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) { return super.onLayoutChild(parent, child, layoutDirection); }
四.嵌套滚动原理和CoordinatorLayout
NestedScrolling提供了一套父View和子View滑动交互机制。要完成这样的交互,父View需要实现NestedScrollingParent接口,而子View需要实现NestedScrollingChild接口,系统提供的NestedScrollView控件就实现了这两个接口,这两个接口虽然有很多抽象方法,但均有NestedScrolling[Parent,Children]Helper辅助类来帮助处理大部分逻辑
NestedScroll的机制的简版是这样的,当子View在处理滑动事件之前,先告诉自己的父View是否需要先处理这次滑动事件,父View处理完之后,告诉子View它处理的多少滑动距离,剩下的还是交给子View自己来处理
CoordinatorLayout的事件传递
CoordinatorLayout并不会直接处理触摸事件,而是尽可能地先交由子View的Behavior来处理,它的onInterceptTouchEvent和onTouchEvent两个方法最终都是调用performIntercept方法,用来分发不同的事件类型分发给对应的子View的Behavior处理
//处理拦截或者自己的触摸事件private boolean performIntercept(MotionEvent ev, final int type) { boolean intercepted = false; boolean newBlock = false; MotionEvent cancelEvent = null; final int action = MotionEventCompat.getActionMasked(ev); final List<View> topmostChildList = mTempList1; getTopSortedChildren(topmostChildList); //在5.0以上,按照z属性来排序,以下,则是按照添加顺序或者自定义的绘制顺序来排列 // Let topmost child views inspect first final int childCount = topmostChildList.size(); for (int i = 0; i < childCount; i++) { final View child = topmostChildList.get(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final Behavior b = lp.getBehavior(); // 如果有一个behavior对事件进行了拦截,就发送Cancel事件给后续的所有Behavior。假设之前还没有Intercept发生,那么所有的事件都平等地对所有含有behavior的view进行分发,现在intercept忽然出现,那么相应的我们就要对除了Intercept的view发出Cancel if ((intercepted || newBlock) && action != MotionEvent.ACTION_DOWN) { // Cancel all behaviors beneath the one that intercepted. // If the event is "down" then we don't have anything to cancel yet. if (b != null) { if (cancelEvent == null) { final long now = SystemClock.uptimeMillis(); cancelEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); } switch (type) { case TYPE_ON_INTERCEPT: b.onInterceptTouchEvent(this, child, cancelEvent); break; case TYPE_ON_TOUCH: b.onTouchEvent(this, child, cancelEvent); break; } } continue; } if (!intercepted && b != null) { switch (type) { case TYPE_ON_INTERCEPT: intercepted = b.onInterceptTouchEvent(this, child, ev); break; case TYPE_ON_TOUCH: intercepted = b.onTouchEvent(this, child, ev); break; } if (intercepted) { mBehaviorTouchView = child; //记录当前需要处理事件的View } } // Don't keep going if we're not allowing interaction below this. // Setting newBlock will make sure we cancel the rest of the behaviors. final boolean wasBlocking = lp.didBlockInteraction(); final boolean isBlocking = lp.isBlockingInteractionBelow(this, child); //behaviors是否拦截事件 newBlock = isBlocking && !wasBlocking; if (isBlocking && !newBlock) { // Stop here since we don't have anything more to cancel - we already did // when the behavior first started blocking things below this point. break; } } topmostChildList.clear(); return intercepted;}
- 安卓behavior详解3--自定义behavior详解
- 安卓behavior详解2--自定义behavior简单案例
- 安卓behavior详解1--系统behavior的简单应用
- CoordinatorLayout的详解以及自定义Behavior
- CoordinatorLayout使用详解之自定义Behavior
- Android Behavior详解
- CoordinatorLayout.Behavior方法详解
- 自定义behavior
- 自定义 Behavior
- 自定义Behavior
- behavior
- BEHAVIOR
- Behavior
- Behavior
- CoordinatorLayout 属性详解 和 Behavior 的使用
- 自定义实现CoordinatorLayout.Behavior
- 自定义Behavior(一)
- 自定义Behavior(二)
- 杭电 6213 (map) 之 Chinese Zodiac
- 黑魔法~XOR linked list
- 理解Tomcat架构、启动流程及其性能优化
- JMX监控Zookeeper状态Java API
- 轮播图下方小圆点
- 安卓behavior详解3--自定义behavior详解
- 零度编程/自学网
- vector和arrayList的区别
- 614D9828AD3C1E5E0F7C4C4DC70358F0 病毒分析
- 算法竞赛入门经典(第2版)-刘汝佳-第七章解题源码(C++语言)(部分)
- SIM900A、GPRS、GSM 基础知识
- iOS关于TableView重用Cell的一点领悟
- HDU
- 【七日牧函】教会中的多样与合一