zoukankan      html  css  js  c++  java
  • View的滑动冲突和解决方案

      1.滑动冲突原因:

      当有内外两层View同时可以滑动的时候,这个时候就会产生滑动冲突。

       2.常见的冲突场景:

      场景1:

       

      场景2:

         

       场景3:

          

     4.解决方法种类:

       (1)外部拦截法:

        

        针对场景1,我们可以发现外部和内部的滑动方向不一样也就是说只要判断当前dy和dx的大小,如果dy>dx,那么当前就是竖直滑动,否则就是水平滑动。明确了这个我就就可以根据当前的手势开始拦截了。从view的事件分发中我们了解点击事件的分发顺序是 通过父布局分发,如果父布局没有拦截,即onInterceptTouchEvent返回false,才会传递给子View。所以我们就可以利用onInterceptTouchEvent()这个方法来进行事件的拦截。

        

     1  public boolean onInterceptTouchEvent(MotionEvent event) {
     2         boolean intercepted = false;
     3         int x = (int) event.getX();
     4         int y = (int) event.getY();
     5 
     6         switch (event.getAction()) {
     7         case MotionEvent.ACTION_DOWN: {
     8             intercepted = false;
     9             break;
    10         }
    11         case MotionEvent.ACTION_MOVE: {
    12             if(父容器拦截的规则){
    13                 intercepted=true;
    14             }else{
    15                 intercepted=false;
    16             }
    17             break;
    18         }
    19         case MotionEvent.ACTION_UP: {
    20             intercepted = false;
    21             break;
    22         }
    23         default:
    24             break;
    25         }
    26         mLastXIntercept=x;
    27         mLastYIntercept=y;
    28         return intercepted;
    29     }

    上面的代码差多就是外部拦截的通用模板了,在onInterceptTouchEvent方法中,

    首先是ACTION_DOWN这个事件,父容器必须返回false,即不拦截事件,因为一旦父容器拦截了ACTION_DOWN这个事件,那么后续的ACTION_MOVE和ACTION_UP事件将直接交给父容器处理,这个时候事件没法继续传递给子元素了;

    然后是ACTION_MOVE这个事件,这个事件可以根据需要决定是否拦截,如果父容器需要拦截就返回true,否则返回false;

    最后是ACTION_UP这个事件,这里必须返回false,因为这个事件本身也没有太多意义。

     so场景一的外部拦截解决方法:

     

     1 public boolean onInterceptTouchEvent(MotionEvent event) {
     2         boolean intercepted = false;
     3         int x = (int) event.getX();
     4         int y = (int) event.getY();
     5 
     6         switch (event.getAction()) {
     7         case MotionEvent.ACTION_DOWN: {
     8             intercepted = false;
     9             break;
    10         }
    11         case MotionEvent.ACTION_MOVE: {
    12             int deltaX=x-mLastXIntercept;
    13             int deltaY=y=mLastYIntercept;
    14             if(Math.abs(deltaX)>Math.abs(deltaY)){
    15                 intercepted=true;
    16             }else{
    17                 intercepted=false;
    18             }
    19             break;
    20         }
    21         case MotionEvent.ACTION_UP: {
    22             intercepted = false;
    23             break;
    24         }
    25         default:
    26             break;
    27         }
    28         mLastXIntercept=x;
    29         mLastYIntercept=y;
    30         return intercepted;
    31     }

      场景二的外部拦截方法:

      

     1 public boolean onInterceptTouchEvent(MotionEvent event) {
     2         boolean intercepted = false;
     3         int x = (int) event.getX();
     4         int y = (int) event.getY();
     5 
     6         switch (event.getAction()) {
     7         case MotionEvent.ACTION_DOWN: {
     8             mLastYIntercept=y;
     9             intercepted = super.onInterceptTouchEvent(event);
    10             break;
    11         }
    12         case MotionEvent.ACTION_MOVE: {
    13             if(listView.getFirstVisiblePosition()==0 &&y>mLastYIntercept){
    14                 intercepted=true;
    15             }else if(listView.getLastVisiblePosition()==listView.getCount-1&&y                <mLastYIntercept){
    16                 intercepted=false;
    17              break;
    18             }
    19             intercepted = false;
    20             break;
    21         }
    22         case MotionEvent.ACTION_UP: {
    23             intercepted = false;
    24             break;
    25         }
    26         default:
    27             break;
    28         }
    29         mLastXIntercept=x;
    30         mLastYIntercept=y;
    31         return intercepted;
    32     }

      

    (2)内部拦截法

       内部拦截法是指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器去处理

     (android系统中,一次点击事件是从父view传递到子view中,每一层的view可以决定是否拦截并处理点击事件或者传递到下一层,如果子view不处理点击事件,则该事件会传递会父view,由父view去决定是否处理该点击事件。在子view可以通过设置此方法去告诉父view不要拦截并处理点击事件,父view应该接受这个请求直到此次点击事件结束)需要用到方法requestDisallowInterceptTouchEvent。

     内部拦截通用模板:

      

     1 public boolean onInterceptTouchEvent(MotionEvent event) {
     2         int x = (int) event.getX();
     3         int y = (int) event.getY();
     4 
     5         switch (event.getAction()) {
     6         case MotionEvent.ACTION_DOWN: {
     7             parent.requestDisallowInterceptTouchEvent(true); //父布局不要拦截此事件
     8             break;
     9         }
    10         case MotionEvent.ACTION_MOVE: {
    11             int deltaX=x-mLastXIntercept;
    12             int deltaY=y=mLastYIntercept;
    13             if(父容器需要拦截的事件){
    14                 parent.requestDisallowInterceptTouchEvent(false); //父布局需要要拦截此事件
    15             }
    16             break;
    17         }
    18         case MotionEvent.ACTION_UP: {
    19             intercepted = false;
    20             break;
    21         }
    22         default:
    23             break;
    24         }
    25         mLastXIntercept=x;
    26         mLastYIntercept=y;
    27         return super.dispathTouchEvent(event);
    28     }

      so 场景二的内部拦截解决方法:

     

     1 //拦截除了Down事件以外的其他方法:
     2 public boolean onInterceptTouchEvent(MotionEvent event) {
     3         int x = (int) event.getX();
     4         int y = (int) event.getY();
     5         int action = event.getAction();
     6          if(action == MotionEvent.ACTION_DOWN){
     7            mLastXIntercept=x;
     8            mLastYIntercept=y;
     9            return super.dispathTouchEvent(event);
    10         }else{
    11            return true;
    12         }
    13    }   
    14 
    15          

    场景三建议使用内部拦截方法比较方便

       

        

  • 相关阅读:
    systemtap没找到函数变量
    systemtap get var of the tracepoing
    如何在tracepoint上注册函数
    stap中的entry函数
    stap用法
    在submit_bio处使用stapn
    巴达努斯
    perf事件的切换
    perf原理再看
    内存回收的阈值
  • 原文地址:https://www.cnblogs.com/mrszhou/p/6896434.html
Copyright © 2011-2022 走看看