Android中ScrollView中的MotionEvent处理

Rot*_*tem 5 android touch scrollview motionevent

我一直试图弄清楚Android中ScrollViews中MotionEvents的行为,这是我无法弄清楚的.

作为一个例子,我创建了一个Activity,里面有一个ScrollView,ScrollView里面有一个LinearLayout.我实现了自己的类来控制与触摸相关的功能:

    public class MainActivity extends Activity {

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

        MyInnerLayout inner = new MyInnerLayout(getApplicationContext());
        MyLayout layout = new MyLayout(getApplicationContext());

        layout.addView(inner,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
        setContentView(layout);

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i("scrollview","activity dispatchTouchEvent "+ev.getAction());
        return super.dispatchTouchEvent(ev);
    };

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        Log.i("scrollview","activity on touch "+ev.getAction());
        return super.onTouchEvent(ev);
    }




    public class MyLayout extends ScrollView {

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

        @Override
        public boolean dispatchKeyEvent(KeyEvent ev) {
            Log.i("scrollview","layout dispatchKeyEvent "+ev.getAction());
            return super.dispatchKeyEvent(ev);
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.i("scrollview","layout onInterceptTouchEvent "+ev.getAction());
            return false;
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            Log.i("scrollview","layout on touch "+ev.getAction());
            return false;
        }

    }

    public class MyInnerLayout extends LinearLayout{

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

        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.i("scrollview","inner layout dispatchTouchEvent "+ev.getAction());
            return true;
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.i("scrollview","inner layout onInterceptTouchEvent "+ev.getAction());
            return true;
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            Log.i("scrollview","inner layout on touch "+ev.getAction());
            return true;
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

当我点击屏幕上的任何地方时,我得到这个日志:

10-14 18:11:48.631: I/scrollview(14906): activity dispatchTouchEvent 0
10-14 18:11:48.631: I/scrollview(14906): layout onInterceptTouchEvent 0
10-14 18:11:48.631: I/scrollview(14906): layout on touch 0
10-14 18:11:48.631: I/scrollview(14906): activity on touch 0
10-14 18:11:48.647: I/scrollview(14906): activity dispatchTouchEvent 1
10-14 18:11:48.647: I/scrollview(14906): activity on touch 1
Run Code Online (Sandbox Code Playgroud)

这意味着触摸事件没有让位于scrollview内部的内部布局.但是当我将ScrollView更改为LinearLayout(只是在扩展中更改它)时,事件将转到内部布局:

10-14 18:24:08.975: I/scrollview(15115): activity dispatchTouchEvent 0
10-14 18:24:08.975: I/scrollview(15115): layout onInterceptTouchEvent 0
10-14 18:24:08.975: I/scrollview(15115): inner layout dispatchTouchEvent 0
10-14 18:24:09.045: I/scrollview(15115): activity dispatchTouchEvent 1
10-14 18:24:09.045: I/scrollview(15115): layout onInterceptTouchEvent 1
10-14 18:24:09.045: I/scrollview(15115): inner layout dispatchTouchEvent 1
Run Code Online (Sandbox Code Playgroud)

我查看了ScrollView类的源代码,它覆盖的唯一与触摸相关的方法就是我自己压倒的方法.所以我不明白LinearLayout和ScrollView的行为之间有什么区别.

Lui*_*uis 10

也许你已经弄明白为什么上面的行为,但万一你不这样做,这就是原因.

概观

onInterceptTouchEvent()被称为自顶向下(从父到子),使得一个视图被儿童正在处理之前拦截运动事件.

onTouchEvent()被称为自底向上(从子到父),直到其中一个消费它和循环共完成.

一个ScrollView拦截MotionEvent,检查它是否应该将它们传递给孩子之前滚动视图.如果应该执行滚动,则会消耗该事件并且子视图不会看到任何内容.

在这种情况下LinearLayout,没有理由在此期间消耗该事件onInterceptTouchEvent(),并且始终将其传递给子视图.

您的代码中发生了什么

因为MyInnerLayout是空的ScrollView,总是消耗着MotionEvent.

例如,如果您设置内部布局背景,如下所示:

    MyInnerLayout inner = new MyInnerLayout(getApplicationContext());
    inner.setBackground(getResources().getDrawable(R.drawable.ic_launcher));
    MyLayout layout = new MyLayout(getApplicationContext());
Run Code Online (Sandbox Code Playgroud)

你会看到,如果你触摸背景图像,事件就会到达孩子身上.如果您在背景图像外触摸,则该事件将被消耗ScrollView.

希望这可以帮助.

问候.