具有子视图时,Android onInterceptTouchEvent不会获取操作

Aby*_*yss 2 java eclipse layout android view

我有父视图v扩展线性布局.孩子一个是LinearLayout,孩子二个是ScrollView.

我要让MyParent查看拦截垂直MotionEvent.ACTION_MOVE(仅限上下方向,子女scrollview.getScrollY()==0)及其父处理它,和其他MotionEvent由孩子处理

这是MyView.xml

  <?xml version="1.0" encoding="utf-8"?>
    <merge xmlns:android="http://schemas.android.com/apk/res/android" >
    <LinearLayout
        android:id="@+id/child_linear>
        android:height="50dp"
        android:width="50dp">
            ...something...
    </LinearLayout>
    <ScrollView
       android:id="@+id/child_scrollview>
      <LinearLayout/>
      </LinearLayout>
    </ScrollView>
    </merge> 
Run Code Online (Sandbox Code Playgroud)

这是我的代码如下

public class MyCustomView extends LinearLayout{
    public MyCustomView(Context context) {
        super(context);
        init();
    }
    private void init(){
        setOrientation(LinearLayout.VERTICAL);
        LayoutInflater inflater = 
(LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = inflater.inflate(R.layout.MyView, this, true);


    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        final int action = event.getAction();
        Log.d(log,"onInterceptTouchEvent : "+action);
        if (action == MotionEvent.ACTION_CANCEL || action == 
MotionEvent.ACTION_UP) {
            mIsBeingDragged = false;
            return false;
        }
        if (action != MotionEvent.ACTION_DOWN && mIsBeingDragged) {
            return true;
        }

        switch (action) {
            case MotionEvent.ACTION_MOVE: {
                if (isReadyForPull()) {
                    final float y = event.getY(), x = 
event.getX();
                    final float diff, oppositeDiff, absDiff;
                    diff = y - mLastMotionY;
                    oppositeDiff = x - mLastMotionX;
                    absDiff = Math.abs(diff);
                    ViewConfiguration config = 
ViewConfiguration.get(getContext());

                    if (absDiff > config.getScaledTouchSlop() &&  
absDiff > Math.abs(oppositeDiff) && diff >= 1f) {
                            mLastMotionY = y;
                            mLastMotionX = x;
                            mIsBeingDragged = true;
                            Log.d(log,"Flag setting");
                    }
                }
                break;
            }
            case MotionEvent.ACTION_DOWN: {
                if (isReadyForPull()) {
                    mLastMotionY = mInitialMotionY = event.getY();
                    mLastMotionX = event.getX();
                    mIsBeingDragged = false;
                }
                break;
            }
        }
        return mIsBeingDragged;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final int action=event.getAction();
        Log.d(log,"onTouchEvent : "+action);
        if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE: {
                Log.d(log,"ACTION MOVE RECEIVE");
                if (mIsBeingDragged) {
                    mLastMotionY = event.getY();
                    mLastMotionX = event.getX();
                    pullEvent();
                    return true;
                }
                break;
            }

            case MotionEvent.ACTION_DOWN: {
                if (isReadyForPull()) {
                    mLastMotionY = mInitialMotionY = event.getY();
                    return true;
                }
                break;
            }

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP: {
                if (mIsBeingDragged) {
                    mIsBeingDragged = false;

                    if (mState == State.RELEASE_TO_REFRESH ) {
                        setState(State.REFRESHING);
                        return true;
                    }
                    if (isRefreshing()) {
                        smoothScrollTo(-mHeaderHeight , null);
                        return true;
                    }

                    setState(State.RESET);
                    return true;
                }
                break;
            }
        }
        return false;
    }
Run Code Online (Sandbox Code Playgroud)

isReadyForPull() 功能只检查这个

    private boolean isReadyForPull(){
        return mScrollView.getScrollY()==0;
    }
Run Code Online (Sandbox Code Playgroud)

我的代码效果很好.

如果我向下移动我的孩子滚动视图,onInterceptTouchEvent首先得到MotionEvent.ACTION_DOWN和初始化值,并获得顺序MotionEvent.ACTION_MOVE所以设置mIsBeingDragged标志真实,并返回.所以,我可以处理我的事件ParentViewonTouchEvent.

否则,如果我动起来的孩子滚动视图,然后onInterceptTouchEvent返回false和我的孩子滚动视图获取MotionEvent和向下滚动.

这是预期的工作.好.

但是,当我触摸我的孩子线性布局时,它不起作用!

如果我触摸并拖动我的孩子的LinearLayout,我CustomView的onInterceptTouchEvent获得MotionEvent.ACTION_DOWN,但不能得到第二MotionEvent.ACTION_MOVE.

为什么这不仅适用于儿童线性布局?

注意:我测试了几次,并且知道(默认)可触摸视图或视图组(如按钮,滚动视图等)可以使用我的代码,而(默认)不可触摸的视图或小部件(如imageview,framelayout)不适用于我的码.

Aby*_*yss 6

解决方案与答案有关,因为它是标准MotionEvent处理的结果.

在我的代码中,当我触摸孩子时LinearLayout,父母CustomViewGroup不会拦截MotionEvent它,因为它返回false,但我的孩子LinearLayout不消耗MotionEvent任何一个,所以MotionEvent它返回到父亲onTouchEvent,而不是onInterceptTouchEvent.

另一方面,当我触摸我的孩子时ScrollView,它会消耗MotionEvent是否启用滚动.

==>我认为因为Android不会再生成一个MotionEvent,直到原来的一个被消费或完成,所以父母CustomViewGroup没有得到ACTION_MOVE MotionEvent通过onInterceptTouchEvent,onTouchEvent当一个孩子没有消费时,安装它是通过管道传输的MotionEvent.

我发现了两个解决方案

解决方案一

强行让我LinearLayout消耗掉MotionEvent.此解决方案仅在儿童LinearLayout无法触摸时可用View,ViewGroup或者Widget.像这样:

LinearLayout mLinearLayout = (LinearLayout)findViewById(R.id.child_linear);
mLinearLayout.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return true;
    }
});
Run Code Online (Sandbox Code Playgroud)

解决方案二

过程中,MotionEvent从一个孩子在我回来CustomViewGrouponTouchEvent.像这样:(如果情况允许,只需添加其他内容onTouchEvent).

case MotionEvent.ACTION_MOVE: {
    if (mIsBeingDragged) {
        mLastMotionY = event.getY();
        mLastMotionX = event.getX();
        pullEvent();
        return true;
    }
    else if (isReadyForPull()) {
        final float y = event.getY(), x = event.getX();
        final float diff, oppositeDiff, absDiff;
        diff = y - mLastMotionY;
        oppositeDiff = x - mLastMotionX;
        absDiff = Math.abs(diff);
        ViewConfiguration config = ViewConfiguration.get(getContext());

        if (absDiff > config.getScaledTouchSlop() &&  absDiff > 
        Math.abs(oppositeDiff) && diff >= 1f) {
             mLastMotionY = y;
             mLastMotionX = x;
             mIsBeingDragged = true;
        }
     }
     break;
 }
Run Code Online (Sandbox Code Playgroud)

虽然解决方案1是某些情况下的快速解决方案,但解决方案2是最灵活和最可靠的.