美文网首页
Android 点击事件传递分析篇

Android 点击事件传递分析篇

作者: 非典型程序猿 | 来源:发表于2020-02-29 15:55 被阅读0次

前两天面试被问到了Android的事件分发机制,以前也学习过,今天再利用这篇文章用实际的操作来分析安卓的点击事件是如何分发的。

示例代码

首先码上代码,代码包括一个TouchEventActivity.java和一个布局文件activity_touch_event.xml
TouchEventActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class TouchEventActivity extends AppCompatActivity implements View.OnTouchListener {
    public static final String TAG = "TouchEventActivity";
    private RelativeLayout relativeLayout1 ;
    private RelativeLayout relativeLayout2 ;
    private TextView textView ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_touch_event);
        initView();

    }

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

        switch (v.getId()){
            case R.id.relative_1:
                Log.d(TAG,"relative_1 has touched");
                showEvent(event);
                Log.d(TAG,"relative_1---");
                return false;
            case R.id.relative_2:
                Log.d(TAG,"relative_2 has touched");
                showEvent(event);
                Log.d(TAG,"relative_2---");
                return true;
            case R.id.textView:
                Log.d(TAG,"textView has touched");
                showEvent(event);
                Log.d(TAG,"textView---");
                return false;
                default:
                    return false;
        }
    }
    public void initView(){
      relativeLayout1 = findViewById(R.id.relative_1);
      relativeLayout2 = findViewById(R.id.relative_2);
      textView = findViewById(R.id.textView);
      relativeLayout1.setOnTouchListener(this);
      relativeLayout2.setOnTouchListener(this);
      textView.setOnTouchListener(this);
    }
    public void showEvent(MotionEvent event){
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.d(TAG,"ACTION_DOWN");
                break;
            case MotionEvent.ACTION_UP:
                Log.d(TAG,"ACTION_UP");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.d(TAG,"ACTION_MOVE");
                break;
                default:
                    Log.d(TAG,"ACTION_UNKNOW");
                    break;
        }
    }
}

activity_touch_event.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".TouchEventActivity"
    android:id="@+id/relative_1">
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:background="#33f3f3"
        android:padding="50dp"
        android:id="@+id/relative_2">
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:padding="30dp"
            android:background="#cdcdcd"
            android:text="textView"/>
    </RelativeLayout>
</RelativeLayout>

运行截图如下


Screenshot_2020-02-29-15-32-55-57.png

我们在例子中用RelativeLayout relative_1中承载了一个RelativeLayout relative_2,接着在relative_2中放置了TextView textView。

首先我们总结一下所知道的安卓分发机制,安卓的事件分发机制是先由上至下分配到最里的一个组件,然后根据onTouchEvent的返回值确定是否要将该事件消费掉。所以接下来我们根据我们的例子我们来做一下实际的测试。

  • 首先我们把三个组件的TouchEvent的返回值都不被消费掉,都返回false。运行结果如下
02-29 15:38:03.762 32043-32043/com.txVideo.demo D/TouchEventActivity: textView has touched
02-29 15:38:03.763 32043-32043/com.txVideo.demo D/TouchEventActivity: ACTION_DOWN
02-29 15:38:03.764 32043-32043/com.txVideo.demo D/TouchEventActivity: textView---
02-29 15:38:03.764 32043-32043/com.txVideo.demo D/TouchEventActivity: relative_2 has touched
02-29 15:38:03.765 32043-32043/com.txVideo.demo D/TouchEventActivity: ACTION_DOWN
02-29 15:38:03.765 32043-32043/com.txVideo.demo D/TouchEventActivity: relative_2---
02-29 15:38:03.766 32043-32043/com.txVideo.demo D/TouchEventActivity: relative_1 has touched
02-29 15:38:03.766 32043-32043/com.txVideo.demo D/TouchEventActivity: ACTION_DOWN
02-29 15:38:03.768 32043-32043/com.txVideo.demo D/TouchEventActivity: relative_1---

根据结果可以看到,事件传递方向是 textView - relative_2 - relative_1,但是事件最终在relative_1被消费掉了吗?当然不是,先不着急,我们继续开始测试

  • 将事件在textView消费掉
02-29 15:40:58.251 602-602/com.txVideo.demo D/TouchEventActivity: textView has touched
02-29 15:40:58.251 602-602/com.txVideo.demo D/TouchEventActivity: ACTION_DOWN
02-29 15:40:58.251 602-602/com.txVideo.demo D/TouchEventActivity: textView---
02-29 15:40:58.307 602-602/com.txVideo.demo D/TouchEventActivity: textView has touched
02-29 15:40:58.307 602-602/com.txVideo.demo D/TouchEventActivity: ACTION_UP
02-29 15:40:58.307 602-602/com.txVideo.demo D/TouchEventActivity: textView---

很明显,onTouch()方法在textView中被完整消费掉了,且relative_2和relative_1都没有被分发到事件

  • 将事件在relative_2中消费掉
02-29 15:43:07.532 1340-1340/com.txVideo.demo D/TouchEventActivity: textView has touched
02-29 15:43:07.533 1340-1340/com.txVideo.demo D/TouchEventActivity: ACTION_DOWN
02-29 15:43:07.534 1340-1340/com.txVideo.demo D/TouchEventActivity: textView---
02-29 15:43:07.535 1340-1340/com.txVideo.demo D/TouchEventActivity: relative_2 has touched
02-29 15:43:07.536 1340-1340/com.txVideo.demo D/TouchEventActivity: ACTION_DOWN
02-29 15:43:07.537 1340-1340/com.txVideo.demo D/TouchEventActivity: relative_2---
02-29 15:43:07.590 1340-1340/com.txVideo.demo D/TouchEventActivity: relative_2 has touched
02-29 15:43:07.590 1340-1340/com.txVideo.demo D/TouchEventActivity: ACTION_UP
02-29 15:43:07.590 1340-1340/com.txVideo.demo D/TouchEventActivity: relative_2---

很明显,textView虽然有事件,但只有按下的事件,而在relative_2中完整的触发了onTouch()事件,relative_1则没有被分发到事件。

  • 事件在relative_1中被消费
02-29 15:45:56.590 1938-1938/com.txVideo.demo D/TouchEventActivity: textView has touched
02-29 15:45:56.591 1938-1938/com.txVideo.demo D/TouchEventActivity: ACTION_DOWN
02-29 15:45:56.591 1938-1938/com.txVideo.demo D/TouchEventActivity: textView---
02-29 15:45:56.594 1938-1938/com.txVideo.demo D/TouchEventActivity: relative_2 has touched
02-29 15:45:56.595 1938-1938/com.txVideo.demo D/TouchEventActivity: ACTION_DOWN
02-29 15:45:56.595 1938-1938/com.txVideo.demo D/TouchEventActivity: relative_2---
02-29 15:45:56.596 1938-1938/com.txVideo.demo D/TouchEventActivity: relative_1 has touched
02-29 15:45:56.597 1938-1938/com.txVideo.demo D/TouchEventActivity: ACTION_DOWN
02-29 15:45:56.599 1938-1938/com.txVideo.demo D/TouchEventActivity: relative_1---
02-29 15:45:56.671 1938-1938/com.txVideo.demo D/TouchEventActivity: relative_1 has touched
02-29 15:45:56.671 1938-1938/com.txVideo.demo D/TouchEventActivity: ACTION_UP
02-29 15:45:56.672 1938-1938/com.txVideo.demo D/TouchEventActivity: relative_1---

很明显,textView和relative_2都只有按下的事件,而relative_1则触发了完整的onTouch()事件,所以回到我们最初的情况,当这三者都没有消费事件时,其实这个onTouch()事件并未被完整触发。

总结

  • 当事件到达时,会优先分配到具体的子控件
  • 当子控件未消费事件时,则继续向它的父组件传递,但此时已经触发了一次按下的点击事件,若它的父组件仍然有更高一级的父组件,则依次类推
  • 当某个控件消费事件时,则触发完整的onTouch()事件,其子控件只触发按下的事件,其父组件不再被分配到此事件.
    今天的安卓事件分配就给大家总结到这里啦,觉得有帮助记得点个赞~

相关文章

网友评论

      本文标题:Android 点击事件传递分析篇

      本文链接:https://www.haomeiwen.com/subject/hpgphhtx.html