1.View的事件分发机制

一个button,简单一点就是onTouch,还有onclick事件,我们一个一个来分析

首先响应的是dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}

其实,在android源码的命名还是很有规律的,dispatchXXX,也就是分发机制,往往就是第一个需要响应的地方。

我们来分析下:touchlistener不为空,也就是view的使用者设置了回调。

第二个条件就是View必须是enable的。第三:onTouch返回false,就说明onTouch不消费该事件,由OnTouchEvent响应。

如果返回True,那么就会直接return。

所以onClick事件一定会被调到。

public boolean onTouchEvent(MotionEvent event) {
final int viewFlags = mViewFlags;
if ((viewFlags & ENABLED_MASK) == DISABLED) {
// A disabled view that is clickable still consumes the touch
// events, it just doesn't respond to them.
return (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
}
if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
// take focus if we don't have it already and we should in
// touch mode.
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
}
if (!mHasPerformedLongPress) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
// Only perform take click actions if we were in the pressed state
if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClick();
}
}
}
if (mUnsetPressedState == null) {
mUnsetPressedState = new UnsetPressedState();
}
if (prepressed) {
mPrivateFlags |= PRESSED;
refreshDrawableState();
postDelayed(mUnsetPressedState,
ViewConfiguration.getPressedStateDuration());
} else if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
mUnsetPressedState.run();
}
removeTapCallback();
}
break;
case MotionEvent.ACTION_DOWN:
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
mPrivateFlags |= PREPRESSED;
mHasPerformedLongPress = false;
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
break;
case MotionEvent.ACTION_CANCEL:
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
removeTapCallback();
break;
case MotionEvent.ACTION_MOVE:
final int x = (int) event.getX();
final int y = (int) event.getY();
// Be lenient about moving outside of buttons
int slop = mTouchSlop;
if ((x < 0 - slop) || (x >= getWidth() + slop) ||
(y < 0 - slop) || (y >= getHeight() + slop)) {
// Outside button
removeTapCallback();
if ((mPrivateFlags & PRESSED) != 0) {
// Remove any future long press/tap checks
removeLongPressCallback();
// Need to switch from pressed to not pressed
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
}
}
break;
}
return true;
}
return false;
}

onTouchEvent

最终会走到performClick这个方法。

    public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
} sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}

可以看到,如果setOnClickListener, onClick 就会走到。

2.ViewGroup的事件分发机制

<com.joyfulmath.frameworksample.viewdemo.MyLayout
android:id="@+id/my_layout"
android:background="#99000044"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/button_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button"/>
<Button
android:id="@+id/imageId"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_lock_power_off"/>
</com.joyfulmath.frameworksample.viewdemo.MyLayout>

一个layout里面有2个button,

package com.joyfulmath.frameworksample.viewdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView; import com.joyfulmath.frameworksample.R; /**
* Created by Administrator on 2016/8/27 0027.
*/
public class TestViewAction extends Activity implements View.OnClickListener,View.OnTouchListener
{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
Button button = (Button) findViewById(R.id.button_id);
button.setOnClickListener(this);
button.setOnTouchListener(this);
Button imageView = (Button) findViewById(R.id.imageId);
imageView.setOnClickListener(this);
imageView.setOnTouchListener(this);
MyLayout myLayout = (MyLayout) findViewById(R.id.my_layout);
myLayout.setOnTouchListener(this);
myLayout.setOnClickListener(this);
} @Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.button_id:
TraceLog.i("button_id");
break;
case R.id.imageId:
TraceLog.i("imageId");
break;
case R.id.my_layout:
TraceLog.i("my_layout");
break;
} } @Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId())
{
case R.id.button_id:
TraceLog.i("button_id");
break;
case R.id.imageId:
TraceLog.i("imageId");
break;
case R.id.my_layout:
TraceLog.i("my_layout");
break;
}
return false;
}
}

TestViewAction

分别点击button1 & button2 & 灰色部分

等到log如下:

08-27 10:19:26.799 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: button_id [at (TestViewAction.java:55)]
08-27 10:19:26.880 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: button_id [at (TestViewAction.java:55)]
08-27 10:19:26.896 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: button_id [at (TestViewAction.java:55)]
08-27 10:19:26.913 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: button_id [at (TestViewAction.java:55)]
08-27 10:19:26.926 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: button_id [at (TestViewAction.java:55)]
08-27 10:19:26.926 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onClick: button_id [at (TestViewAction.java:38)]
08-27 10:19:27.434 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: imageId [at (TestViewAction.java:58)]
08-27 10:19:27.535 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: imageId [at (TestViewAction.java:58)]
08-27 10:19:27.543 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: imageId [at (TestViewAction.java:58)]
08-27 10:19:27.544 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onClick: imageId [at (TestViewAction.java:41)]
08-27 10:19:28.111 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: my_layout [at (TestViewAction.java:61)]
08-27 10:19:28.156 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: my_layout [at (TestViewAction.java:61)]
08-27 10:19:28.173 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: my_layout [at (TestViewAction.java:61)]
08-27 10:19:28.190 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: my_layout [at (TestViewAction.java:61)]
08-27 10:19:28.237 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onTouch: my_layout [at (TestViewAction.java:61)]
08-27 10:19:28.237 2120-2120/com.joyfulmath.frameworksample I/TestViewAction: onClick: my_layout [at (TestViewAction.java:44)]

也就是点击button1以后,不会传递都layout

But,如果layout里面有一个函数

public boolean onInterceptTouchEvent(MotionEvent ev)

这个函数就是截断对button的分发处理,默认是return false。

至此,我们有了一个大概的流程。

Activtiy->ViewGroup->View

如果仔细分析就会发现,在Activity里面有一个getDocView。所以Activity里面有个RootView的概念。

言归正传,ViewGroup本质上也是一个View,所以,可以把模型简单的定性为Activtiy->ViewGroup->View 三层。

首先Activity里面有2个函数,我们分析看看:

    @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
TraceLog.i();
return super.dispatchTouchEvent(ev);
} @Override
public boolean onTouchEvent(MotionEvent event) {
TraceLog.i();
return super.onTouchEvent(event);
}

所以大体流程如下:

1.@Activty.diapatchTouchEvent ->@Layout.dispatchTouchEvent->@layout.onInterceptTouchEvent return true/false

2.return true->@layout.onTouchEvent 后面部分同view

3.return false->@view.dispatchTouchEvent View的分发见上一片流程。

上面是2016年的文章分析,最新的java层的分析可以参考如下文章

demanmath.com

关注公共号:

参考:

《深入理解android设计思想》   林学森

android 事件分发机制的更多相关文章

  1. Android事件分发机制(下)

    这篇文章继续讨论Android事件分发机制,首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View和子 ...

  2. Android事件分发机制(上)

    Android事件分发机制这个问题不止一个人问过我,每次我的回答都显得模拟两可,是因为自己一直对这个没有很好的理解,趁现在比较闲对这个做一点总结 举个例子: 你当前有一个非常简单的项目,只有一个Act ...

  3. android事件分发机制

    android事件分发机制,给控件设置ontouch监听事件,当ontouch返回true时,他就不会走onTouchEvent方法,要想走onTouchEvent方法只需要返回ontouch返回fa ...

  4. [转]Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

    Android事件分发机制 该篇文章出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分 ...

  5. Android事件分发机制源码分析

    Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ...

  6. 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...

  7. 【自己定义控件】android事件分发机制

    自己定义Viewgrou中我们或许会常常碰到这种情况,2个子控件的事件冲突导致滑动没实用了.滑动反应非常慢,点击没用了,要划非常多次才移动一点点等等.或许我们第一反应就是百度,google去搜索下答案 ...

  8. Android 事件分发机制具体解释

    很多其它内容请參照我的个人网站: http://stackvoid.com/ 网上非常多关于Android事件分发机制的解释,大多数描写叙述的都不够清晰,没有吧来龙去脉搞清晰,本文将带你从Touch事 ...

  9. 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象

    前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...

  10. 【朝花夕拾】Android自定义View篇之(五)Android事件分发机制(上)Touch三个重要方法的处理逻辑

    前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/10998855.html]谢谢! 在自定义View中,经常需要处理Android事件分发的问题, ...

随机推荐

  1. [Keras] mnist with cnn

    典型的卷积神经网络. Keras傻瓜式读取数据:自动下载,自动解压,自动加载. # X_train: array([[[[ 0., 0., 0., ..., 0., 0., 0.], [ 0., 0. ...

  2. CSS字体记录

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAaYAAACnCAIAAADVOG9FAAAgAElEQVR4nOy9eXwcxZk/vL/9ve8eb7 ...

  3. Cesium应用篇:3控件(3)SelectionIndicator& InfoBox

    假设这样一个场景,用户在Cesium球上加载了一个GeoJson文件(DataSource),里面是全美国所有州的Geometry信息(Entity),叠加到球面后,你自然会有一种冲动,点击某一个州, ...

  4. Google数据中心B4网络具体实现

    ① 背景介绍 Google的网络有两种,一种是数据中心内部网络,另外一种是WAN网,其中WAN网又分为两种:一是数据中心之间的互联网络,属于内部网络(G-Scale Network),另外一种是面向I ...

  5. JAVA常见面试题之Forward和Redirect的区别

    用户向服务器发送了一次HTTP请求,该请求可能会经过多个信息资源处理以后才返回给用户,各个信息资源使用请求转发机制相互转发请求,但是用户是感觉不到请求转发的.根据转发方式的不同,可以区分为直接请求转发 ...

  6. 移动端click事件延迟300ms问题

    因为历史原因,移动端点击事件会有300ms延迟,来判断用户是连续双击缩放还是点击跳转.即如果300ms内连续点击两次,则会理解为对页面进行缩放操作(当然前提是移动端页面设置为可缩放的):在一次点击之后 ...

  7. 【原创】kafka server源代码分析(二)

    十四.AbstractFetcherManager.scala 该scala定义了两个case类和一个抽象类.两个case类很简单: 1. BrokerAndFectherId:封装了一个broker ...

  8. listview控件及其与数据库的连接

    一.显示数据 1.视图 -----小三角--视图-Details,该选项最常用,选中之后会以表格样式呈现. 2.设置列头 ----右键--编辑列 --添加 先编辑列,再编辑项 编辑列右边的属性:Tex ...

  9. Oracle 英文 非标准格式 日期 格式化

    最近在处理一张表的时候,需要按照日期排序,日期字段中日期的格式有两种. 格式一:07-Aug-2015 格式二:10/28/16 日期转化及格式化sql语句: select to_date('07-A ...

  10. poj1113--凸包(Andrew)

    题目大意: 给出平面上若干个点的坐标,你的任务是建一个环形围墙,把所有的点围在里面,且距所有点的距离不小于l.求围墙的最小长度. 思路: 很容易得出答案就是凸包周长+以l为半径的圆的周长. 这里讲一下 ...