Android 滑动冲突与解决策略

论坛 期权论坛 脚本     
匿名技术用户   2020-12-22 08:59   19   0

安卓开发过程中滑动冲突的情形主要有三类:

① 父view与子view的滑动方向不同,如:父view左右滑动,子view上下滑动或相反;

这种情形是比较简单的,只需要根据不同的滑动动作进行相应的拦截与处理即可。

② 父view与子view的滑动方向相同,即,父view左右,子view也左右,父view上下,子view也是上下;

这种情形需要根据具体情况来进行拦截处理,比如父View在出现子View滑动到边缘的情况才进行

拦截处理或者其他情况。

③ 以上两种情形,多个View的嵌套。

这种情形虽比较复杂,但根据上面两种情形的处理法则分开进行处理即可。


滑动冲突的解决策略的理论基础为安卓的事件分发机制,不甚了解的朋友可以去先补补这方面的知识。

针对滑动冲突的解决策略有以下两种:

一种是外部拦截法:即是当事件满足滑动条件,通过父View的onInterceptTouchEvent方法对其进行

拦截,拦截之后将直接进入父View的onTouchEvent进行事件消费,不会再传入下级view;

二种是内部拦截法:即是通过子View的dispatchTouchEvent方法接收到down事件,然后获取父View的requestDisallowInterceptTouchEvent方法禁止其onInterceptTouchEvent拦截,当满足父View滑动条件的

时候才允许。

第二种方法需要父View不拦截down事件,一般情况下也是不拦截down事件的,因为拦截了down事件,

所有子元素点击事件都会失效。建议采用第一种方法,易于理解,不容易出错。


针对第一种方法,下面

一个下拉刷新的SwipeRefreshLayout里面嵌套了左右滑动、并且在pullToRefreshListView头的viewPage

和上下滑动pullToRefreshListView(这里解释一下,pullToRefreshListView禁掉了它的下拉刷新功能,只用它

的上拉刷新),若不做解决事件冲突处理,就会出现只能父View下拉刷新,viewPager左右滑动无效,并且当

ListView往下滑动后不能再上滑,因为上滑时候的下拉事件被父view拦截了,所以这里有了两种冲突情形。

首先先分析viewPage与父view SwipeRefreshLayout的滑动冲突,一个上下,一个左右,那好办,只要重写SwipeRefreshLayout的onInterceptTouchEvent对滑动事件进行事件判断,如果是左右滑动的那么返回false

进行拦截,事件将直接传到子View,即传给了viewPager,实现其左右滑动的操作。然后说说pullToRefreshListView

与父view SwipeRefreshLayout的滑动冲突,因为两者都要上滑即手势下拉的操作,所以产生了冲突。而这里我

只是想当pullToRefreshListView滑动到顶部才使能SwipeRefreshLayout的下拉刷新,所以思路就是当没滑动到

顶部的时候SwipeRefreshLayout的onInterceptTouchEvent方法返回false 不进行拦截,把事件传给他的子View pullToRefreshListView,从而实现其上滑操作,直到滑动到了顶部父View才对事件进行拦截,如此便解决了

事件的冲突。

获取子View pullToRefreshListView,并开启滑动监听,判断是否处于顶部

<span style="font-size:14px;">                if(getChildAt(0).getId() == R.id.pullToRefreshListView){
                    ((PullToRefreshListView)getChildAt(0)).getRefreshableView().setOnScrollListener(new AbsListView.OnScrollListener() {
                        @Override
                        public void onScrollStateChanged(AbsListView view, int scrollState) {}
                        @Override
                        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                            if(firstVisibleItem==0){
                                isFirst = true;
                            }else{
                                isFirst = false;
                            }
                        }
                    });
                }</span>

重写onInterceptTouchEvent进行条件判断

<span style="font-size:14px;"> @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPrevX = MotionEvent.obtain(event).getX();
                break;
            case MotionEvent.ACTION_MOVE:
                final float eventX = event.getX();
                float xDiff = Math.abs(eventX - mPrevX);
                if (xDiff > mTouchSlop) {
                    return false;
                }
                if(!isFirst){
                    return false;
                }
        }
        return super.onInterceptTouchEvent(event);
    }</span>

为了精准判断滑动的方式,我们在自定义viewgroup里面重写onInterceptTouchEvent时,需要对滑动

的xy轴距离判断大小,若竖直方向距离大则认为是竖直滑动,否则认为是水平滑动。


而第二种方法一般代码如下:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                if("满足条件")
                    getParent().requestDisallowInterceptTouchEvent(false);
                break;
        }
        return super.dispatchTouchEvent(ev);
    }



分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP