Android Event事件分发

前言

Android Event事件分发:子View优先获取滑动事件

注:本文章不讲事件分发理论,直接给实现先方案。

最终效果

滑动冲突

如视频中,我的条形统计图可以左右滑动,统计图和左右滑动的ViewPage冲突,也和上下滚动的ScrollView冲突。我们的需求是:子View优先获取滑动事件

解决思路

Android Event事件分发_第1张图片

  1. ViewParent接口中有个方法叫做requestDisallowInterceptTouchEvent,即请求ViewGroup不允许侦听触摸事件。解决思路:我们判断,当子View获取到ACTION_DOWN时,我们通知父布局设置不允许侦听触摸事件,子View获取到ACTION_UP时,我们通知父布局设置允许侦听触摸事件,即可轻松解决滑动冲突问题。

  2. 由于考虑到多个滑动冲突同时存在的情况,因此我把通知写成“观察者模式”,无论你的APP中有多少个冲突,都可以统一用这个工具解决。

代码实现:观察模式的通知类

package com.hmongsoft.merchant.util.eventsUtil;

import java.util.HashMap;

/**
 * 事件拦截管理器(观察者模式)
 */
public class EventInterceptManager {

    //单例
    private static class Holder{
        private static final EventInterceptManager eventInterceptManager=new EventInterceptManager();
    }
    public static EventInterceptManager INSTANCE(){
        return Holder.eventInterceptManager;
    }
    private EventInterceptManager() {}

    //用于存储ViewAction的Hash
    private HashMap<ViewActionTag,CallBack> viewHash=new HashMap<>();

    /**
     * 第一步: 父布局监听子View事件
     * @param tag  View回调接口的标签
     * @param callback 回调的接口实现类
     */
    public void register(ViewActionTag tag, CallBack callback){
        viewHash.put(tag,callback);
    }

    /**
     * 第二步:子View请求父布局设置
     * @param tag View回调接口的标签
     * @param isReleaseEvent 是否需要
     */
    public void request(ViewActionTag tag, Boolean isReleaseEvent){
        CallBack actionCallback=viewHash.get(tag);
        if (actionCallback!=null)actionCallback.todo(tag,isReleaseEvent);
    }

    /**
     * 回调接口
     */
    public interface CallBack{
        void todo(Object tag,Object data);
    }

}

代码实现:枚举标签

注:同一个APP中,解决一处滑动冲突,就手动在这里增加一个枚举标签即可

package com.hmongsoft.merchant.util.eventsUtil;

public enum ViewActionTag {
    INDEX_VIEW_PAGE,//对应:案例2
    ACCOUNT_SCROLL_VIEW//对应:案例1
}

使用方法——第一步: 父布局监听子View通知

案例1:

ScrollView my_account_scroll_view=(ScrollView) view.findViewById(R.id.my_account_scroll_view);
EventInterceptManager.INSTANCE().register(ViewActionTag.ACCOUNT_SCROLL_VIEW, new EventInterceptManager.CallBack() {
    @Override
    public void todo(Object tag, Object data) {
        if (tag ==ViewActionTag.ACCOUNT_SCROLL_VIEW){
            //请求ScrollView允许或者不允许侦听触摸事件
            my_account_scroll_view.requestDisallowInterceptTouchEvent((Boolean) data);
        }
    }
});

案例2:

ViewPager viewPager = findViewById(R.id.viewPager);
EventInterceptManager.INSTANCE().register(ViewActionTag.INDEX_VIEW_PAGE, new EventInterceptManager.CallBack() {
    @Override
    public void todo(Object tag, Object data) {
        //请求ScrollView允许或者不允许侦听触摸事件
        if (tag ==ViewActionTag.INDEX_VIEW_PAGE)viewPager.requestDisallowInterceptTouchEvent((Boolean) data);
    }
});

使用方法——第二步:子View请求父布局设置

//自定的可以左右滚动的View(即:子View)
public class ScrollBarChart extends View {

    public ScrollBarChart(Context context) {
        this(context,null);
    }

    public ScrollBarChart(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ScrollBarChart(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                //通知父布局:要求父布局不允许拦截事件
                EventInterceptManager.INSTANCE().request(ViewActionTag.ACCOUNT_SCROLL_VIEW,true);//对应:案例1
                EventInterceptManager.INSTANCE().request(ViewActionTag.INDEX_VIEW_PAGE,true);//对应:案例2
                break;
            case MotionEvent.ACTION_UP:
                //通知父布局:恢复默认设置
                EventInterceptManager.INSTANCE().request(ViewActionTag.ACCOUNT_SCROLL_VIEW,false);//对应:案例1
                EventInterceptManager.INSTANCE().request(ViewActionTag.INDEX_VIEW_PAGE,false);//对应:案例2
               
                break;
        }
        return super.dispatchTouchEvent(event);
    }

}

在子View的dispatchTouchEvent()方法中,通知父布局设置。

案例到此结束!

你可能感兴趣的:(Android代码块总结,android,java,开发语言)