Android事件分发常见冲突案例

一:安卓事件分发的常用总结语句:
 ViewGroup,先要走分发流程,如果没有孩子处理事件,自己就再走处理流程(自己处理事件)
View,只能走处理事件流程.

 二:事件分发流程(简洁):
(1) down--首先确定down事件属于谁的?: 属于父容器的?属于子view的?
 1.先看是否拦截后自己处理(即不分发下去)
  2.如果不拦截,分发下去:
            排序  
            遍历分发
            领取事件的子View 处理该事件
  3.没孩子领取处理该事件,再看下自己是否处理事件。

 ①如果父容器拿到了down事件,那么后续事件(move up)怎么处理?有父容器说了算,或者拦截,自己处理事件,或者事件分发给子view处理。
②如果子Veiw拿到了down事件 那么后续的事件(move up)有谁处理,由子View 说了算 ,或者子view请求父容器要拦截事件,让父容器处理事件(view.getParent().requestDisallowInterceptTouchEvent(false)(请求系统不要禁用父容器的拦截事件);或者子View自己处理事件.


(2) move--处理事件
        1.先看是否拦截后自己处理(即不分发下去)  (子view可以请求不拦截)
          2.分发下去:
            直接由down事件确定的view处理

三:控件滑动冲突的解决方案:

 1.外部拦截法

外部滑动方向与内部滑动方向不一致
解决方案:外部拦截法,当事件传递到父View时,父View需要处理此事件,就拦截,不处理此事件就不拦截


 2.内部拦截法

外部滑动方向与内部滑动方向一致;
解决方案:内部拦截法,当事件传递到父View时,父View都传递给子View,如果子View需要处理此事件就消耗掉,否则就交给父View处理。但是这种方法和Android事件分发不一致,需要配合 requestDisallowInterceptTouchEvent 方法才能正常工作

扫描二维码关注公众号,回复: 13191872 查看本文章

 事件冲突案例1: 父容器 BadViewPager 与子view MylistView的冲突

public class MainActivity extends AppCompatActivity {
    private int[] iv = new int[]{R.mipmap.iv_0, R.mipmap.iv_1, R.mipmap.iv_2,
            R.mipmap.iv_3, R.mipmap.iv_4, R.mipmap.iv_5,
            R.mipmap.iv_6, R.mipmap.iv_7, R.mipmap.iv_8};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_viewpager);
        BadViewPager pager = findViewById(R.id.viewpager);

        List<Map<String, Integer>> strings = new ArrayList<>();
        Map<String, Integer> map;
        for (int i = 0; i < 20; i++) {
            map = new HashMap<>();
            map.put("key", iv[i % 9]);
            strings.add(map);
        }

        MyPagerAdapter adapter = new MyPagerAdapter(this, strings);
        pager.setAdapter(adapter);
    }
}



public class MyPagerAdapter extends PagerAdapter {
    private Context mContext;
    private List<Map<String, Integer>> mData;

    public MyPagerAdapter(Context context, List<Map<String, Integer>> list) {
        mContext = context;
        mData = list;
    }

    @Override
    public int getCount() {
        return 5;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = View.inflate(mContext, R.layout.item_list, null);
        ListView list = view.findViewById(R.id.list);
        list.setAdapter(new SimpleAdapter(container.getContext(), mData, R.layout.item_base, new String[]{"key"}, new int[]{R.id.iv}));
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }
}

使用内部拦截法:让子view(MyListView)处理事件冲突
当你 上下滑动子view myListView的同时可以左右滑动ViewPager  子Veiw不可以抢父容器的事件
/**
 内部拦截法:子view(MyListView)处理事件冲突
 *  */
public class MyListView extends ListView {
   public MyListView(Context context) {
        super(context);
    }
  public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
  private int mLastX, mLastY;
  @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
     //todo   当down时,父容器(BadViewPager)会把事件往下分发给子view(父容器拿不到该事件了)  让子view(MyListVIew)来处理事件(子view 拿到down事件 )
           getParent().requestDisallowInterceptTouchEvent(true);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastX;
                int deltaY = y - mLastY;
   // todo    如果Math.abs(deltaX) > Math.abs(deltaY)  判断出是左右滑动,
    // todo 那么   子view 把该事件  让给父容器(BadViewPager)去处理      让 父容器会拦截事件,父容器处理该事件  那么你就可以左右滑动父容器(BadViewPager)
                  if (Math.abs(deltaX) > Math.abs(deltaY)) {
                 getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                break;

            }
            default:
                break;
        }

        mLastX = x;
        mLastY = y;
        return super.dispatchTouchEvent(event);
    }
 }

 外部拦截法:父容器BadViewPager处理冲突事件
 当你左右滑动父容器  BadViewPager的同时不可以上下滑动myListView  父容器可以抢子Veiw的事件

/**
    外部拦截法:父容器处理冲突事件
 *  父容器想要把事件分发给谁就分发给谁
 *     */
public class BadViewPager extends ViewPager {

    private int mLastX, mLastY;

    public BadViewPager(@NonNull Context context) {
        super(context);
    }

    public BadViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
//        if (event.getAction() == MotionEvent.ACTION_DOWN){
//            super.onInterceptTouchEvent(event);
//            return false;
//        }
//        return true;

        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mLastX = (int) event.getX();
                mLastY = (int) event.getY();
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastX;
                int deltaY = y - mLastY;
                if (Math.abs(deltaX) > Math.abs(deltaY)) {
   //todo  如果  onInterceptTouchEvent  =false 父容器(BadViewPager)不拦截事件 ,   分发给子view (MyListView )     父容器(BadViewPager) 不处理事件(那么父容器就不能左右滑动了)
                //    return false;
  //todo  如果  onInterceptTouchEvent  =true 父容器(BadViewPager)拦截事件 ,不分发给子view (MyListView ) 父容器(BadViewPager) 自己处理事件(那么父容器就可以左右滑动了)
                    return true;
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                break;
            }
            default:
                break;
        }

        return super.onInterceptTouchEvent(event);

    }
}

事件冲突案例2: 父容器 SwipeRefreshLayout 与子view Viewpager的冲突


/**
 *  父容器CustomSRL2来处理这个冲突事件
 * */
public class CustomSRL2 extends SwipeRefreshLayout {
    public CustomSRL2(Context context) {
        super(context);
    }
   public CustomSRL2(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    private int mLastX, mLastY;
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
          int x = (int) ev.getX();
         int y = (int) ev.getY();
         switch (ev.getAction()){
            //todo down    父容器拿到事件  下面 父容器如何处理这个事件呢?
             case MotionEvent.ACTION_DOWN: {
                 mLastX = (int) ev.getX();
                 mLastY = (int) ev.getY();
                  break;
             }
             case MotionEvent.ACTION_MOVE: {

                 int deltaX = x - mLastX;
                 int deltaY = y - mLastY;
                 //todo 如果 Math.abs(deltaY) > Math.abs(deltaX)   上下垂直滑动, onInterceptTouchEvent=true  父容器SwipeRefreshLayout(上拉刷新) 拦截事件 自己处理 。
                 if (Math.abs(deltaY) > Math.abs(deltaX)) {
                        return true ;
                 }
                 break;
             }
             case MotionEvent.ACTION_UP: {
                 break;
             }
             default:
                 break;
         }


        return super.onInterceptTouchEvent(ev);
    }
}




/**
 *  子view  ViewPager
 * 
 * */
public class CustomVPInner extends ViewPager {

    private float startX;
    private float startY;
    private float x;
    private float y;
    private float deltaX;
    private float deltaY;

    public CustomVPInner(Context context) {
        super(context);
    }

    public CustomVPInner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = ev.getX();
                startY = ev.getY();
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                x = ev.getX();
                y = ev.getY();
                deltaX = Math.abs(x - startX);
                deltaY = Math.abs(y - startY);
                if (deltaX < deltaY) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33552379/article/details/119881393