AS 事件分发(一)Activity的事件分发

Android事件分发源码解析
本文围绕Android事件分发展开,介绍了事件分发的开始,如重写dispatchTouchEvent方法,分析了事件传递层级和View添加到DecorView的流程。还深入查看了相关方法的返回值,如dispatchTouchEvent返回true时事件被消费,以及getWindow().superDispatchTouchEvent等方法的实现。此外,给出了onTouchEvent的流程图并进行讲解。

1.源码的查看

1.开始分发:重写dispatchTouchEvent

1. 先了解事件分发

在这里插入图片描述
事件:一般手指触碰屏幕:至少产生两个事件(按下DOWN,起来UP)
在这里插入图片描述
分发:
在这里插入图片描述

2.事件传递层级

在这里插入图片描述

3.View添加到DecorView流程

在这里插入图片描述

重写分发方法,这里是分发的开始(派遣):dispatchTouchEvnet

/**
     * 这个是事件开始,肯定会执行的,至少两次,点击起来两次,移动的话多次
     * @param ev
     * @return true表示事件消费了,即点击按钮没反应,因为没事件了,false表示事件没有消费,即点击按钮可以执行
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {//派遣点击事件

        Log.d(TAG, "dispatchTouchEvent: "+i++);
        return super.dispatchTouchEvent(ev);

    }

界面中有一个按钮,监听setOnTouchListener

findViewById(R.id.bt).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        Log.d(TAG, "onTouch: down");
                        break;
                    case MotionEvent.ACTION_MOVE:
                        Log.d(TAG, "onTouch: move");
                        break;
                    case MotionEvent.ACTION_UP:
                        Log.d(TAG, "onTouch: up");
                        break;
                    case MotionEvent.ACTION_CANCEL:
                        Toast.makeText(MainActivity.this, "cancel", Toast.LENGTH_SHORT).show();
                        break;
                }
                return false;
            }
        });

当点击按钮的时候(这里有停顿一会),会执行
在这里插入图片描述
在这里插入图片描述
dispatchTouchEvent返回的是一个Boolean值,当返回为true的时候,事件表示被消费了:意味没有事件了,所以点击按钮的时候没有反应(这里将其返回值设置为true)
在这里插入图片描述
执行结果:
在这里插入图片描述
(其实手指是执行了:DOWN,MOVE,UP),

2.查看返回值:点进去

在这里插入图片描述
在这里插入图片描述
由于我们点击屏幕的时候,会执行一次DOWN,所以onUserInteraction会被执行,它里面是一个空方法
在这里插入图片描述

3.查看getWindow().superDispatchTouchEvent(ev)

在这里插入图片描述
点进去:它是一个公共的抽象方法,返回的是一个boolean值
在这里插入图片描述
查看:它只有一个唯一的实现类PhoneWindow,所以我们找到PhoneWindow类在这里插入图片描述
双击shift,输入phoneWindow,找到对应的类
在这里插入图片描述
在这里插入图片描述

4.查看mDecor.superDispatchTouchEvent

mDicor是DecorView,而这个DecorView是Window持有的,点进去
在这里插入图片描述
再点进去,最终由ViewGroup里的DispatchTouchEvent实现,它返回为true,就结束了
在这里插入图片描述
在这里插入图片描述
当返回为false的时候,返回onTouchEvent(ev)的boolean值

5.onTouchEvent源码:

在这里插入图片描述
先查看mWindow.shouldCloseOnTouch
mWindow就是Window,找到里面的这个方法
在这里插入图片描述
在这里插入图片描述
满足下面三个就返回true(个人感觉这三个肯定有的,希望大神help me):
在这里插入图片描述

1.流程图

在这里插入图片描述
里面红色部分onTouchEvent的流程图
onTouchEvent里面的逻辑

2.讲解:

1.dispatchOnTouchEvent的点击:

点击MainActivity时会触发dispatchOnTouchEvent两次(是DOWN与UP)。然后点击,移动,在松开:就会触发多次dispatchOnTouchEvent(应该是DOWN,……MOVE……MOVE……UP)

2.dispatchOnTouchEvent的返回值

它返回一个boolean值。当返回为true的时候,点击Activity上的Button,无效不响应
在这里插入图片描述

因为事件被消费了(手指点击下去的时候会触发触摸事件,一般为DOWN、UP或DOWN、MOVE、UP):

<think> 我们正在讨论如何在方法中调用事件方法。根据用户提供的引用和之前的问题,我们需要整理出几种常见的实现方式。 引用[1]提到了事件冒泡、事件捕获和事件代理等概念,这些是DOM事件处理的机制,但与“在方法中调用事件方法”没有直接关系。 引用[2]描述了个Fragment(片段)调用Activity(活动)中方法的场景,这发生在Android开发中。用户希望从Fragment调用Activity的方法,并传递数据,同时避免使用静态方法。 引用[3]则是在Vue.js框架中,子组件调用父组件方法的方式,通过$emit触发父组件的事件。 综合来看,用户的问题“在方法中调用事件方法”可能是指在不同组件或上下文中调用事件处理函数。这里的事件方法可能是指绑定在事件上的处理函数,但更可能是指在个方法内部去触发另事件处理函数(即调用事件方法)。 我们可以分几种情况讨论: 1. **在同个上下文中直接调用事件方法**:如果事件方法是个普通函数,我们可以在其他方法中直接调用它。 2. **跨组件调用**:例如在Vue中,子组件调用父组件的方法(通过$emit触发事件);在Android中,Fragment调用Activity的方法(通过接口回调或获取Activity实例)。 3. **触发DOM事件**:如果我们想要以编程方式触发个DOM事件(比如点击事件),可以使用`element.click()`或者`dispatchEvent`方法。 由于用户的问题比较宽泛,我将列举几种常见场景的实现方式: 、在同个组件/对象中调用事件方法 我们可以将事件处理函数定义为方法,然后在其他方法中直接调用。 二、在Vue.js中子组件调用父组件的方法 通过`$emit`触发个自定义事件,父组件监听这个事件并调用对应的方法。 三、在Android中Fragment调用Activity的方法 通常做法是在Fragment中定义个接口,Activity实现这个接口,然后在Fragment中通过接口回调来调用Activity的方法。 四、在原生JavaScript中触发事件 可以使用`element.dispatchEvent(new Event('click'))`来触发事件,这样绑定的点击事件处理函数就会被执行。 五、在React中,子组件调用父组件的方法 父组件通过props将个方法传递给子组件,子组件在需要的时候调用这个方法。 下面我们分别详细说明: ### 、同个上下文中直接调用 例如,我们有个点击事件处理函数`handleClick`,我们可以在另个方法`someMethod`中直接调用它。 ```javascript function handleClick() { console.log('按钮被点击'); } // 在另个方法中调用 function someMethod() { // 做些操作... handleClick(); // 直接调用 } ``` ### 二、Vue.js中子组件调用父组件方法 子组件通过`$emit`触发事件,父组件监听该事件并执行相应的方法。 子组件: ```vue <template> <button @click="callFather">调用父组件方法</button> </template> <script> export default { methods: { callFather() { // 触发名为'father-event'的事件,并传递数据 this.$emit('father-event', 'data from child'); } } } </script> ``` 父组件: ```vue <template> <child-component @father-event="handleFatherEvent"></child-component> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, methods: { handleFatherEvent(data) { console.log('父组件接收到数据:', data); // 这里可以调用父组件的方法 } } } </script> ``` ### 三、Android中Fragment调用Activity的方法 步骤: 1. 在Fragment中定义个接口。 2. 让Activity实现这个接口。 3. 在Fragment的`onAttach`方法中,将Activity转换为接口实例。 4. 在需要的地方,通过接口实例调用Activity中的方法。 示例: ```java // Fragment中 public class MyFragment extends Fragment { // 定义接口 public interface OnFragmentInteractionListener { void onFragmentAction(String data); } private OnFragmentInteractionListener mListener; @Override public void onAttach(Context context) { super.onAttach(context); try { mListener = (OnFragmentInteractionListener) context; } catch (ClassCastException e) { throw new ClassCastException(context.toString() + " must implement OnFragmentInteractionListener"); } } // 在某个方法中调用 private void someMethodInFragment() { if (mListener != null) { mListener.onFragmentAction("Data from fragment"); } } } ``` 在Activity中: ```java public class MainActivity extends AppCompatActivity implements MyFragment.OnFragmentInteractionListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 添加Fragment等操作 } @Override public void onFragmentAction(String data) { // 处理来自Fragment的调用 Log.d("MainActivity", "Received data: " + data); } } ``` ### 四、原生JavaScript触发DOM事件 我们可以通过创建事件分发来触发个元素上绑定的事件处理函数。 ```javascript // 获取元素 const button = document.getElementById('myButton'); // 添加事件监听 button.addEventListener('click', function() { console.log('按钮被点击了!'); }); // 在某个方法中触发这个点击事件 function triggerClick() { // 创建事件 const event = new Event('click'); // 触发事件 button.dispatchEvent(event); } // 调用triggerClick就会触发按钮的点击事件处理函数 ``` ### 五、React中子组件调用父组件的方法 父组件将个方法作为prop传递给子组件,子组件调用该方法。 父组件: ```jsx function Parent() { const handleChildCall = (data) => { console.log('子组件调用了父组件的方法,数据:', data); }; return <Child onCallParent={handleChildCall} />; } ``` 子组件: ```jsx function Child(props) { const handleClick = () => { // 调用父组件传递过来的方法,并传递数据 props.onCallParent('Data from child'); }; return <button onClick={handleClick}>调用父组件方法</button>; } ``` 以上是几种常见场景的实现方式。具体使用哪种方式取决于你的开发环境和场景。 如果用户有更具体的环境(如Vue、React、Android、原生JavaScript等),可以进步细化问题。 根据上述内容,生成相关问题: </think> ### 在方法中调用事件方法的实现方式 根据您提供的引用内容,以下是几种常见的在方法中调用事件方法的技术方案,涵盖原生 JavaScript、Vue 和 Android 场景: --- #### 、JavaScript 中的实现方式 1. **直接调用事件处理函数** 将事件处理函数定义为普通方法,在需要时直接调用: ```javascript // 定义事件处理方法 function handleClick(event) { console.log('事件触发', event.target); } // 在普通方法中调用 function triggerEvent() { const mockEvent = { target: document.createElement('button') }; handleClick(mockEvent); // 手动调用事件方法 } ``` 2. **通过 DOM 元素触发事件** 使用 `dispatchEvent` 创建并派发自定义事件: ```javascript const button = document.getElementById('myButton'); // 添加事件监听 button.addEventListener('click', handleClick); // 在方法中触发事件 function triggerEvent() { const event = new Event('click'); // 创建事件对象 button.dispatchEvent(event); // 触发事件 } ``` --- #### 二、Vue 中的实现方式 (引用[3]) 1. **通过 `$emit` 触发父组件事件** 子组件使用 `$emit` 调用父组件的事件方法: ```vue <!-- 子组件 --> <script> export default { methods: { sendToParent() { this.$emit('parent-event', '子组件数据'); // 触发父组件事件 } } } </script> <!-- 父组件 --> <template> <child-component @parent-event="handleEvent"/> <!-- 监听事件 --> </template> <script> methods: { handleEvent(data) { console.log('收到数据:', data); // 执行事件逻辑 } } </script> ``` 2. **直接调用组件方法** 通过 `ref` 获取组件实例后直接调用其方法: ```vue <!-- 父组件 --> <child-component ref="childRef"/> <script> methods: { callChildMethod() { this.$refs.childRef.childMethod(); // 直接调用子组件方法 } } </script> ``` --- #### 三、Android 中的实现方式 (引用[2]) 1. **接口回调(推荐)** Fragment 通过接口调用 Activity 的方法: ```kotlin // 1. 在Fragment中定义接口 interface EventCallback { fun onEvent(data: String) } // 2. Activity实现接口 class MainActivity : AppCompatActivity(), EventCallback { override fun onEvent(data: String) { // 处理事件 } } // 3. Fragment中调用 class MyFragment : Fragment() { private lateinit var callback: EventCallback override fun onAttach(context: Context) { super.onAttach(context) callback = context as EventCallback } fun triggerEvent() { callback.onEvent("Fragment数据") // 调用Activity方法 } } ``` 2. **通过 Activity 实例调用** 直接获取 Activity 实例后调用公共方法: ```kotlin (requireActivity() as MainActivity).handleEvent("数据") ``` --- #### 四、阻止事件传递的注意事项 (引用[1]) 若需避免事件冒泡影响: ```javascript function handleClick(event) { event.stopPropagation(); // 阻止事件冒泡 // 事件处理逻辑 } ``` --- ### 实现方案对比 | **场景** | **技术方案** | **适用场景** | |------------------|---------------------------|--------------------------------| | JavaScript | `dispatchEvent` + 事件监听 | 原生 Web 开发 | | Vue 组件通信 | `$emit` / `ref` | 父子组件方法调用 | | Android 跨组件 | 接口回调 | Fragment 与 Activity 通信 | | 通用 | 直接方法调用 | 同组件/同对象内部调用 | > 提示:优先使用基于接口/事件总线的解耦方案(如 `$emit` 或回调接口),避免直接依赖具体实现[^1][^2][^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值