完美解决嵌套了HorizontalScrollView的父容器不响应点击事件

在安卓开发中,当一个clickable为true的ViewGroup控件包含了一个HorizontalScrollView的时候,点击HorizontalScrollView的位置既不能响应ViewGroup控件的点击事件,当然也不能使ViewGroup控件设置的selector背景变色,经典的用法是 Adapter View 的 item中包含一个HorizontalScrollView,item的点击就不能响应,必须点除了HorizontalScrollView的别的位置,很不友好。

因为HorizontalScrollView将事件的很多动作都拦截消耗掉了,包括但不限于:

MotionEvent.ACTION_DOWN
MotionEvent.ACTION_MOVE
MotionEvent.ACTION_UP
MotionEvent.ACTION_CANCEL

其中一般点击事件需要响应的三个动作DOWN、UP、CANCEL全被拦截掉了,如何解决呢?

遇事不决问百度,百度不决问谷歌。网上提供了一种方法,就是给包含HorizontalScrollView的父控件设置android:descendantFocusability属性,值有三个选择:

        beforeDescendants:viewgroup会优先其子类控件而获取到焦点

        afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点

        blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点

遇到点击冲突时,给包含HorizontalScrollView的父控件设置android:descendantFocusability=“blocksDescendants”,据说可以解决冲突。但本人亲测无效,原因不明,可能是API版本或者手机问题(?)

 

下面我自己写了几行代码,定义了一个很简单但很有效的自定义HorizontalScrollView,完美结局了冲突,item点击事件和HorizontalScrollView本身的左右滑动还有RecyclerView的上下滑动,再外面是ViewPager的左右滑动都没有冲突,令人神清气爽

 

package com.yc.ui.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.HorizontalScrollView;

/**
 * 兼容父容器点击事件的HorizontalScrollView
 *
 * created by yc on 2018-12-27
 */
public class ParentClickHorizontalScrollView extends HorizontalScrollView {

    private View parentView;

    public ParentClickHorizontalScrollView(Context context) {
        super(context);
    }

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

    public ParentClickHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public View getParentView() {
        return parentView;
    }

    public void setParentView(View parentView) {
        this.parentView = parentView;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //注意 getParent() 是 ViewParent 但不一定是 View
        if (parentView == null
                && getParent() != null
                && getParent() instanceof View) {
            parentView = (View) getParent();
        }

        if (parentView != null) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    parentView.onTouchEvent(ev);  //使父容器也能响应本次按下事件
                    break;

                case MotionEvent.ACTION_MOVE: //当触发滑动时,将父容器的按下响应失效
                    //修改动作为ACTION_CANCEL
                    ev.setAction(MotionEvent.ACTION_CANCEL);
                    parentView.onTouchEvent(ev);
                    //父容器响应后恢复事件原动作
                    ev.setAction(MotionEvent.ACTION_MOVE);
                    break;

                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    parentView.onTouchEvent(ev);  //将松手事件,先行传递给父容器响应
                    break;
            }
        }
        return super.onTouchEvent(ev);  //无论如何 本身都响应事件
    }
}

 

简单吧,几行代码就搞定了,不知道为什么网上这么难找,可能是我组织不好关键字所以搜不到╮(╯▽╰)╭

使用的话布局中直接用ParentClickHorizontalScrollView 替换HorizontalScrollView即可,父控件和ParentClickHorizontalScrollView本身无需设置额外其他属性

 

你可能感兴趣的:(安卓)