Android 嵌套布局简析

来源:互联网 发布:生化危机6 for mac 编辑:程序博客网 时间:2024/06/06 05:19

前言

嵌套布局是事件分发的衍生内容,理解了嵌套布局的实现方式,Md的很多效果都是毛毛雨了

原文地址进入

这里写图片描述

Uml 时序图形

这里写图片描述

 嵌套布局实现方式,以及 5.0 中与嵌套布局有关联的组件

提起嵌套布局,MD中的 CoordinatorLayout,SwipeRefreshLayout,RecyclerView 当然还有V4包下的NestedScrollView,都有直接关系,因为他们是 NestedScrollingParent(NP) 或者 NestedScrollingChild(NC) 直接或者间接子类。

那么如何才能进行嵌套布局自定义?
通过成为NP,NC子类进行嵌套布局开发妥妥的。
下面是NP,NC 具体方法,调用时序查看blog头部的时序图结合源码进行理解
NestedScrollingChildHelper // Child辅助类
NestedScrollingParentHelper // Parent辅助类

核心类 NestedScrollingParent

package android.support.v4.view;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;public interface NestedScrollingParent {    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);    public void onStopNestedScroll(View target);    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,            int dxUnconsumed, int dyUnconsumed);    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);    public boolean onNestedPreFling(View target, float velocityX, float velocityY);    public int getNestedScrollAxes();}

核心类 NestedScrollingChild

package android.support.v4.view;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewParent;public interface NestedScrollingChild {    public void setNestedScrollingEnabled(boolean enabled);    public boolean isNestedScrollingEnabled();    public boolean startNestedScroll(int axes);    public void stopNestedScroll();    public boolean hasNestedScrollingParent();    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,            int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);    public boolean dispatchNestedPreFling(float velocityX, float velocityY);}

简单一下回调方法的介含义,以及需要在那里处理事件:

onStartNestedScroll该方法,一定要按照自己的需求返回true,该方法决定了当前控件是否能接收到其内部View(非并非是直接子View)滑动时的参数;假设你只涉及到纵向滑动,这里可以根据nestedScrollAxes这个参数,进行纵向判断。

onNestedPreScroll该方法的会传入内部View移动的dx,dy,如果你需要消耗一定的dx,dy,就通过最后一个参数consumed进行指定,例如我要消耗一半的dy,就可以写consumed[1]=dy/2

onNestedFling你可以捕获对内部View的fling事件,如果return true则表示拦截掉内部View的事件。

主要关注的就是这三个方法~

这里内部View表示不一定非要是直接子View,只要是内部View即可。

下面看一下我们具体的实现:

public class StickyNavLayout extends LinearLayout implements NestedScrollingParent{    @Override    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes)    {        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;    }    @Override    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed)    {        boolean hiddenTop = dy > 0 && getScrollY() < mTopViewHeight;        boolean showTop = dy < 0 && getScrollY() > 0 && !ViewCompat.canScrollVertically(target, -1);        if (hiddenTop || showTop)        {            scrollBy(0, dy);            consumed[1] = dy;        }    }    @Override    public boolean onNestedPreFling(View target, float velocityX, float velocityY)    {        if (getScrollY() >= mTopViewHeight) return false;        fling((int) velocityY);        return true;    }}

onStartNestedScroll中,我们判断了如果是纵向返回true,这个一般是需要内部的View去传入的,你要是不确定,或者担心内部View编写的不规范,你可以直接return true;

onNestedPreScroll中,我们判断,如果是上滑且顶部控件未完全隐藏,则消耗掉dy,即consumed[1]=dy;如果是下滑且内部View已经无法继续下拉,则消耗掉dy,即consumed[1]=dy,消耗掉的意思,就是自己去执行scrollBy,实际上就是我们的StickNavLayout滑动。

此外,这里还处理了fling,通过onNestedPreFling方法,这个可以根据自己需求定了,当顶部控件显示时,fling可以让顶部控件隐藏或者显示。

Eg:当然有人会说用手势 + 事件分发拦截同样可以实现这个效果,的确可以实现,只是效果会打折扣

事件分发是这样的:子View首先得到事件处理权,处理过程中,父View可以对其拦截,但是拦截了以后就无法再还给子View(本次手势内)。
NestedScrolling机制是这样的:内部View在滚动的时候,首先将dx,dy交给NestedScrollingParent,NestedScrollingParent可对其进行部分消耗,剩余的部分还给内部View。

这里针对实现了NetstedScrollingParent 的类继续log输出,直观显示滚动事件调用链。

不进行滑动

vlayout E/StickyNavLayout: onStartNestedScroll05-22 14 E/StickyNavLayout: onNestedScrollAccepted05-22 14 E/StickyNavLayout: onStopNestedScroll

进行滑动

05-22 14:46:11.655 27721-27721/: onStartNestedScroll05-22 14:46:11.655 27721-27721/: onNestedScrollAccepted05-22 14:46:11.875 27721-27721/: onNestedPreScroll05-22 14:46:11.895 27721-27721/: onNestedPreScroll05-22 14:46:11.915 27721-27721/: onNestedPreScroll05-22 14:46:11.925 27721-27721/: onNestedPreScroll05-22 14:46:11.945 27721-27721/: onNestedPreScroll05-22 14:46:11.965 27721-27721/: onNestedPreScroll05-22 14:46:11.975 27721-27721/: onNestedPreScroll05-22 14:46:11.995 27721-27721/: onNestedPreScroll05-22 14:46:12.015 27721-27721/: onNestedPreScroll05-22 14:46:12.025 27721-27721/: onNestedPreScroll05-22 14:46:12.045 27721-27721/: onStopNestedScroll

快速滑动

05-22 14:48:18.245 27721-27721/: onStartNestedScroll05-22 14:48:18.245 27721-27721/: onNestedScrollAccepted05-22 14:48:18.315 27721-27721/: onNestedPreScroll05-22 14:48:18.315 27721-27721/: onNestedScroll05-22 14:48:18.315 27721-27721/: onNestedPreFling05-22 14:48:18.315 27721-27721/: onNestedFling05-22 14:48:18.315 27721-27721/: onStopNestedScroll

抛,快速 滑动触发Fling

05-22 14:49:51.875 27721-27721/: onNestedPreFling05-22 14:49:51.875 27721-27721/: onNestedFling

1.嵌套布局模式。依附于onTouchEvent() 进行处理。在down,move,up 中进行回调。Helper 类中实现

  1. 固定大小的 int [2],集合。 作为形参,进行传递,在函数中可以通过形参进行赋值

3.scroller 和 后面 api 19 新添加对于over 边界处理的 overscroller ,两者80% api重复,后者多了几个处理Over bound的 api

Demo 链接:http://blog.csdn.net/o279642707/article/details/72654386

总结:

嵌套布局滑动和事件分发之间的区别,进行自定义扩展嵌套布局需要实现那些方法,实现那几个类。嵌套布局的延伸兼容性等有个大体的了解。细节部分还请自行体验


引用:
RecyclerView的滚动事件分析
https://segmentfault.com/a/1190000005718165
带你玩转嵌套滑动 http://blog.csdn.net/lmj623565791/article/details/52204039
Android NestedScrolling 实战
https://race604.com/android-nested-scrolling/
Android 嵌套滑动机制(NestedScrolling)
https://segmentfault.com/a/1190000002873657
Android 自定义控件 轻松实现360软件详情页
http://blog.csdn.net/lmj623565791/article/details/43649913
NestedScrollingParent, NestedScrollingChild  详解
http://blog.csdn.net/chen930724/article/details/50307193
关于View的ScrollTo, getScrollX 和 getScrollY
http://www.xuebuyuan.com/2013505.html