Android开发小知识5—事件分发机制详细解析

事件概论

在Android开发中,事件的处理是非常重要的一部分,Android程序的事件流程参考了Java中的事件处理操作。 如要进行事件处理,必须要有一个事件源。事件源的产生可以有很多形式,如单击按钮、长按等,之后根据此事件源找到相应的事件处理操作类对事件进行处理。这篇文章中将详细的分析Android事件。

事件处理流程图.png

上图中事件处理主要涉及3个对象:

  • Event Source(事件源):事件发生的场所,可以简单的理解为组件。
  • Event(事件):事件封装了界面组件上发生的特定事件,通常是用户的操作,比如点击事件。可以通过Event获取具体事件。
  • Event Listener(事件监听器):监听事件源所发生的事件,并做出相应的处理。

事件监听器

事件监听器是View类中包含一个回调方法的接口。 当用户与APP发生交互,触发已注册此视图的监听器时,Android 将调用这些方法。

View.OnClickListener:当用户点击组件时, 调用此方法。

View.OnLongClickListener: 当用户长按组件时,将调用此方法。此方法必须返回一个布尔值,返回 true 表示您已经处理事件且事件应就此停止;如果您尚未处理事件和或事件应该继续传递给其他任何点击监听器,则返回 false。

View.OnFocusChangeListener: 当组件的焦点改变时,将调用此方法。

View.OnKeyListener:当APP的键盘发生状态改变时,将调用此方法。此方法必须返回一个布尔值,表示您是否已处理完事件,以及是否应该将它继续传下去。 也就是说,返回 true 表示您已经处理事件且事件应就此停止;如果您尚未处理事件和或事件应该继续传递给其他任何按键监听器,则返回 false。

View.OnTouchListener: 当用户执行可视为触摸事件的操作时,其中包括按下、释放或屏幕上的任何移动手势,将调用此方法。在复杂的布局中,此方法的调用永远一定的先后顺序(在后面将详细提及)。

View.OnCreateContextMenuListener: 当需要生成菜单时,将调用此方法。

这些方法是其相应接口的唯一成员。要定义其中一个方法并处理事件,一般的做法是在 Activity 中实现嵌套接口或将其定义为匿名类。然后,将实现的实例传递给相应的View.set...Listener()方法.例如,调用setOnClickListener()并向其传递OnClickListener实现。

匿名类实现
button.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  //TODO someting
              }
          });

事件处理程序(Event)

默认事件处理程序的回调方法中,有如下几种用于事件处理的常见回调,其中包括:

  • onKeyDown(int, KeyEvent):在发生新的按键事件时调用。
  • onKeyUp(int, KeyEvent):在发生按键弹起事件时调用。
  • onTrackballEvent(MotionEvent):在发生轨迹球运动事件时调用。
  • onTouchEvent(MotionEvent):在发生触摸屏运动事件时调用。
  • onFocusChanged(boolean, int, Rect):在视图获得或失去焦点时调用。
事件的类型:

ACTION_DOWN:表示用户开始触摸。
ACTION_MOVE:表示用户在移动(手指或者其他)。
ACTION_UP:表示用户抬起了手指。
ACTION_CANCEL:表示手势被取消了。
ACTION_OUTSIDE:表示用户触碰超出了正常的UI边界。
ACTION_POINTER_DOWN:有一个非主要的手指按下了。
ACTION_POINTER_UP:一个非主要的手指抬起来了。

事件发生的位置,x,y轴:

getX():获得事件发生时,触摸的中间区域在屏幕的X轴。
getY() :获得事件发生时,触摸的中间区域在屏幕的X轴。
在多点触控中还可以通过:
getX(int pointerIndex):来获得对应手指事件的发生位置. 获得X轴用。
getY(int pointerIndex):来获得对应手指事件的发生位置. 获得Y轴用 。

事件分发机制

在管理布局内更复杂的事件时,对于事件的响应处理会从最顶层的组件不断向子组件传递,一直到最后的View组件。因此,在复杂布局中,对事件的处理也要考虑一下如下方法。

onTouchEvent:在发生触摸屏运动事件时调用。是真正用来进行业务逻辑处理的地方,返回true表示已经将该事件消费,返回false表明事件继续传递。

onInterceptTouchEvent:此方法允许ViewGroup监视分派给子视图的事件,返回false表示无需拦截,则递归的调用子组件的dispatchTouchEvent。返回true表示需要拦截,则直接调用本组件的onTouchEvent方法进行处理。因此,次方法只会存在于ViewGroup中。

dispatchTouchEvent:此方法的情况比较复杂,要区分在ViewGroup和View中的其区别。
ViewGroupdispatchTouchEvent()具体的执行逻辑:

首先执行本组件的onInterceptTouchEvent。如果返回false,表明无需拦截,则调用第二个方法,即子组件的dispatchTouchEvent方法;如果返回true,无需向子组件传递,则直接调用本组件的onTouchEvent方法。 如果需要向子组件传递事件。如果递归调用子组件的dispatchTouchEvent返回false,则调用本组件的onTouchEvent方法;如果递归调用子组件的dispatchTouchEvent返回true,则无需调用本组件的onTouchEvent方法。 最后子组件的dispatchTouchEvent的返回值会返回给父组件的dispatchTouchEvent方法。

view中的dispatchTouchEvent会直接调用其自身的onTouchEvent

ViewGroup`dispatchTouchEvent()`.png

总结

对于事件,重要的是在设计开发中的应用和理解。这里只是分享了我的一些认识。如有不足之处,希望多多指出。文章参考了AndroidAPI指南和Android MotionEvent事件响应机制

原文作者litterMay
原文链接:http://www.jianshu.com/p/8e8e048fa61e

你可能感兴趣的:(Android开发小知识5—事件分发机制详细解析)