[16]——View 事件体系详解(1)

1、什么是 View

在我们的日常工作中,你可能已经接触过了很多 View ,View 是 Android 中所有控件的基类,例如 Buttton、TextView、LinearLayout,这些类的继承关系如下图的所示(使用 Ctrl + H 快捷键组合可以查看选中类的继承关系):


Buttton

TextView

LinearLayout

上图可以看出 LinearLayout 与 TextView 还有些不同,LinearLayout 的父类是 ViewGroup, ViewGroup 的父类也是 View。

查看 View 源代码可以看到官方对 View 有这样一段说明:

<p>
This class represents the basic building block for user interface components. A View
occupies a rectangular area on the screen and is responsible for drawing and
event handling. View is the base class for <em>widgets</em>, which are
used to create interactive UI components (buttons, text fields, etc.). The
{@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which
are invisible containers that hold other Views (or other ViewGroups) and define
their layout properties.
</p>

View 类是用户界面的基本组成块。一个 View 在屏幕上占据一个矩形区域,负责绘制视图与事件处理。View 是控件的基类,它是用于创建交互式UI组件(按钮、文本域等)。其子类 ViewGroup 类是所有布局(Layout)的基类,布局(Layout)是一个可持有其他 View(或其他 ViewGroup)并能定义它们布局属性的看不见的容器。

2、View 的点击事件

View 类中有一个回调方法为 onTouchEvent,该回调方法会在触摸屏幕事件发生时调用,在 View 类中可以通过实现该回调方法来处理 View 的一系列滑动事件的处理。

我们可以自定义一个 MyView 类继承自 View 类,重写 onTouchEvent 方法:

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d(TAG, "onTouch");
    return super.onTouchEvent(event);
}

修改布局文件,添加我们自定义的 View,需要注意的是,这里必须要写该类的完整包名:

<com.junerver.viewdemo.MyView
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:background="#ffddee"/>

运行后,点击该区域,Logcat 中输出如下:


logcat 输出

可以看出,每次我们点击该 View 所在区域时就会调用一次 onTouchEvent 回调方法。

2.1、MotionEvent

onTouchEvent 回调方法中我们可以发现,该方法接受了一个 MotionEvent 参数,该参数是手指接触屏幕后所产生的的一系列事件。
我们依旧选择查看源码介绍来简单了解该类:

Object used to report movement (mouse, pen, finger, trackball) events.
Motion events may hold either absolute or relative movements and other data, depending on the type of device.

该对象用于报告运动(鼠标、笔、手指、轨迹球)事件。
运动事件可以持有绝对或相对运动和其他数据,这取决于设备的类型。

细心的你可能会发现,上一小节我们的代码存在一个小问题,那就是如果我们点击 View 后拖动一段距离,并不会产生新的 Log 日志,这与我们预想的不一样,按道理应该会在滑动的过程中产生一系列的事件,并不断的调用 onTouchEvent 回调方法。

其实原因很简单,注意 onTouchEvent 回调方法,这是一个有返回值的方法,它的返回值是一个 boolean 类型,而上一节我们代码的最后一行是 return super.onTouchEvent(event);
该表达式的返回值其实是一个 false,我们可以查看 View 源码中的 onTouchEvent 方法的介绍,其中有这样一句话:

@return True if the event was handled, false otherwise.
如果事件被处理(消费)则返回 true,否则返回 false。

需要注意的是,我们在 View 上点击、滑动的时候,其实会产生很多的 MotionEvent,这些事件如同队列一样,依次的通过 onTouchEvent 回调方法来处理。这里因为我们使用的默认返回值 false,所以系统认为本次事件尚未处理完毕,所以我们后续的滑动事件,并没有被处理,只需将该方法的返回值设为 true 就可以不断的接收到点击事件。

2.2、MotionEvent 事件类型

查看源码可以得知,点击事件本身是区分事件类型的,常用的点击事件类型有:

public static final int ACTION_DOWN             = 0;//单点触摸动作
public static final int ACTION_UP               = 1;//单点触摸离开动作
public static final int ACTION_MOVE             = 2;//触摸点移动动作
public static final int ACTION_CANCEL           = 3;//触摸动作取消
public static final int ACTION_OUTSIDE          = 4;//触摸动作超出边界
public static final int ACTION_POINTER_DOWN     = 5;//多点触摸动作
public static final int ACTION_POINTER_UP       = 6;//多点离开动作

正常情况下,触摸一次屏幕都会产生一系列的触摸事件,我们可以使用 MotionEventCompat.getActionMasked(event) 方法来获知本次触摸时间的事件类型。

PS:可能你会在一些代码中看到使用 event.getAction() 方法来获取触摸事件的事件类型,但是需要注意的是,如果该 View 产生的是一个多点触摸事件,那么 event.getAction() 的返回值将不同于 MotionEventCompat.getActionMasked(event)。原因其实很简单,大家可以查看这两个方法的源码,或是参考getAction、getActionMask、getActionIndex区别这篇文章。

修改 onTouchEvent 回调方法如下:

@Override
public boolean onTouchEvent(MotionEvent event) {
    int action = MotionEventCompat.getActionMasked(event);
    event.getAction();
    switch(action) {
        case MotionEvent.ACTION_DOWN:
            Log.d(TAG, "down");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d(TAG, "move");
            break;
        case MotionEvent.ACTION_UP:
            Log.d(TAG, "up");
            break;
    }
    return true;
}

再次点击该 View 并滑动,可以看到 Logcat 上输出了一系列的触摸事件被触发的日志。


一系列的触摸事件
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容