iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >android中view手势滑动冲突的解决方法
  • 944
分享到

android中view手势滑动冲突的解决方法

view方法Android 2022-06-06 06:06:37 944人浏览 泡泡鱼
摘要

Android手势事件的冲突跟点击事件的分发过程息息相关,由三个重要的方法来共同完成,分别是:dispatchTouchEvent、onInterceptTouchEvent和

Android手势事件的冲突跟点击事件的分发过程息息相关,由三个重要的方法来共同完成,分别是:dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。


public boolean dispatchTouchEvent(MotionEvent ev)

这个方法用来进行事件的分发。如果事件传递到view,那么这个方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件。

   


 public boolean onInterceptTouchEvent(MotionEvent event)

在上述方法内部调用,用来判断是拦截某个事件,如果当前View拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。


 public boolean onTouchEvent(MotionEvent event)

 在dispathcTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View无法再次接到事件。

例:


  public boolean dispatchTouchEvent(MotionEvent ev){
       boolean consume = false;
      if(onInterceptTouchEvent(ev)){
          consume = onTouchEvent(ev);
       }  else {
         consum = child.dispathcTouchEvent(ev);
      }
    return consume;
   }

手势冲突的解决方法就是用上面的三个方法;主要分为两种解决方法:·1外部拦截法 2内部拦截法

1.常见的滑动冲突场景

1.1 外部滑动方向和内部滑动的方向不一致

这种情况我们经常遇见,比如使用viewpaper+listview时,在这种效果中,可以通过左右滑动切换页面,而每一个页面往往又是一个listview,本来在这种情况下是有冲突的,但是Viewpaper内部处理了这个滑动冲突,因此采用viewpaper我们无需关注这个问题,如果我们采用的不是Viewpaper而是ScrollView等,那么必须手动处理滑动冲突,否则内外两层只能有一层滑动,那就是滑动冲突。另外内部左右滑动,外部上下滑动也同样属于该类。

1.2 外部滑动方向和内部滑动方向一致

这种情况就比较复杂,当内外两层都在同一个方向可以滑动的时候,显然存在逻辑问题,因为当手指开始滑动的时候,系统无法知道用户到底是想让那一层动,所以当手指滑动的时候就会出现问题,要么只能一层动,要么内外两成动的都很卡顿。

2.给出解决方案

2.1 外部拦截法

针对场景1,我们可以发现外部和内部的滑动方向不一样也就是说只要判断当前dy和dx的大小,如果dy>dx,那么当前就是竖直滑动,否则就是水平滑动。明确了这个我就就可以根据当前的手势开始拦截了。


从上一节中我们分析了view的事件分发,我们知道点击事件的分发顺序是 通过父布局分发,如果父布局没有拦截,即onInterceptTouchEvent返回false,才会传递给子View。所以我们就可以利用onInterceptTouchEvent()这个方法来进行事件的拦截。来看一下代码:


 public boolean onInterceptTouchEvent(MotionEvent event) {
    boolean intercepted = false;
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN: {
      intercepted = false;
      break;
    }
    case MotionEvent.ACTION_MOVE: {
      if(父容器拦截的规则){
        intercepted=true;
      }else{
        intercepted=false;
      }
      break;
    }
    case MotionEvent.ACTION_UP: {
      intercepted = false;
      break;
    }
    default:
      break;
    }
    mLastXIntercept=x;
    mLastYIntercept=y;
    return intercepted;
  }

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

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

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

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

下面我们来具体做一下拦截的操作,我们需要在水平滑动的时候父容器拦截事件。


public boolean onInterceptTouchEvent(MotionEvent event) {
    boolean intercepted = false;
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN: {
      intercepted = false;
      break;
    }
    case MotionEvent.ACTION_MOVE: {
      int deltaX=x-mLastXIntercept;
      int deltaY=y=mLastYIntercept;
      if(Math.abs(deltaX)>Math.abs(deltaY)){
        intercepted=true;
      }else{
        intercepted=false;
      }
      break;
    }
    case MotionEvent.ACTION_UP: {
      intercepted = false;
      break;
    }
    default:
      break;
    }
    mLastXIntercept=x;
    mLastYIntercept=y;
    return intercepted;
  }

 从上面的代码来看,我们只是修改了一下拦截条件而已,所以说外部拦截还是很简单方便的。在滑动的过程中,当水平方向的距离大时就判定水平滑动。

还是一贯我们做实验来证明理论的风格,我们来自定义一个HorizontalScrollView来体现一下用外部拦截法解决冲突的快感。

先上一下代码:


package com.gxl.viewtest;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.text.LoginFilter;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

public class HorizontalScrollView extends ViewGroup {
  private final String TAG = "HorizontalScrollView";
  private VelocityTracker mVelocityTracker;
  private Scroller mScroller;
  private int mChildrenSize;
  private int mChildWidth;
  private int mChildIndex;
  //上次滑动的坐标
  private int mLastX = 0;
  private int mLastY = 0;
  //上次上次拦截滑动的坐标
  private int mLastXIntercept = 0;
  private int mLastYIntercept = 0;
  public HorizontalScrollView(Context context) {
    super(context);
    init(context);
  }
  public HorizontalScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
  }
  public HorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
  }
  public void init(Context context) {
    mVelocityTracker = VelocityTracker.obtain();
    mScroller = new Scroller(context);
  }
  public boolean onInterceptTouchEvent(MotionEvent event) {
    boolean intercepted = false;
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN: {
        intercepted = false;
        break;
      }
      case MotionEvent.ACTION_MOVE: {
        int deltaX = x - mLastXIntercept;
        int deltaY = y - mLastYIntercept;
        if (Math.abs(deltaX) > Math.abs(deltaY)) {
          intercepted = true;
        } else {
          intercepted = false;
        }
        break;
      }
      case MotionEvent.ACTION_UP: {
        intercepted = false;
        break;
      }
      default:
        break;
    }
    mLastX = x;
    mLastY = y;
    mLastXIntercept = x;
    mLastYIntercept = y;
    return intercepted;
  }
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    mVelocityTracker.addMovement(event);
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
        break;
      case MotionEvent.ACTION_MOVE:
        int deltaX = x - mLastX;
        if((getScrollX()-deltaX)>=0&&(getScrollX()-deltaX)<=(getMeasuredWidth()-ScreenUtils.getScreenWidth(getContext()))) {
          scrollBy(-deltaX, 0);
        }
        break;
      case MotionEvent.ACTION_UP:
        mVelocityTracker.computeCurrentVelocity(1000);
        float xVelocityTracker = mVelocityTracker.getXVelocity();
        if (Math.abs(xVelocityTracker) > 50) {
          if (xVelocityTracker > 0) {
            Log.i(TAG, "快速向右划");
          } else {
            Log.i(TAG, "快速向左划");
          }
        }
        mVelocityTracker.clear();
        break;
    }
    mLastX = x;
    mLastY = y;
    return true;
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int measuredWidth = 0;
    int measureHeight = 0;
    final int childCount = getChildCount();
    measureChildren(widthMeasureSpec, heightMeasureSpec);
    int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec);
    int widthSpaceMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec);
    int heightSpaceMode = MeasureSpec.getMode(heightMeasureSpec);
    if (childCount == 0) {
      setMeasuredDimension(0, 0);
    } else if (heightSpaceMode == MeasureSpec.AT_MOST && widthSpaceMode == MeasureSpec.AT_MOST) {
      final View childView = getChildAt(0);
      measuredWidth = childView.getMeasuredWidth() * childCount;
      measureHeight = childView.getMeasuredHeight();
      setMeasuredDimension(measuredWidth, measureHeight);
    } else if (heightSpaceMode == MeasureSpec.AT_MOST) {
      measureHeight = getChildAt(0).getMeasuredHeight();
      setMeasuredDimension(widthSpaceSize, measureHeight);
    } else if (widthSpaceMode == MeasureSpec.AT_MOST) {
      final View childView = getChildAt(0);
      measuredWidth = childView.getMeasuredWidth() * childCount;
      setMeasuredDimension(measuredWidth, heightSpaceSize);
    }
  }
  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    Log.i(TAG, "onLayout: " + getMeasuredWidth());
    int childleft = 0;
    final int childCount = getChildCount();
    mChildrenSize = childCount;
    for (int i = 0; i < mChildrenSize; i++) {
      final View childView = getChildAt(i);
      if (childView.getVisibility() != View.GoNE) {
        final int childWidth = childView.getMeasuredWidth();
        mChildWidth = childWidth;
        childView.layout(childleft, 0, childleft + mChildWidth, childView.getMeasuredHeight());
        childleft += childWidth;
      }
    }
  }
  private void smoothScrollTo(int destX,int destY)
  {
    int scrollX=getScrollX();
    int delta=destX-scrollX;
    mScroller.startScroll(scrollX,0,delta,0,1000);
  }
  @Override
  public void computeScroll() {
    if (mScroller.computeScrollOffset()) {
      scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
      postInvalidate();
    }
  }
}

再来看一下布局文件
  


 <com.gxl.viewtest.HorizontalScrollView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:background="#00ff00"
    >
    <ListView
      android:id="@+id/listview1"
      android:layout_width="600dp"
      android:layout_height="match_parent"
      android:background="@color/colorPrimary"
      >
    </ListView>
    <ListView
      android:id="@+id/listview2"
      android:layout_width="600dp"
      android:layout_height="match_parent"
      android:background="@color/colorAccent"
      >
    </ListView>
    <ListView
      android:id="@+id/listview3"
      android:layout_width="600dp"
      android:layout_height="match_parent"
      android:background="#ff0000"
      >
    </ListView>
  </com.gxl.viewtest.HorizontalScrollView>

以上就是外部处理滑动冲突的代码,认真看一下,思路还是很清晰的。里面还涉及了一些自定义View的知识,我会在后面的博文中认真分析一下代码,你先看一下onInterceptTouchEvent处理滑动冲突的部分。
看一下效果图哈。

2.2 内部拦截法

内部拦截法是指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器去处理,这种方法和Android中的事件分发机制不一致,需要配合requestDisallowInterceptTouchEvent方法才能正常工作,这个方法的大体解释就是:

requestDisallowInterceptTouchEvent是ViewGroup类中的一个公用方法,参数是一个boolean值,官方介绍如下

Called when a child does not want this parent and its ancestors to intercept touch events with ViewGroup.onInterceptTouchEvent(MotionEvent).
This parent should pass this call onto its parents. This parent must obey this request for the duration of the touch (that is, only clear the flag after this parent has received an up or a cancel.

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

使用起来外部拦截事件略显复杂一点。下面我也先来看一下它的通用模板(注意下面的代码是定义在子View中的):


public boolean onInterceptTouchEvent(MotionEvent event) {
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN: {
      parent.requestDisallowInterceptTouchEvent(true); //父布局不要拦截此事件
      break;
    }
    case MotionEvent.ACTION_MOVE: {
      int deltaX=x-mLastXIntercept;
      int deltaY=y=mLastYIntercept;
      if(父容器需要拦截的事件){
        parent.requestDisallowInterceptTouchEvent(false); //父布局需要要拦截此事件
      }
      break;
    }
    case MotionEvent.ACTION_UP: {
      intercepted = false;
      break;
    }
    default:
      break;
    }
    mLastXIntercept=x;
    mLastYIntercept=y;
    return super.dispathTouchEvent(event);
  }

上述代码是内部拦截法的典型代码,当面对不同的滑动策略时只需要修改里面的条件即可,其他不需要修改做改动而且也不能改动。

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

您可能感兴趣的文章:Android实现手势滑动多点触摸放大缩小图片效果Android GestureDetector手势滑动使用实例讲解Android实现图片自动轮播并且支持手势左右无限滑动Android手势滑动实现ImageView缩放图片大小Android实现手势滑动多点触摸缩放平移图片效果Android实现手势滑动多点触摸缩放平移图片效果(二)Android 高仿微信朋友圈动态支持双击手势放大并滑动查看图片效果Android手势滑动实现两点触摸缩放图片Android实现手势滑动和简单动画效果Android手势左右滑动效果


--结束END--

本文标题: android中view手势滑动冲突的解决方法

本文链接: https://www.lsjlt.com/news/23306.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android中DrawerLayout+ViewPager滑动冲突的解决方法
    DrawerLayout 是 Android 官方的侧滑菜单控件,而 ViewPager 相信大家都很熟悉了。今天这里就讲一下当在 DrawerLayout 中嵌套 ViewPager 时,要如何解决滑动冲突的问题,效果如下:首先,让我们先...
    99+
    2023-05-31
    android drawerlayout viewpager
  • Android应用中的View出现滑动冲突如何解决
    本篇文章给大家分享的是有关Android应用中的View出现滑动冲突如何解决,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1、外部滑动方向和内部滑动方向不一致考虑这样一种场景,...
    99+
    2023-05-31
    view roi android
  • ViewPager2滑动冲突的解决方法
    ViewPager2滑动冲突解决,供大家参考,具体内容如下 本文章对ViewPager2的滑动冲突没有提供完善的解决方案,仅为巩固解决滑动冲突方面的知识 首先看看没有解决滑动冲突时...
    99+
    2024-04-02
  • Android之解决RecyclerView与NestedScrollView的滑动冲突方法
    1、解决RecyclerView与NestedScrollView的滑动冲突 问题一:当我们滑动RecyclerView组件时,上方的轮播图并没有进行滑动(NestedScrollView没有滑动,即...
    99+
    2023-09-15
    android java 开发语言
  • Android中怎么解决嵌套滑动冲突
    本篇文章为大家展示了Android中怎么解决嵌套滑动冲突,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一.会产生滑动冲突的情况那么什么时候会产生滑动冲突呢?比如你有个activity,activit...
    99+
    2023-05-30
    android
  • Android应用中出现滑动冲突如何解决
    今天就跟大家聊聊有关Android应用中出现滑动冲突如何解决,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。场景一:类似于ViewPager嵌套Fragmnet并且在Fragmnet中...
    99+
    2023-05-31
    android roi
  • Android应用的中滑动事件出现冲突如何解决
    Android应用的中滑动事件出现冲突如何解决?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。外部拦截法外部拦截法是指在有点击事件时都要经过父容器,那么在父容器时如果需要拦截...
    99+
    2023-05-31
    android roi
  • Android进阶 View事件体系(三):典型的滑动冲突情况和解决策略
    Android进阶 View事件体系(三):典型的滑动冲突情况和解决策略 内容概要 本篇文章为总结View事件体系的第三篇文章,前两篇文章的在这里: Android进阶 View事件体系(一):概要...
    99+
    2023-09-02
    android java ui
  • Android使用NestedScrollView 内嵌RecycleView滑动冲突问题解决
    目录场景描述实现思路问题和优化优化场景描述 使用NestedScrollView 内嵌RecycleView时,当用户上滑时,NestedScrollView需要首先响应上滑事件,直...
    99+
    2024-04-02
  • 在Android中使用listview时出现滑动冲突如何解决
    在Android中使用listview时出现滑动冲突如何解决?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Android listview的滑动冲突解决方法在Android开发...
    99+
    2023-05-31
    listview android roi
  • Android使用NestedScrollView内嵌RecycleView滑动冲突问题如何解决
    这篇“Android使用NestedScrollView内嵌RecycleView滑动冲突问题如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,...
    99+
    2023-07-02
  • View事件分发原理和ViewPager+ListView嵌套滑动冲突怎么解决
    今天小编给大家分享一下View事件分发原理和ViewPager+ListView嵌套滑动冲突怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面...
    99+
    2023-06-30
  • git解决冲突的方法
    这篇文章将为大家详细讲解有关git解决冲突的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。git解决冲突的方法:首先在项目目录上点击右键,点击双向红箭头的位置;然后选择需要修改冲突的文件,选择merg...
    99+
    2023-06-06
  • jQuery 名称冲突的解决方法
    jQuery 使用名为 noConflict() 的方法来解决该问题。 var jq=jQuery.noConflict(),帮助您使用自己的名称(比如 jq)来代替 $ 符号。 示...
    99+
    2022-11-21
    jQuery 名称冲突
  • Android 中ScrollView与ListView冲突问题的解决办法
    Android 中ScrollView与ListView冲突问题的解决办法自定义MyListViewpublic class MyListView extends ListView { public MyListView(Context...
    99+
    2023-05-30
    android scrollview listview
  • Android实现View滑动效果的6种方法
    本文实例为大家分享了Android实现View滑动效果的具体代码,供大家参考,具体内容如下 一、View的滑动简介 View的滑动是Android实现自定义控件的基础,同时在开发中我...
    99+
    2024-04-02
  • 解决Maven依赖冲突的方法
    目录背景处理回顾背景 在项目中screw-core依赖时发生了冲突,控制台指出是log4j产生的依赖冲突,导致程序报错无法运行,是一个典型的maven依赖冲突,基于这个问题进行 处理...
    99+
    2023-05-20
    Maven依赖冲突
  • springBoot启动报错log4j冲突的解决方案
    springBoot启动报错log4j冲突 先上一段报错内容 SLF4J: Class path contains multiple SLF4J bindings. SLF4J: ...
    99+
    2024-04-02
  • React样式冲突解决问题的方法
    目录前言:CSS IN JS一、概念二、CSS Modules三、在项目中使用css Modules四、css module配合sass五、module.scss 使用步骤:六、总结...
    99+
    2023-03-10
    React样式冲突 React样式
  • 解决MongoDB技术开发中遇到的写入冲突冲突问题的方法研究
    解决MongoDB技术开发中遇到的写入冲突问题的方法研究在大规模并发访问下,MongoDB作为一种非关系型数据库,常常会遇到写入冲突的问题。这种冲突发生在多个客户端同时对同一文档进行写入操作时,可能会导致数据不一致的情况发生。为了解决这个问...
    99+
    2023-10-22
    MongoDB 解决方法 写入冲突
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作