滑动冲突的解决方式

1.外部拦截
点击事件斗仙经过父容器的拦截处理,如果父容器需要此事件就拦截,否则就不拦截。外部拦截需要重写父容器的onInterceptTouchEvent方法,在内部做相应的拦截即可。
2.内部拦截
内部拦截是指父容器不拦截任何事件,所有的时间都传递给子元素,如果子元素需要此事件就直接消耗掉,否则交由父容器处理,此方式需要配合requestDisallowInterceptTouchEvent方法才能正常工作。


外部拦截:
我们来实现一个类似于ViewPager中检讨ListView的效果,为了制造滑动冲突,我们写一个类似于ViewPager的控件,名字就叫做HorizontalScrollViewEx
为了实现ViewPager的效果,我们定义了一个类似于水平LinearLayout的东西,只不过他可以水平滑动,初始化时我们在它内部添加若干ListView,这样一来内部的ListView和本身出现了类似于场景1中的冲突。
解决代码如下:

public class MainActivity extends Activity {

    private HorizontalScrollViewEx mListContainer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        // TODO Auto-generated method stub
        LayoutInflater inflater = getLayoutInflater();
        mListContainer = (HorizontalScrollViewEx) findViewById(R.id.testview);
        final int screenWidth = MyUtils.getScreenMetrics(this).x;
        final int screenHeight = MyUtils.getScreenMetrics(this).y;

        for (int i = 0; i < 3; i++) {
            ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.content_layout, mListContainer, false);
            layout.getLayoutParams().width = screenWidth;
            TextView textView = (TextView) layout.findViewById(R.id.title);
            textView.setText("page " + (i + 1));
            textView.setBackgroundColor(Color.rgb(255 / (i + 1), 255 / (i + 1), 0));
            createList(layout);
            mListContainer.addView(layout);
        }
    }

    private void createList(ViewGroup layout) {
        ListView listView = (ListView) layout.findViewById(R.id.list);
        ArrayList<String> datas = new ArrayList<String>();
        for (int i = 0; i < 50; i++) {
            datas.add("name " + i);
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.content_list_item, R.id.name, datas);
        listView.setAdapter(adapter);
    }

}

我们在MainActivity中创建了3个ListView加入到自定义的HorizontalScrollViewEx 中,这样HorizontalScrollViewEx 为父容器而ListView为子元素。
采用外部拦截的解决方式:
修改父容器的拦截事件即修改HorizontalScrollViewEx 中的onInterceptTouchEvent方法 修改内容如下:

@Override
    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: {
            intercepted = false;
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
                intercepted = true;
            }
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            int deltaX = x - mLastXIntercept;
            int deltaY = y - mLastYIntercept;
            if (Math.abs(deltaX) > Math.abs(deltaY)) {
                intercepted = true;
            } else {
                intercepted = false;
            }
            break;
        }
        case MotionEvent.ACTION_UP: {
            intercepted = false;
            break;
        }
        default:
            break;
        }

        mLastX = x;
        mLastY = y;
        mLastXIntercept = x;
        mLastYIntercept = y;

        return intercepted;
    }

在滑动过程中当水平距离大时Math.abs(deltaX) > Math.abs(deltaY)就判断为水平滑动。
Demo源码下载


内部拦截:
首先自定义一个ListView:

public class ListViewEx extends ListView {

    private HorizontalScrollViewEx2 mHorizontalScrollViewEx2;
    // 分别记录上次滑动的坐标
    private int mLastX = 0;
    private int mLastY = 0;

    public ListViewEx(Context context) {
        super(context);

    }

    public ListViewEx(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // TODO Auto-generated constructor stub
    }

    public ListViewEx(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(true);
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            int deltaX = x - mLastX;
            int deltaY = y - mLastY;
            if (Math.abs(deltaX) > Math.abs(deltaY)) {
                mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(false);
            }
            break;
        }
        case MotionEvent.ACTION_UP: {
            break;
        }
        default:
            break;
        }
        mLastX = x;
        mLastY = y;
        return super.dispatchTouchEvent(event);
    }

    public void setParent(HorizontalScrollViewEx2 ex) {
        // TODO Auto-generated method stub
        mHorizontalScrollViewEx2 = ex;
    }

}

然后修改父容器的onInterceptTouchEvent方法

@Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            mLastX = x;
            mLastY = y;
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
                return true;
            }
            return false;
        } else {
            return true;
        }
    }

这就是内部拦截解决常见冲突
源码Demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值