Androidイベント配信メカニズムの概要(1)

8146 ワード

本文は網易雲コミュニティから来た
著者:孫有軍
イベントメカニズムはAndroidの複雑で重要な知識点です.例えば、イベントをカスタマイズしたいとか、コンポーネントに他のレイアウトをネストしたいとか、このようなイベントの衝突が発生することが多いです.お父さん!イベントは主にonTouch、onClick、onTouchEvent、dispatchTouchEvent、onInterceptTouchEventなどの一連のイベントをカバーし、イベント間では相互に相互に結合されており、戻り値があるイベントもあり、true、false、どのような場合にtrue、どのような場合にfalseに戻るのか、なぜ戻り値があるのか、考えてみると全体的によくありません.
しかし(万悪のしかし)、この知識点はやはり掌握しなければならなくて、知識の深さと広さはあなたの歩く遠さを決定して、これに鑑みて私達はこの知識点をつついて突き刺します.
準備作業
工欲善其事必先利其器ということわざがありますが、彼の実行プロセスを見るために、まずサンプルを書いて、いくつかのログを打って実行プロセスを見てみましょう.
まず外層レイアウトのLayoutをカスタマイズし、カスタムLayoutはLinearLayoutを継承し、対応する関数を複写し、呼び出す前にログを入力します.次のようになります.
public class Layout extends LinearLayout {
    public Layout(Context context) {
        super(context);
        init();
    }

    public Layout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public Layout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        //requestDisallowInterceptTouchEvent(false);
    }


    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("Event", "Layout onInterceptTouchEvent " + MotionEvent.actionToString(ev.getAction()));
        return super.onInterceptTouchEvent(ev);
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("Event", "Layout onTouchEvent " + MotionEvent.actionToString(event.getAction()));
        return super.onTouchEvent(event);
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("Event", "Layout dispatchTouchEvent " + MotionEvent.actionToString(event.getAction()));
        return super.dispatchTouchEvent(event);
    }

}

ログを出力するためにログをカスタマイズしました.コードは次のとおりです.
public class LogTextView extends TextView {

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

    public LogTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LogTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("Event", "TextView  onTouchEvent " + MotionEvent.actionToString(event.getAction()));
        return super.onTouchEvent(event);
    }

    @Override
    public void setOnTouchListener(OnTouchListener l) {
        super.setOnTouchListener(l);
    }

    @Override
    public void setOnClickListener(OnClickListener l) {
        super.setOnClickListener(l);
    }
}

次はレイアウトファイルです.



    

    

レイアウトには2つのview、1つのTextView、1つのImageViewがネストされています.最後はメインインタフェースです.
public class MainActivity extends AppCompatActivity {

    private LogTextView tv;
    private ImageView imageView;

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

    private void findViews() {
        tv = (LogTextView) findViewById(R.id.textView);
        imageView = (ImageView) findViewById(R.id.image);
    }

    private void setViewListener() {
        tv.setOnTouchListener(new View.OnTouchListener() {
            @TargetApi(Build.VERSION_CODES.KITKAT)
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("Event", "TextView  onTouch " + MotionEvent.actionToString(event.getAction()));
                return true;
            }
        });
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("Event", "TextView  onClick ");
            }
        });
        imageView.setOnTouchListener(new View.OnTouchListener() {
            @TargetApi(Build.VERSION_CODES.KITKAT)
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("Event", "ImageView onTouch " + MotionEvent.actionToString(event.getAction()));
                return false;
            }
        });
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("Event", "ImageView onClick ");
            }
        });
    }
}

実行結果
       round 1
TextViewのonTouchはfalseに戻り、TextViewをクリックします.ログは次のとおりです.
05-05 14:04:44.091 27644-27644/com.sunny.event E/Event: Layout    dispatchTouchEvent ACTION_DOWN
05-05 14:04:44.091 27644-27644/com.sunny.event E/Event: Layout    onInterceptTouchEvent ACTION_DOWN
05-05 14:04:44.091 27644-27644/com.sunny.event E/Event: TextView  onTouch ACTION_DOWN
05-05 14:04:44.091 27644-27644/com.sunny.event E/Event: TextView  onTouchEvent ACTION_DOWN
05-05 14:04:44.158 27644-27644/com.sunny.event E/Event: Layout    dispatchTouchEvent ACTION_MOVE
05-05 14:04:44.158 27644-27644/com.sunny.event E/Event: Layout    onInterceptTouchEvent ACTION_MOVE
05-05 14:04:44.158 27644-27644/com.sunny.event E/Event: TextView  onTouch ACTION_MOVE
05-05 14:04:44.158 27644-27644/com.sunny.event E/Event: TextView  onTouchEvent ACTION_MOVE
05-05 14:04:44.158 27644-27644/com.sunny.event E/Event: Layout    dispatchTouchEvent ACTION_UP
05-05 14:04:44.159 27644-27644/com.sunny.event E/Event: Layout    onInterceptTouchEvent ACTION_UP
05-05 14:04:44.159 27644-27644/com.sunny.event E/Event: TextView  onTouch ACTION_UP
05-05 14:04:44.159 27644-27644/com.sunny.event E/Event: TextView  onTouchEvent ACTION_UP
05-05 14:04:44.159 27644-27644/com.sunny.event E/Event: TextView  onClick

ログによると、まずACTIONがあります.DOWNイベント、実行順はLayoutのdispatchTouchEvent→onInterceptTouchEvent→(TextView)onTouch要→onTouchEvent、その後の私パーキンソン発生、ACTION_MOVEイベントは、渡される順番がDownと一致し、最後のイベントがUPイベントであり、通常クリックでスライドしないとMOVEイベントは発生しないので、この3つのイベントで最後にTextViewのonClickイベントが呼び出された.
まとめ:
  • イベントの伝達順序は、まず外層容器であり、その後、具体的なViewである.
  • onTouchイベントはonTouchEventイベントより先に、onTouchEventはonClickイベント
  • より先に
       round 2
    TextViewのonTouchイベントをtrueに返します.再実行します.実行順序は次のとおりです.
    05-05 14:10:20.556 27644-27644/com.sunny.event E/Event: Layout    dispatchTouchEvent ACTION_DOWN
    05-05 14:10:20.556 27644-27644/com.sunny.event E/Event: Layout    onInterceptTouchEvent ACTION_DOWN
    05-05 14:10:20.556 27644-27644/com.sunny.event E/Event: TextView  onTouch ACTION_DOWN
    05-05 14:10:20.616 27644-27644/com.sunny.event E/Event: Layout    dispatchTouchEvent ACTION_MOVE
    05-05 14:10:20.616 27644-27644/com.sunny.event E/Event: Layout    onInterceptTouchEvent ACTION_MOVE
    05-05 14:10:20.616 27644-27644/com.sunny.event E/Event: TextView  onTouch ACTION_MOVE
    05-05 14:10:20.622 27644-27644/com.sunny.event E/Event: Layout    dispatchTouchEvent ACTION_UP
    05-05 14:10:20.622 27644-27644/com.sunny.event E/Event: Layout    onInterceptTouchEvent ACTION_UP
    05-05 14:10:20.622 27644-27644/com.sunny.event E/Event: TextView  onTouch ACTION_UP

    ログから、onTouchがtrueに戻ると、実行順序は次のようになります.
    まずはACTION_DOWNイベント(Layout)dispatchTouchEvent→onInterceptTouchEvent→(TextView)onTouch,ACTION_MOVEとACTION_UP実行手順同ACTION_DOWNは、TextViewのonTouchEventイベントがなくなり、onClickイベントもなくなったことがわかります.
    小結
    1、onTouchイベントの戻り値をtrueとするとonTouchEventイベントがブロックされます
    2、onTouchEventはonClickと関連がある
    上の2回の実行で毎回onInterceptTouchEventイベントが呼び出されていますが、これはいったい何ですか?彼の戻り値を見に行きましょうか?
    網易雲無料体験館、0コスト体験20+クラウド製品! 
    更なる網易研究開発、製品、運営経験の分かち合いは網易クラウドコミュニティに訪問してください
    関連記事:【推奨】SpringBoot入門(二)——スタート依存【推奨】WiresharkによるHTTPSデータの解読【推奨】21分でコンパイラを書く