关于解决多个viewpager嵌套所遇到的事件传递问题

    在开发时候我们会有一种情景,类似于新闻客户端的,就是在主页面的viewpager里面的view或者frament中再嵌套了一个viewpager,这时候如果不做任何处理的话,我们父view中的viewpager和子view的viewpager会产生冲突,比如滑动的卡顿等。

       所以为了解决这个情况我们需要了解一下安卓中的事件传递机制。如果有对安卓的事件传递机制的人不那么熟悉的话,那请自己去研究一下,在这里我只简单说一下时间传递机制的基本原理。


关于解决多个viewpager嵌套所遇到的事件传递问题_第1张图片

说明:

首先触摸事件发生时(ACTION_DOWN),由系统调用Activity的dispatchTouchEvent方法,分发该事件。根据触摸事件的坐标,将此事件传递给out的dispatchTouchEvent处理,out则调用onInterceptTouchEvent 判断事件是由自己处理,还是继续分发给子View。此处由于out不处理Touch事件,故根据事件发生坐标,将事件传递给out的直接子View(即middle)。

Middle及Center中事件处理过程同上。但是由于Center组件是clickable 表示其能处理Touch事件,故center中的onInterceptTouchEvent方法将事件传递给center自己的onTouchEvent方法处理。至此,此Touch事件已被处理,不继续进行传递。

关于事件传递自己有以下总结


1. 事件首先传递给父控件-->父控件最新接收到事件,`拥有事件处理的最高优先级`;
2. 关键方法
1. dispatchTouchEvent:是否派发,常见处理-->不做任何的处理.
2. onInterceptTouchEvent:是否拦截
1. 是(true)-->调用自己的onTouchEvent去处理事件,`如果你对MotionEvent进行了拆分(action_down,action_move,action_up,action_cancel),这个时候传递流程不能说的那么绝对`
2. 否(false)-->事件传递给孩子
1. 孩子是view-->ontouchEvent
2. 孩子是viewGroup-->和之前的情况一样
        3. onTouchEvent:是否消费
1. return true:消费事件
2. return false:不消费事件

 以下是在自己写的程序中打印的一些测试log

ScrollableViewGroup以及ViewHook事件传递流程分析
 ---ScrollableViewGroup(父亲)----onInterceptTouchEvent---MotionEvent.ACTION_DOWN--- return false
---viewGroudHook---onTouchEvent---ACTION_DOWN  return true
----ScrollableViewGroup(父亲)---onInterceptTouchEvent---MotionEvent.ACTION_MOVE--- return true,onInterceptTouchEvent返回true的时候.肯定回来自己的onTouchevent里面,但是可能会去孩子那里执行以下action_cancel
---viewGroudHook---onTouchEvent---ACTION_CANCEL--->这个地方很容易产生疑惑
---ScrollableViewGroup(父亲)---onTouchEvent-----MotionEvent.ACTION_MOVE------- 父亲在onInterceptTouchEvent里面的action_move分支下return true,所以我们进入的是ontouchEvent的Action_move
---ScrollableViewGroup(父亲)---onTouchEvent-----MotionEvent.ACTION_MOVE------- 这里我们用打断点的形式.没有看到action_move.所以我们常用打日志的形式进行了分析
---ScrollableViewGroup(父亲)---onTouchEvent-----MotionEvent.ACTION_MOVE-------
---ScrollableViewGroup(父亲)---onTouchEvent-----MotionEvent.ACTION_UP-------


以上就是个人对安卓的事件传递机制的一些小总结,可能也借鉴了一下别人的图,请见谅


大家看了上面事件传递机制,应该也基本有所了解,所以我就直接贴源码好了。
这里我重写了viewpager,实现的逻辑是当滑动到子view的viewpager的头或者尾的时候就请求父控件进行事件拦截,然后实现父view的viewpager的滑动事件。但是我看了网易新闻的客户端,貌似头条新闻并不是到尾它就切换到父viewpaer的下一个view,所以大家根据自己的需求改一下以下的代码吧

/**
 * 头条新闻水平滑动的ViewPager
 * @author Administrator
 *
 */
public class TopNewsViewPager extends ViewPager{

	private int startX;
	private int startY;

	public TopNewsViewPager(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	public TopNewsViewPager(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}
	
	/**
     * 事件分发,请求父控件及祖宗控件是否拦截事件
     * 1.用户右滑,而且是第一个页面,就需要父控件拦截,显示上一个标签或者侧边栏
     * 2.用户左滑,而且是最后一个页面,就需要父控件拦截,显示下一个标签
     * 3.上下滑动,需要父控件拦截
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
    	
//    	//用getParent去请求,希望父控件不拦截这个OnToch事件
//        getParent().requestDisallowInterceptTouchEvent(true);
    	
            switch (ev.getAction()) {
            
			case MotionEvent.ACTION_DOWN:
				//用getParent去请求,希望父控件不拦截这个OnToch事件
				//这样为了保证ACTION_MOVE调用
	             getParent().requestDisallowInterceptTouchEvent(true);
	
	             startX = (int) ev.getRawX();
	             startY = (int) ev.getRawY();
	             
				break;

             case MotionEvent.ACTION_MOVE:
            	 
            	 int endX=(int) ev.getRawX();
            	 int endY=(int) ev.getRawY();
            	 
            	 if(Math.abs(endX-startX)>Math.abs(endY-startY)){//左右滑动
            		 
            		 if(endX>startX){//右滑
            			 
            			 if(getCurrentItem()==0){//第一个页面,需要父控件拦截
            				 
            				 getParent().requestDisallowInterceptTouchEvent(false);
            			 }
            			 
            		 }else{//左滑
            			 
            			 if(getCurrentItem()==getAdapter().getCount()-1){//最后一个页面,需要拦截
            				
            				 getParent().requestDisallowInterceptTouchEvent(false);
            			 }
            			 
            		 }
            		 
            	 }else{//上下滑动,需要父控件拦截
            		 getParent().requestDisallowInterceptTouchEvent(false);
            	 }
				
				break;
			}    	

        	
    	
    	
    	return super.dispatchTouchEvent(ev);
    }
	
}

以上大概就是我对多个viewpager嵌套的事件传递的解决吧。


你可能感兴趣的:(关于解决多个viewpager嵌套所遇到的事件传递问题)