• Android 滑动冲突以及如何解决


    今天针对一个滑动冲突的其中一类----内外两层的滑动方向一致。

    遇到的问题是:
    外层是一个自定义LinearLayout,我在它上面重写了onToucheEvent,设置了滑动事件,让它内部的子View能够在手指下滑的时候,组件跟着下移,手指松开,组件回到原来位置。
    内层是一个ScrollView,它本身就可滑动。
    那么当我手指在屏幕上滑动的时候,系统并不明确我想让哪一层滑动,可能系统给出的结果就不是我预期的。所以,这里我们必须写程序去控制这个滑动效果。

     

    我们想要达到的效果是:
    当我下滑:
    在ScrollView滑动最上面的时候(即 ScrollView的顶端已经显示出来),此时如果我下滑,那么就触发外层自定义LinearLayout的滑动事件。
    在ScrollView并不是滑动到最上面的时候,此时如果我下滑,就触发scrollView本身的scroll效果。

    当我上滑:
    无论ScrollView处于何种情况,都不要触发外层自定义LinearLayout的滑动事件。

     

    最终效果如下图:

    这是刚刚加载的样子:

      

     

    这是scrollView处于顶端但是向下滑动的时候:触发了外层layout的下拉事件,松开手则会回弹

     

    这是ScrollView不处于顶端而向下滑的时候:并不会触发外层的下拉事件,因为在自定义ScrollView中,重写了onTouchEvent,定义了外层getParent何时可以拦截,而何时不能拦截。(scroll到顶的时候可以拦截下拉事件,没到顶的时候则不能拦截下拉事件)


    -----------------------------------------------------------------------
    解决此问题的前提是 :熟练掌握 事件分发机制的原理。
    解决此问题的方法步骤为:
    1)外部拦截:在自定义LinearLayout中,重写onInterceptTouchEvent,拦截所有下滑的事件,释放所有下滑的事件。
    2)内部拦截:在子组件,也就是自定义ScrollView中,重写OnTouchEvent,判定是不是当前scroll到了顶部,如果是到了顶部,那么就允许父组件进行拦截。如果是滑到中间位置,不是顶部,就不允许父组件进行拦截,事件就会在子组件这里消耗掉,父组件就不会执行onTouchEvent.

    最终就达成了上面说的预期效果;

     

    全部代码如下:

    MyParentView.java 即 外围的自定义LinearLayout,由它进行外部拦截

     1 import android.content.Context;
     2 import android.util.AttributeSet;
     3 import android.util.Log;
     4 import android.view.MotionEvent;
     5 import android.widget.LinearLayout;
     6 
     7 public class MyParentView extends LinearLayout {
     8 
     9     private int mMove;
    10     private int yDown, yMove;
    11     private int i = 0;
    12 
    13     public MyParentView(Context context, AttributeSet attrs) {
    14         super(context, attrs);
    15     }
    16 
    17     @Override
    18     public boolean onInterceptTouchEvent(MotionEvent ev) {
    19         int y = (int) ev.getY();
    20         boolean isIntercept = false;// 默认不拦截,这个变量只能放在方法内部作为局部变量,因为如果作为全局变量的话,子组件内部有可能划不动;至于是啥原因,我还没想明白
    21         switch (ev.getAction()) {
    22             case MotionEvent.ACTION_DOWN:
    23                 yDown = y;
    24                 break;
    25             case MotionEvent.ACTION_MOVE:
    26                 yMove = y;
    27                 if (yMove - yDown < 0) {// 上滑动作直接放行
    28                     isIntercept = false;
    29                 } else if (yMove - yDown > 0) { // 下滑动作拦截住,不往下发
    30                     isIntercept = true;
    31                 }
    32                 break;
    33             case MotionEvent.ACTION_UP:
    34                 break;
    35         }
    36         Log.d("onInterceptTouchEvent", "isIntercept:" + isIntercept);
    37 
    38         return isIntercept;
    39     }
    40 
    41     /**
    42      * 重写onTouchEvent获取屏幕事件
    43      *
    44      * @param event
    45      * @return
    46      */
    47     @Override
    48     public boolean onTouchEvent(MotionEvent event) {
    49         int y = (int) event.getY();// 取得Y轴坐标值
    50         switch (event.getAction()) {
    51             case MotionEvent.ACTION_DOWN:
    52                 yDown = y;
    53                 break;
    54             case MotionEvent.ACTION_MOVE:
    55                 yMove = y;
    56                 if ((yMove - yDown) > 0) {// 如果是向下拉,因为向下拉的话,yMove总是比yDown要大
    57                     mMove = yMove - yDown;// 计算出拖动的距离
    58                     i += mMove;//记录一共拖动了多长距离,累加的
    59                     layout(getLeft(), getTop() + mMove, getRight(), getBottom() + mMove);// 调用layout进行重新布局,只是改变布局的相对于父组件的位置
    60                 }
    61                 break;
    62             case MotionEvent.ACTION_UP:
    63                 layout(getLeft(), getTop() - i, getRight(), getBottom() - i);
    64                 i = 0;
    65                 break;
    66         }
    67         return true;
    68     }
    69 }

    MyScrollView.java 内层的自定义ScrollView,由它进行内部拦截

     1 import android.content.Context;
     2 import android.util.AttributeSet;
     3 import android.util.Log;
     4 import android.view.MotionEvent;
     5 import android.widget.ScrollView;
     6 
     7 public class MyScrollView extends ScrollView {
     8 
     9 
    10     public MyScrollView(Context context) {
    11         this(context, null);
    12     }
    13 
    14     public MyScrollView(Context context, AttributeSet attrs) {
    15         this(context, attrs, 0);
    16     }
    17 
    18     public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    19         super(context, attrs, defStyleAttr);
    20     }
    21 
    22     @Override
    23     public boolean onTouchEvent(MotionEvent ev) {
    24         Log.d("onInterceptTouchEvent", "MyScrollView:onTouchEvent");
    25         switch (ev.getAction()) {
    26             case MotionEvent.ACTION_MOVE:
    27                 int scrollY = getScrollY();//纵向滑动的顶端Y轴坐标值
    28                 if (scrollY == 0) {//如果已经scroll到了顶端
    29                     //允许父View进行事件拦截
    30                     getParent().requestDisallowInterceptTouchEvent(false);//是否禁止父组件拦截事件. false表示不禁止,也就是允许
    31                 } else {
    32                     //禁止父View进行事件拦截
    33                     getParent().requestDisallowInterceptTouchEvent(true);//true表示禁止,不允许
    34                 }
    35                 break;
    36         }
    37         return super.onTouchEvent(ev);
    38 
    39     }
    40 }

     

    布局文件 activity_scroll_conflict.xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <com.example.administrator.technologystackapp.activities.custom.scroll_confict.MyParentView xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:id="@+id/parent_view"
     4     android:layout_width="match_parent"
     5     android:layout_height="match_parent"
     6     android:orientation="vertical">
     7 
     8     <com.example.administrator.technologystackapp.activities.custom.scroll_confict.MyScrollView
     9         android:layout_width="match_parent"
    10         android:layout_height="match_parent">
    11 
    12         <LinearLayout
    13             android:layout_width="match_parent"
    14             android:layout_height="match_parent"
    15             android:gravity="center"
    16             android:orientation="vertical"
    17             android:padding="10dp">
    18 
    19             <TextView
    20                 android:layout_width="match_parent"
    21                 android:layout_height="100dp"
    22                 android:layout_margin="5dp"
    23                 android:background="@drawable/textview_background2"
    24                 android:gravity="center"
    25                 android:text="content1" />
    26 
    27             <TextView
    28                 android:layout_width="match_parent"
    29                 android:layout_height="100dp"
    30                 android:layout_margin="5dp"
    31                 android:background="@drawable/textview_background2"
    32                 android:gravity="center"
    33                 android:text="content2" />
    34 
    35             <TextView
    36                 android:layout_width="match_parent"
    37                 android:layout_height="100dp"
    38                 android:layout_margin="5dp"
    39                 android:background="@drawable/textview_background2"
    40                 android:gravity="center"
    41                 android:text="content3" />
    42 
    43             <TextView
    44                 android:layout_width="match_parent"
    45                 android:layout_height="100dp"
    46                 android:layout_margin="5dp"
    47                 android:background="@drawable/textview_background2"
    48                 android:gravity="center"
    49                 android:text="content4" />
    50 
    51             <TextView
    52                 android:layout_width="match_parent"
    53                 android:layout_height="100dp"
    54                 android:layout_margin="5dp"
    55                 android:background="@drawable/textview_background2"
    56                 android:gravity="center"
    57                 android:text="content5" />
    58 
    59             <TextView
    60                 android:layout_width="match_parent"
    61                 android:layout_height="100dp"
    62                 android:layout_margin="5dp"
    63                 android:background="@drawable/textview_background2"
    64                 android:gravity="center"
    65                 android:text="content6" />
    66 
    67         </LinearLayout>
    68 
    69     </com.example.administrator.technologystackapp.activities.custom.scroll_confict.MyScrollView>
    70 
    71 </com.example.administrator.technologystackapp.activities.custom.scroll_confict.MyParentView>

    最后是Activity:

     1 import android.os.Bundle;
     2 
     3 import com.example.administrator.technologystackapp.R;
     4 import com.example.administrator.technologystackapp.activities.activity.manager.BaseActivity;
     5 
     6 public class ActivityScrollConflict extends BaseActivity {
     7 
     8     @Override
     9     protected void onCreate(Bundle savedInstanceState) {
    10         super.onCreate(savedInstanceState);
    11         setContentView(R.layout.activity_scroll_conflict);
    12     }
    13 }

     

     一个辅助的drawable

    textview_background2.xml:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <shape xmlns:android="http://schemas.android.com/apk/res/android">
     3     <!-- 实心 -->
     4     <solid android:color="@android:color/holo_blue_light" />
     5     <!-- 边框 -->
     6     <stroke
     7         android:width="2dp"
     8         android:color="@android:color/holo_blue_dark" />
     9     <!-- 圆角 -->
    10     <corners android:radius="3dp" />
    11     <!-- 边距 -->
    12     <padding
    13         android:bottom="5dp"
    14         android:left="5dp"
    15         android:right="5dp"
    16         android:top="5dp" />
    17 </shape>

     

     

     

     

     

     

     

     

  • 相关阅读:
    访问者模式(Visitor)
    策略模式
    职责链模式(Chain of Responsibility)
    模版方法模式
    逃离大厦第80关与马踏棋盘
    结合JDK源码看设计模式——迭代器模式
    Java并发——线程介绍
    结合JDK源码看设计模式——模板方法模式
    结合JDK源码看设计模式——桥接模式
    结合JDK源码看设计模式——组合模式
  • 原文地址:https://www.cnblogs.com/hankzhouAndroid/p/9005977.html
Copyright © 2020-2023  润新知