深坑系列之--onInterceptTouchEvent的move

相信大家都有接触过容器嵌套出现滑动冲突,尤其是轮播图和listView之间的滑动的不协调。那如何去解决呢?

在Android的View系列中分为两种ViewGroup和View,对于滑动事件的相关方法有:

  1. dispatchTouchEvent(ev);
  2. onInterceptTouchEvent(ev);  --->ViewGroup及子类独有的
  3. onTouchEvent(ev);

    这三个表示事件的分发,事件的拦截,事件的消费,一个触摸的事件一般分别先从dispathc->onIntercept->onTouch。当然是在默认的情况下。这三个方法返回值类型为boolean。返回值决定了这触摸事件的顺序和执行的结果。

触摸事件传递机制:

一般情况下,ViewGroup下包含子View,最近在做一个项目就是使用SwipeRefreshLayout+ViewPager以及常见的ListView,在滑动的时候,发现三个组件对滑动都有响应。。。体验很差。于是花了一个下午的时间把滑动事件又重新梳理了一下。废话少说,言归正传:

221240_XCrh_2978666.png

直接看图来的直观,画的好累,有错误还请指正哦,在黑色线条为人为不去干扰的传递机制,而在开发中我们通过onInterceprt()这个方法来改变这个传递的顺序。

onInterceprt():在返回true,表示拦截此次触摸事件,也就是不在往下传递触摸事件。默认传递。

dispatch():一般在开发中,不去动它。

onTouchEvent(): 事件的处理---->你要处理的逻辑代码。

注意:在dispatch()中不管你返回false还是true,对于触摸传递机制都不会往下传递。只有官方的return super事件才往下传递。

代码栗子:

222640_cvVs_2978666.png

自定义ViewGroup和自定义Button,在ViewGroup拦截action.Move事件,推理可得-->button的点击事件不受影响的。点击出现Toast

代码如下:

package com.example.huangzhibo.intercept;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
import android.widget.ScrollView;

import static android.R.attr.y;

/**
 * Created by HuangZhiBo on 2017/3/22.
 */

public class MyViewGroup extends RelativeLayout {

    private int y;

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

    private static final String TAG = "MyScrollView";


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean result = false;
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //DOWN事件千万不能拦截
                result = false;
                y = (int) ev.getY();
                Log.i(TAG, "onInterceptTouchEvent: ---ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onInterceptTouchEvent:------ACTION_MOVE ");
                float v = ((int)ev.getY() - y);
               /* Log.i(TAG, "onInterceptTouchEvent: "+v);
                if (Math.abs(v)>10) {
                    result = true;
                }else{
                    result = false;
                }*/
                result=true;
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "onInterceptTouchEvent: -----ACTION_UP");
                result = false;
                break;

        }
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "onTouchEvent: ---ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onTouchEvent:------ACTION_MOVE ");
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "onTouchEvent: -----ACTION_UP");
                break;
        }
        return super.onTouchEvent(ev);
    }
}
public class MyButton extends android.support.v7.widget.AppCompatButton {
    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    private static final String TAG = "MyButton";


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "onTouchEvent: ---ACTION_DOWN");

                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onTouchEvent:------ACTION_MOVE ");

                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "onTouchEvent: -----ACTION_UP");
                break;
        }
        return super.onTouchEvent(event);
    }
}

运行程序-> 点击button Toast并未出现,再看log信息,可以看出MOVE多次调用,只是点击为啥Move出现多次,猜测在onInterceptTouchEvent的MOVE直接返回true,虽然只是轻轻点击了一下,可系统认定为滑动事件(很微妙),此刻点击事件就无效了。

程序的log打印:

223239_mv0D_2978666.png

接着改善(ViewGroup):

package com.example.huangzhibo.intercept;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
import android.widget.ScrollView;

import static android.R.attr.y;

/**
 * Created by HuangZhiBo on 2017/3/22.
 */

public class MyViewGroup extends RelativeLayout {

    private int y;

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

    private static final String TAG = "MyScrollView";


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean result = false;
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //DOWN事件千万不能拦截
                result = false;
                y = (int) ev.getY();
                Log.i(TAG, "onInterceptTouchEvent: ---ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onInterceptTouchEvent:------ACTION_MOVE ");
                float v = ((int)ev.getY() - y);
                Log.i(TAG, "onInterceptTouchEvent: "+v);
                if (Math.abs(v)>10) {
                    result = true;
                }else{
                    result = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "onInterceptTouchEvent: -----ACTION_UP");
                result = false;
                break;

        }
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "onTouchEvent: ---ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onTouchEvent:------ACTION_MOVE ");
                break;
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "onTouchEvent: -----ACTION_UP");
                break;
        }
        return super.onTouchEvent(ev);
    }
}

log打印:

233515_FqHa_2978666.png

可以看出,我们在Move的滑动事件中,给它设置了个滑动距离才拦截滑动事件。这样用户点击了button由于对于微观的滑动来说,并未拦截。响应点击事件。

结束语:

在onInterceptTouchEvent中如果返回return Super.onInterceptTouchEvent(ev)以上代码无效,至于原因的从源代码分析,对于要进行人为干预的onInterceptTouchEvent 最好不要return Super.onInterceptTouchEvent( ).

转载于:https://my.oschina.net/huangzhi1bo/blog/865066

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值