5

Android の ScrollViews での MotionEvents の動作を理解しようとしてきましたが、理解できないことがあります。

例として、内部に 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;
        }

    }

}

画面のどこかをクリックすると、次のログが表示されます。

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

これは、タッチ イベントがスクロールビュー内の内部レイアウトに到達しなかったことを意味します。ただし、ScrollView を LinearLayout に変更すると (単に extends で変更するだけです)、イベントは内側のレイアウトに移動します。

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

ScrollView クラスのソース コードを調べたところ、それがオーバーライドする唯一のタッチ関連メソッドは、自分でオーバーライドしたものだけです。したがって、LinearLayout と ScrollView の動作の違いは何なのかわかりません。

4

2 に答える 2

10

上記の動作の理由はすでにわかっているかもしれませんが、そうでない場合に備えて、ここにその理由を示します。

概要

これらonInterceptTouchEvent()はトップダウン (親から子へ) と呼ばれ、子によって処理される前に 1 つのビューがモーション イベントをインターセプトできるようにします。

それらの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());

背景画像をタッチすると、イベントが子に到達することがわかります。背景画像の外側をタッチすると、イベントは によって消費されますScrollView

お役に立てれば。

よろしく。

于 2012-11-29T15:06:35.273 に答える
0

スクロール ビューにアニメーションを含むビューがあります。アニメーションの開始と停止は、モーション イベント (DOWN と UP) と同じです。私は同じ解決策を修正します:

public class RootActivity extends Activity implements OnTouchListener {

private View tochedView = null;

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

    ((View) findViewById(R.id.btnOther)).setOnTouchListener(this);

    ScrollView scroll = (ScrollView) findViewById(R.id.scrollView);
    scroll.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP && tochedView != null) {
                Log.i("Touche", "ScrollView ACTION_UP");
                Animation upAnim = AnimationUtils.loadAnimation(RootActivity.this, R.anim.btn_up_anim);
                tochedView.startAnimation(upAnim);
                tochedView = null;
                return true;
            }
            return false;
        }
    });
}


private void animateView(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        Log.i("Touche", "ACTION_DOWN");
        Animation downAnim = AnimationUtils.loadAnimation(this, R.anim.btn_down_anim);
        v.startAnimation(downAnim);
        tochedView = v;
    }
    if (event.getAction() == MotionEvent.ACTION_UP && tochedView != null) {
        Log.i("Touche", "ACTION_UP");
        Animation upAnim = AnimationUtils.loadAnimation(this, R.anim.btn_up_anim);
        v.startAnimation(upAnim);
        tochedView = null;
    }

}


@Override
public boolean onTouch(View v, MotionEvent event) {
        animateView(v, event);
}

}

于 2014-04-08T16:15:09.657 に答える