【cocos2d-js公文】十七、事件分发机制
简单介绍
游戏开发中一个非常重要的功能就是交互,假设没有与用户的交互。那么游戏将变成动画,而处理用户交互就须要使用事件监听器了。
总概:
- 事件监听器(cc.EventListener) 封装用户的事件处理逻辑
- 事件管理器(cc.eventManager) 管理用户注冊的事件监听器,依据触发的事件类型分发给对应的事件监听器
- 事件对象(cc.Event) 包括事件相关信息的对象
怎样使用呢? 首先须要创建一个事件监听器。事件监听器包括下面几种类型:
- 触摸事件监听器 (cc.EventListenerTouch)
- 键盘事件监听器 (cc.EventListenerKeyboard)
- 加速计事件监听器 (cc.EventListenerAcceleration)
- 鼠标事件监听器 (cc.EventListenerMouse)
- 自己定义事件监听器 (cc.EventListenerCustom)
在监听器中实现各种事件的处理逻辑,然后将监听器增加到事件管理器中, 当事件触发时,事件管理器会依据事件类型分发给对应的事件监听器。以下以一个简单的演示样例来演示使用的方法。
用法
如今会在一个场景中加入三个button(cc.Sprite),三个button将会互相遮挡,而且都须要可以监听和处理触摸事件。下面是详细实现
首先创建三个精灵,作为三个button的显示图片
var sprite1 = new cc.Sprite("Images/CyanSquare.png");
sprite1.x = size.width/2 - 80;
sprite1.y = size.height/2 + 80;
this.addChild(sprite1, 10); var sprite2 = new cc.Sprite("Images/MagentaSquare.png");
sprite2.x = size.width/2;
sprite2.y = size.height/2;
this.addChild(sprite2, 20); var sprite3 = new cc.Sprite("Images/YellowSquare.png");
sprite3.x = 0;
sprite3.y = 0;
sprite2.addChild(sprite3, 1);
创建一个单点触摸事件监听器(事件类型:TOUCH_ONE_BY_ONE),并完毕逻辑处理内容
// 创建一个事件监听器 OneByOne 为单点触摸
var listener1 = cc.EventListener.create({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches: true, // 设置是否吞没事件,在 onTouchBegan 方法返回 true 时吞掉事件,不再向下传递。 onTouchBegan: function (touch, event) { //实现 onTouchBegan 事件处理回调函数
var target = event.getCurrentTarget(); // 获取事件所绑定的 target, 一般是cc.Node及其子类 // 获取当前触摸点相对于button所在的坐标
var locationInNode = target.convertToNodeSpace(touch.getLocation());
var s = target.getContentSize();
var rect = cc.rect(0, 0, s.width, s.height); if (cc.rectContainsPoint(rect, locationInNode)) { // 推断触摸点是否在button范围内
cc.log("sprite began... x = " + locationInNode.x + ", y = " + locationInNode.y);
target.opacity = 180;
return true;
}
return false;
},
onTouchMoved: function (touch, event) { //实现onTouchMoved事件处理回调函数, 触摸移动时触发
// 移动当前button精灵的坐标位置
var target = event.getCurrentTarget();
var delta = touch.getDelta(); //获取事件数据: delta
target.x += delta.x;
target.y += delta.y;
},
onTouchEnded: function (touch, event) { // 实现onTouchEnded事件处理回调函数
var target = event.getCurrentTarget();
cc.log("sprite onTouchesEnded.. ");
target.setOpacity(255);
if (target == sprite2) {
sprite1.setLocalZOrder(100); // 又一次设置 ZOrder。显示的前后顺序将会改变
} else if (target == sprite1) {
sprite1.setLocalZOrder(0);
}
}
});
引擎提供了cc.EventListener.create统一来创建各类型的事件监听器,能够通过指定不同的 event
来设置想要创建的监听器类型,如上例中的cc.EventListener.TOUCH_ONE_BY_ONE
为单点触摸事件监听器。
可选event
类型列表:
- cc.EventListener.TOUCH_ONE_BY_ONE (单点触摸)
- cc.EventListener.TOUCH_ALL_AT_ONCE (多点触摸)
- cc.EventListener.KEYBOARD (键盘)
- cc.EventListener.MOUSE (鼠标)
- cc.EventListener.ACCELERATION (加速计)
- cc.EventListener.CUSTOM (自己定义)
将事件监听器加入到事件管理器中
// 加入监听器到管理器
cc.eventManager.addListener(listener1, sprite1);
cc.eventManager.addListener(listener1.clone(), sprite2);
cc.eventManager.addListener(listener1.clone(), sprite3);
这里的cc.eventManager 是一个单例对象,可直接拿来使用。通过调用 addListener
函数能够将listener增加到管理器中。须要注意的是第二个參数,假设传入的是一个Node对象,则增加的是SceneGraphPriority(精灵以显示优先级)
类型的listener,假设是一个数值类型的參数。则增加到的是FixedPriority 类型的listener。
注意: 这里当我们想给不同的节点使用同样的事件监听器时。须要使用 clone()
函数克隆出一个新的监听器。由于在使用 addListener
方法时,会对当前使用的事件监听器加入一个已注冊的标记。这使得它不可以被加入多次。另外,有一点很重要,FixedPriority
类型的 listener加入完之后须要手动删除,而SceneGraphPriority 类型的 listener是跟node绑定的,在node调用cleanup时会被移除。
详细的演示样例使用方法能够參考引擎自带的tests。
更高速的加入事件监听器到管理器的方式
以下提交一种更快捷绑定事件到节点的方式。 只是这样做就不会得到监听器的引用,无法再对监听器进行其它操作,适用于一些简单的事件操作。 代码例如以下:
cc.eventManager.addListener({
event: cc.EventListener.TOUCH_ALL_AT_ONCE,
onTouchesMoved: function (touches, event) {
var touch = touches[0];
var delta = touch.getDelta(); var node = event.getCurrentTarget().getChildByTag(TAG_TILE_MAP);
var diff = cc.pAdd(delta, node.getPosition());
node.setPosition(diff);
}
}, this);
cc.eventManager的 addListener
的第一个參数也支持两种类型的參数: cc.EventListener
类型对象和json格式的对象,假设是json格式对象,方法会依据传入的event
属性来创建相应的监听器。
新的触摸机制
以上的步骤相对于 2.x 版本号触摸机制实现。稍显复杂了点。在老的版本号中仅仅需在节点中重载onTouchBegan
/onTouchesBegan
等方法,
处理相应的触摸事件逻辑,然后调用cc.registerTargetedDelegate
或cc.registerStandardDelegate
将节点增加到触摸事件分发器中就能够了,甚至有些已封装的类仅仅须要调用setTouchEnabled
,
就能够开启触摸事件,比方:cc.Layer
。
而新机制将事件处理逻辑独立出来,封装到一个 监听器(listner) 中,使得不同对象能够使用同一份监听器代码(使用clone()
来达到目的)。另外,cc.eventManager增加了精灵以显示优先级
(SceneGraphPriority)排序的功能,以这种类型注冊的监听器,事件管理器会依据屏幕显示的情况来决定事件会优化分发给哪个事件监听器。 而2.x要实现这种功能却很的麻烦。须要用户自己通过调用setPriority
来管理节点的事件响应优先级。
注意:与 SceneGraphPriority 所不同的是 FixedPriority 将会根据手动设定的 Priority
值来决定事件对应的优先级,值越小优先级越高,
后面章节中会作更详细的解说。
其他事件派发处理模块
除了触摸事件响应之外,还能够使用同样的事件处理方式来处理其它事件。
键盘响应事件
除了能够监听键盘按键,还能够是终端设备的各个菜单键。都能使用同一个监听器来进行处理。
//给statusLabel绑定键盘事件
cc.eventManager.addListener({
event: cc.EventListener.KEYBOARD,
onKeyPressed: function(keyCode, event){
var label = event.getCurrentTarget();
//通过推断keyCode来确定用户按下了哪个键
label.setString("Key " + keyCode.toString() + " was pressed!");
},
onKeyReleased: function(keyCode, event){
var label = event.getCurrentTarget();
label.setString("Key " + keyCode.toString() + " was released!");
}
}, statusLabel);
加速计事件
在使用加速计事件监听器之前。须要先启用此硬件设备, 代码例如以下:
cc.inputManager.setAccelerometerEnabled(true);
然后将对应的事件处理监听器与sprite进行绑定就能够了,例如以下:
cc.eventManager.addListener({
event: cc.EventListener.ACCELERATION,
callback: function(acc, event){
//这里处理逻辑
}
}, sprite);
鼠标响应事件
对于PC和超级本,加入鼠标事件的的处理,能够加强用户的体验,其处理逻辑与触摸事件基本一样,多了一些鼠标特有的事件响应。如滚轮事件(onMouseScroll).
cc.eventManager.addListener({
event: cc.EventListener.MOUSE,
onMouseMove: function(event){
var str = "MousePosition X: " + event.getLocationX() + " Y:" + event.getLocationY();
// do something...
},
onMouseUp: function(event){
var str = "Mouse Up detected, Key: " + event.getButton();
// do something...
},
onMouseDown: function(event){
var str = "Mouse Down detected, Key: " + event.getButton();
// do something...
},
onMouseScroll: function(event){
var str = "Mouse Scroll detected, X: " + event.getLocationX() + " Y:" + event.getLocationY();
// do something...
}
},this);
注意: 因为在PC浏览器中。没有触摸事件。而此时强制要求用户写鼠标事件的响应代码。必定会让开发人员多写非常多代码。其实触摸响应的逻辑与鼠标相差不大,所以引擎在检測到不支持触摸事件时,会让鼠标事件模拟成触摸事件进行分发,开发人员仅仅需编写触摸事件监听器就能完毕大部分工作。而对于针对鼠标操作而设计的游戏,须要推断用户按下什么键,响应滚轮等,这就须要开发人员编写鼠标事件监听器了。
(开发人员反馈,鼠标事件监听器也须要有swallowTouches这个选项。我们将会有v3.1版本号中增加这个项.)
自己定义事件
以上是系统自带的事件类型,这些事件由系统内部自己主动触发。如 触摸屏幕,键盘响应等,除此之外,还提供了一种 自己定义事件。简而言之,它不是由系统自己主动触发。而是人为的干涉,例如以下:
var _listener1 = cc.EventListener.create({
event: cc.EventListener.CUSTOM,
eventName: "game_custom_event1",
callback: function(event){
// 能够通过getUserData来设置须要传输的用户自己定义数据
statusLabel.setString("Custom event 1 received, " + event.getUserData() + " times");
}
});
cc.eventManager.addListener(this._listener1, 1);
以上定义了一个 “自己定义事件监听器”,实现了一些逻辑, 而且加入到事件分发器。
那么以上逻辑是在什么情况下响应呢?请看例如以下:
++this._item1Count;
var event = new cc.EventCustom("game_custom_event1");
event.setUserData(this._item1Count.toString());
cc.eventManager.dispatchEvent(event);
创建了一个自己定义事件(EventCustom
)对象 ,而且设置了其用户自己定义(UserData)数据,手动调用cc.eventManager.dispatchEvent(event);
将此事件分发出去,从而触发之前监听器中所实现的逻辑。
cc.eventManager增加自己定义事件的处理,开发人员就能够非常方便的使用该功能来实现观察者模式。
移除事件监听器
我们能够通过下面方法移除一个已经被加入了的监听器。
cc.eventManager.removeListener(listener); //移除一个已加入的监听器
也能够使用removeListeners
,移除注冊到cc.eventManager
中指定类型的全部监听器,当然使用该函数时。传入的參数假设是一个节点(cc.Node及其子类)对象。
事件管理器将移除与该对象相关的全部事件监听器, 代码例如以下:
cc.eventManager.removeListeners(cc.EventListener.TOUCH_ONE_BY_ONE); //移除全部单点触摸事件监听器
cc.eventManager.removeListeners(aSprite); //移除全部与aSprite相关的监听器
事件管理器还提供了函数用来移除已注冊的全部监听器。
cc.eventManager.removeAllListeners();
当使用 removeAllListeners
的时候,此节点的全部的监听将被移除,推荐使用 指定删除的方式。
_注意:调用removeAllListeners
之后 菜单(cc.Menu
)
也不能响应。由于它内部有一个触摸事件监听器。也会从事件管理器中删除。
暂停/恢复
与场景相关(SceneGraph类型)的监听器
开发过程中,我们常常会遇到这种情况:想要让一个Layer中全部的Node对象的事件都停止响应。 在响应用户事件后。又要恢复该Layer的全部事件响应。如: 用户想要显示一个模式对话框。显示对话框后,禁止对话框后全部对象的事件响应。 在用户关闭对话框后,又恢复这些对象的事件响应。
我们仅仅须要暂停根node的事件,就能够让根节点以及其子节点暂停事件响应。 代码例如以下:
cc.eventManager.pauseTarget(aLayer, true); //让aLayer对象暂停响应事件
而恢复对象的事件响应也很easy:
cc.eventManager.resumeTarget(aLayer, true); //让aLayer对象恢复响应事件
注意: 第二个參数为可选參数。默认值为false, 表示是否递归调用子节点的暂停/恢复操作.
进阶话题
SceneGraphPriority类型与FixedPriority类型具体解释
事件管理器将监听器类型分为两大类:SceneGraphPriority和FixedPriority, 以下将会具体说明它们之间的差别, 并介绍FixedPriority的使用场景与用法。
SceneGraphPriority事件类型是指事件的响应优先级与监听器关联对象在场景中显示顺序(zOrder)相关, 比方一个精灵对象在场景的显示在最上层时,它对事件的响应优先级最高。
这样开发人员就不须要再像v2.x中那样在场景对象的zOrder变化后,手动再调用setPriority
来改变对应的优先级了,这些事将交由管理器来处理。
而 FixedPriority 事件类型则是相对于 SceneGraphPriority 来定义的,不须要与场景显示顺序相关的事件监听器 也就是优化级固定的(fixed)。就能够注冊成FixedPriority类型事件。
我们的SceneGraphPriority定义的系统优先级是0, 在加入监听器(addListener
)时,
假设第二个參数设置为负数时,该监听器就会拥有比全部场景相关监听器都高的优先级。 而假设是正数。则反之。
那么什么情况下使用FixedPriority类型的监听器呢? 比方。一个冒险类的游戏中。游戏主角应该要最先响应触摸事件。而UI界面的button往往会安排在界面的最上层。可是。假设主角移动到了button的后面。这时点击游戏主角。假设游戏主角注冊的是SceneGraphPriority类型监听器,响应的将会是button事件。
而假设注冊成FixedPriority类型,并把它的优先级设置为负数,将会响应游戏主角的事件。
有开发人员反馈想保持他们在v2.x的响应优先级管理机制。由于他们有特殊的需求。那么这部分开发人员也能够使用FixedPriority来管理,cc.eventManager
也提供了一个setPriority
函数来管理优先级。
UI控件的事件处理具体解释
Cocos提供一套UI控件。很多开发人员对于控件的事件响应。特别是对于容器类控件(如:ccui.PageView, ccui.ScrollView)的事件响应有些疑惑。这里将具体说明控件的事件处理流程。
首先来看一下ccui.Widget
的事件实现, 全部的控件的事件监听器都是单点触摸事件,而且会吞食事件,注冊代码例如以下:
this._touchListener = cc.EventListener.create({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches: true,
onTouchBegan: this.onTouchBegan.bind(this),
onTouchMoved: this.onTouchMoved.bind(this),
onTouchEnded: this.onTouchEnded.bind(this)
});
cc.eventManager.addListener(this._touchListener, this);
然后看一下它的各事件响应函数。会发现每一个函数都会有类似这种语句: if (widgetParent) widgetParent.interceptTouchEvent(ccui.Widget.TOUCH_XXXXX, this,
touch);
这句的意思是,在控件处理完自己的触摸事件之后。都会向父节点(widgetParent)发送事件响应通知。那么,interceptTouchEvent的实现是什么呢? 代码例如以下:
interceptTouchEvent: function(eventType, sender, touch){
var widgetParent = this.getWidgetParent();
if (widgetParent)
widgetParent.interceptTouchEvent(eventType,sender,touch);
}
对于像ccui.Button, ccui.ImageView这种控件。它仅仅是简单的向父类发送事件通知即可了,而对于像ccui.PageView这种容器类控件。会对这些通知做出响应,代码例如以下:
interceptTouchEvent: function (eventType, sender, touch) {
var touchPoint = touch.getLocation();
switch (eventType) {
case ccui.Widget.TOUCH_BEGAN:
this._touchBeganPosition.x = touchPoint.x;
this._touchBeganPosition.y = touchPoint.y;
break;
case ccui.Widget.TOUCH_MOVED:
this._touchMovePosition.x = touchPoint.x;
this._touchMovePosition.y = touchPoint.y;
var offset = 0;
offset = Math.abs(sender.getTouchBeganPosition().x - touchPoint.x);
if (offset > this._childFocusCancelOffset) {
sender.setFocused(false);
this._handleMoveLogic(touch);
}
break;
case ccui.Widget.TOUCH_ENDED:
case ccui.Widget.TOUCH_CANCELED:
this._touchEndPosition.x = touchPoint.x;
this._touchEndPosition.y = touchPoint.y;
this._handleReleaseLogic(touch);
break;
}
}
这种处理。就能实如今button上滑动时。也能让其父节点的PageView触摸事件。不然,假设不採用这种机制,当一个PageView中填满了子控件时。PageView将无法响应触摸事件。
属性与方法列表
cc.Event
(事件类)
属性/方法 | 类型 | 參数说明 | 使用方法说明 |
---|---|---|---|
getType | Number | no | 返回事件类型,包括:TOUCH, KEYBOARD, ACCELERATION, MOUSE, CUSTOM |
stopPropagation | void | no | 停止当前事件的冒泡 |
isStopped | Boolean | no | 事件是否已停止 |
getCurrentTarget | cc.Node | no | 返回事件相关的Node对象, 假设事件未与cc.Node对象关联,则返回null |
cc.EventCustom
(自己定义事件)
cc.EventCustom
继承自 cc.Event
属性/方法 | 类型 | 參数说明 | 使用方法说明 |
---|---|---|---|
setUserData | void | data: 要设置的自己定义数据 | 设置用户自己定义数据 |
getUserData | * | no | 返回用户设置的自己定义数据 |
getEventName | String | no | 返回自己定义事件名称 |
cc.EventMouse
(鼠标事件)
cc.EventMouse
继承自 cc.Event
属性/方法 | 类型 | 參数说明 | 使用方法说明 |
---|---|---|---|
setScrollData | void | scrollX。 scrollY | 设置滚轮数据 |
getScrollX | Number | no | 返回x轴滚轮数据 |
getScrollY | Number | no | 返回y轴滚轮数据 |
setLocation | void | x, y | 设置鼠标光标位置 |
getLocation | cc.Point | no | 获取鼠标光标位置 |
getLocationInView | cc.Point | no | 返回鼠标光标在屏幕上的位置 |
getDelta | cc.Point | no | 获取当前光标与上一光标的偏移量 |
setButton | void | button | 设置鼠标按键 |
getButton | Number | no | 获取鼠标按键 |
cc.EventTouch
()
cc.EventTouch
继承自 cc.Event
属性/方法 | 类型 | 參数说明 | 使用方法说明 |
---|---|---|---|
getEventCode | Number | no | 获取触摸事件类型代码: BEGAN, MOVED, ENDED, CANCELLED |
getTouches | Array | no | 获取触摸事件中全部点信息 |
cc.EventListener
(事件监听器)
属性/方法 | 类型 | 參数说明 | 使用方法说明 |
---|---|---|---|
checkAvailable | boolean | no | 检測监听器是否有效 |
clone | cc.EventListener | no | 克隆一个监听器,其子类会重写本函数 |
create | cc.EventListener | json object | 通过json对象创建事件监听器 |
cc.EventListener.create
函数參数列表:
创建EventListenerTouchOneByOne对象:
event: cc.EventListener.TOUCH_ONE_BY_ONE
可选參数:
- swallowTouches, boolean, 是否吞下该touch点
- onTouchBegan, function, TouchBegan 事件回调
- onTouchMoved, function, TouchMoved 事件回调
- onTouchEnded, function, TouchEnded 事件回调
- onTouchCancelled, function, TouchCancelled 事件回调
创建EventListenerTouchAllAtOnce对象:
event: cc.EventListener.TOUCH_ALL_AT_ONCE
可选參数:
- onTouchesBegan, function, TouchesBegan 事件回调
- onTouchesMoved, function, TouchesMoved 事件回调
- onTouchesEnded, function, TouchesEnded 事件回调
- onTouchesCancelled, function, TouchesCancelled 事件回调
创建EventListenerKeyboard对象:
event: cc.EventListener.KEYBOARD
可选參数:
- onKeyPressed, function, KeyPressed (键按下) 事件回调
- onKeyReleased, function, keyRelease (键放开) 事件回调
创建EventListenerMouse对象:
event: cc.EventListener.MOUSE
可选參数:
- onMouseDown, function, MouseDown 事件回调
- onMouseUp, function, MouseUp 事件回调
- onMouseMove, function, MouseMove 事件回调
- onMouseScroll, function, MouseScroll 事件回调
创建EventListenerAcceleration对象:
event: cc.EventListener.ACCELERATION
可选參数:
- callback, function, Acclerometer 事件回调
创建EventListenerCustom对象:
event: cc.EventListener.CUSTOM
可选參数:
- callback, function, 自己定义事件回调
cc.eventManager
属性/方法 | 类型 | 參数说明 | 使用方法说明 |
---|---|---|---|
pauseTarget | void | node, recursive(是否递归调用子类) | 暂停传入的node相关的全部监听器的事件响应 |
resumeTarget | void | node, recursive | 恢复传入的node相关的全部监听器的事件响应 |
addListener | void | json对象或cc.EventListener, node对象或优化值 | 向事件管理器加入一个监听器 |
addCustomListener | void | eventName, callback | 向事件管理器加入一个自己定义事件监听器 |
removeListener | void | listener | 移除一个事件监听器 |
removeListeners | void | listenerType | cc.Node, recursive |
removeCustomListeners | void | customEventName | 移除同一事件名的自己定义事件监听器 |
removeAllListeners | void | no | 移除全部事件监听器 |
setPriority | void | listener, fixedPriority | 设置FixedPriority类型监听器的优先集 |
setEnabled | void | enabled | 是否同意分发事件 |
isEnabled | boolean | no | 检測事件管理器是否分发事件 |
dispatchEvent | void | event | 分发事件 |
dispatchCustomEvent | void | eventName, optionalUserData | 分发自己定义事件 |
【cocos2d-js公文】十七、事件分发机制的更多相关文章
- Cocos2d-x 3.2 学习笔记(九)EventDispatcher事件分发机制
EventDispatcher事件分发机制先创建事件,注册到事件管理中心_eventDispatcher,通过发布事件得到响应进行回调,完成事件流. 有五种不同的事件机制:EventListenerT ...
- Android与javascript中事件分发机制的简单比较
在前面两篇博客中,我们讨论了Android中的事件分发的相关内容,那么在本篇博客当中,我们就简单探讨一下html或javascript中的事件分发机制,并进行简单的对比. 在前端中,对事件进行绑定有三 ...
- cocos2d-x游戏引擎核心(3.x)----事件分发机制之事件从(android,ios,desktop)系统传到cocos2dx的过程浅析
(一) Android平台下: cocos2dx 版本3.2,先导入一个android工程,然后看下AndroidManifest.xml <application android:label= ...
- Cocos2d-X研究之v3.x 事件分发机制具体解释
事件分发机制 " src="http://www.cgzhw.com/wp-content/uploads/2014/07/inherent3.png" style=&q ...
- Android事件分发机制浅谈(一)
---恢复内容开始--- 一.是什么 我们首先要了解什么是事件分发,通俗的讲就是,当一个触摸事件发生的时候,从一个窗口到一个视图,再到一个视图,直至被消费的过程. 二.做什么 在深入学习android ...
- Android事件分发机制浅谈(二)--源码分析(ViewGroup篇)
上节我们大致了解了事件分发机制的内容,大概流程,这一节来分析下事件分发的源代码. 我们先来分析ViewGroup中dispatchTouchEvent()中的源码 public boolean dis ...
- Atitit View事件分发机制
1. Atitit View事件分发机制 1. Atitit View事件分发机制1 1.1. 三个关键方法 dispatchTouchEvent onInterceptTouchEvent onTo ...
- Android Touch事件分发机制学习
Android 事件分发机制 ViewGroup dispatchTouchEvent 返回true dispatchTouchEvent: Activity ACTION_DOWN Myrelat ...
- android 事件分发机制
1.View的事件分发机制 一个button,简单一点就是onTouch,还有onclick事件,我们一个一个来分析 首先响应的是dispatchTouchEvent public boolean d ...
- Android View 事件分发机制 源码解析 (上)
一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~ 首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个My ...
随机推荐
- 【Oracle】nvl与nvl2对比
1.nvl(v1,v2),只要v1为null,即将值变为v2. pay(类型):number; 在执行 nvl(pay_type,'null') 函数的时候会提示无效数字,可能是nvl函数会自动将其转 ...
- [Swust OJ 166]--方程的解数(hash法)
题目链接:http://acm.swust.edu.cn/problem/0166/ Time limit(ms): 5000 Memory limit(kb): 65535 有如下方程组: A1 ...
- Javascript DOM 03 表格添加、删除 + 搜索
获取 tBodies.tHead.tFoot.rows.cells 隔行变色 鼠标移入高亮 添加.删除一行 DOM方法的使用 ...
- iOS 开发设计常用软件及工具整理
1, xCode 2, AppCode 3, Skech 原型设计软件 4, Hype 动画设计工具 5, fontawsome 免费图表 6, Prepo icon, images.catlog 生 ...
- 用Flask实现视频数据流传输
Flask 是一个 Python 实现的 Web 开发微框架.这篇文章是一个讲述如何用它实现传送视频数据流的详细教程. 我敢肯定,现在你已经知道我在O’Reilly Media上发布了有关Flask的 ...
- hadoop安全模式
hadoop安全模式在分布式文件系统启动的时候,开始的时候会有安全模式,当分布式文件系统处于安全模式的情况下,文件系统中的内容不允许修改也不允许删除,直到安全模式结束.安全模式主要是为了系统启动的 ...
- 年度酷工作---高级数据工程师(公司靠谱,技术强悍,产品牛叉,福利有干货) 关键词:7000万用户、五星级厨师、住房补助 - V2EX
年度酷工作---高级数据工程师(公司靠谱,技术强悍,产品牛叉,福利有干货) 关键词:7000万用户.五星级厨师.住房补助 - V2EX 年度酷工作---高级数据工程师(公司靠谱,技术强悍,产品牛叉,福 ...
- Eclipse3.6 添加JUnit源代码
Eclipse中无法查看JUnit源代码,也无法设置源代码的jar. 解决方法: 1. 下载org.junit.source_4.8.1.v4_8_1_v20100427-1100.jar,放到ec ...
- osgi实战学习之路:8. Service-3之ServiceTracker
通过ServiceTracker能够对查找的Service进行扩展 以下的demo引入装饰器模式对Service进行日志的扩展 demo: Provider student-manage/Activa ...
- Linux之shell编程基础
一.变量 变量在shell中分为:本地变量.环境变量.位置参数: 本地变量:仅可在用户当前shell生命期的脚本中使用的变量,本地变量随着shell进程的消亡而无效,本地变量在新启动的shell中依旧 ...