看了很久的View的事件冲突解决办法,一直没有什么好的头绪,今天用了半天时间,好好看了一下view的事件原理,虽说没有自己看源码(主要是看不懂),但是在众多大神的博客里面也是通过源码来分析,所以也当自己看了吧,下面自己把自己目前理解的记录下来,希望自己能够很好的理解这一部分知识。
- 首先所有的我们看得见的都是继承自View的,我们将View的子类(不是很准确)分为View和ViewGroup。事件分为dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent event)。而view是没有oninterceptTouchEvent,因为事件传递给它,它要么处理(ontouchEvent()返回true)、要么不处理,交给父类的ontouchEvent()处理。父View如果拦截了ACTION_DOWN则子View完全接收不到事件序列,所以一般情况下我们在ACTION_DOWN是不拦截事件的,在ACTION_MOVE中,判断我们什么情况需要拦截(返回true),ACTION_UP事件我们一般也不拦截,如果拦截了子View获取不到up事件,里面的click事件也不会响应(click()是由ontouchEvent()调用)
- 而我们常见的滑动冲突有1、水平与竖直方向交叉 2、水平与水平方向的交叉 3、多层嵌套滑动。
- 我们解决滑动冲突一般有两种思路,1、(外部拦截)父View判断何时该拦截(自己处理),何时不拦截交由子View处理。2、(内部拦截)子View判断,自己什么时候需要处理事件(调用parent.requestDisallowInterceptEvent(true)),因为父View的move 和 up事件受这个方法返回值影响。
其他关于View事件处理的零散知识点:
- //获取touchSlop值
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(viewConfiguration); 这个值表示的的手机能识别的最小的滑动距离,可以通过这个值和我们手指移动的距离来判断我们的动作是不是滑动,一般用在ACTION_MOVE里面如果是则进行拦截等等。 - //创建Scroller实例
mScroller = new Scroller(context);
//调用startScroll()方法来初始化滚动,并刷新界面
mScroller.startScroll(getScrollX(),0,dx,0);
invalidate();重绘会调用以下方法(需要自己重写)
@Override
public void computeScroll() {
super.computeScroll();
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
invalidate();
}
} - scrollTo和scrollBy的区别:前者是绝对滚动,相对的这个布局,后者是相对与上一次滚动后的滚动。