• Android处理滑动冲突


    1、技术概述

    在Android开发中,不可避免地会遇到View嵌套的情况,而其中就会出现滑动冲突的现象,所以了解解决滑动冲突的方法是十分有必要的

    2、技术详述

    滑动冲突的场景

    常见的滑动冲突的场景主要有以下两种:

    • 父View滑动方向和子View滑动方向不一致
    • 父View滑动方向和子View滑动方向一致

    滑动冲突产生的原因

    Android的事件分发机制是从父View传递到子View的,首先事件会传递到父View的dispatchTouchEvent方法中,而该方法会调用onInterceptTouchEvent方法判断父View在此时是否需要拦截该事件,如果用户在某个方向的滑动距离超过某一个阈值,则父View的onInterceptTouchEvent方法会返回true,此时父View会直接接管该事件流程直到出现ACTION_UP事件也就是用户抬手时,事件会直接交由父View的onTouchEvent方法处理,造成了子View无法接收到事件;亦或是父View在ACTION_DOWN事件时放弃了该事件,父View会将该事件分发给所有子View处理,此时某个子View先行检测到滑动,此时子View的onInterceptTouchEvent将返回true,事件就会由子View的onTouchEvent方法处理,若该方法返回了true,那么该事件将不会被父View处理。此时便产生了滑动冲突。

    滑动冲突的解决方案

    滑动冲突的解决方法主要有两种,分为外部拦截法与内部拦截法

    外部拦截法

    外部拦截法的原理是重写父View的onInterceptTouchEvent方法,通过判断父View是否需要该事件来选择是否拦截该事件,从而解决了滑动冲突

    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: 
                //父View的ACTION_DOWN事件必须返回false,否则后续ACTION_MOVE以及ACTION_UP事件会直接交由父View处理不会经过子View
                intercepted = false;
                break;
            case MotionEvent.ACTION_MOVE: 
                if (父容器需要当前点击事件) {
                    intercepted = true;
                } else {
                    intercepted = false;
                }
                break;
            case MotionEvent.ACTION_UP: 
                //如果父View拦截了该事件,则子View会接收不到ACTION_UP事件导致点击事件失效
                intercepted = false;
                break;
            default:
                break;
        }
        mLastXIntercept = x;
        mLastYIntercept = y;
        return intercepted;
    }
    
    内部拦截法

    内部拦截法的原理是重写子View的dispatchTouchEvent方法,利用调用父View的requestDisallowInterceptTouchEvent(true)方法使父View不处理该事件让事件分发给子View处理,如果子View不需要处理该事件则调用父View的requestDisallowInterceptTouchEvent(false)使父View重新具备处理事件的能力

    public boolean dispatchTouchEvent(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 - mLastX;
                int deltaY = y - mLastY;
                if (父容器需要此类点击事件) {
                    parent.requestDisallowInterceptTouchEvent(false);
                }
                break;
            case MotionEvent.ACTION_UP: 
                break;
            default:
                break;
        }
        mLastX = x;
        mLastY = y;
        return super.dispatchTouchEvent(event);
    }
    

    同时还需要重写父View的onInterceptTouchEvent方法,因为父View在处理ACTION_DOWN事件时是不受requestDisallowInterceptTouchEvent设置的标志位约束的,具体而言是在父View的dispatchTouchEvent方法中判断事件是ACTION_DOWN类型时会清除requestDisallowInterceptTouchEvent设置的标志位,如果父View处理了ACTION_DOWN事件,之后的ACTION_MOVE以及ACTION_UP事件就不会分发给子View,这时重写的·dispatchTouchEvent·方法里写的判断就都失效了。所以需要重写方法使父View不处理ACTION_DOWN事件从而让事件分发给子View

    public boolean onInterceptTouchEvent(MotionEvent event) {
        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            return false;
        } else {
            return true;
        }
    }
    

    3、总结

    滑动冲突可以利用外部拦截法以及内部拦截法处理,主要利用了onInterceptTouchEventrequestDisallowInterceptTouchEvent等方法进行处理

    4、参考文献

    《Android开发艺术探索》 任玉刚著. ————电子工业出版社

  • 相关阅读:
    使用java.util.LinkedList模拟实现内存页面置换算法--LRU算法
    JMS学习(八)-ActiveMQ Consumer 使用 push 还是 pull 获取消息
    判断二叉树是否是平衡二叉树 及二叉树各种操作汇总
    二叉树的前序、中序、后序的非递归遍历实现
    排列与组合的一些定理(二)
    找出数字在已排序数组中出现的次数
    SRM 212 Div II Level Two: WinningRecord,Brute Force
    覆写Activity的finish()方法
    POJ 2046 Gap 搜索- 状态压缩
    WebView利用UserAgent传递SESSIONID
  • 原文地址:https://www.cnblogs.com/Xily9/p/13184648.html
Copyright © 2020-2023  润新知