处理用户界面事件Handling UI Events android
在Android上,不止一个途径来侦听用户和应用程序之间交互的事件。对于用户界面里的事件,侦听方法就是从与用户交互的特定视图对象截获这些事件。视图类提供了相应的手段。 算法
在各类用来组建布局的视图类里面,你可能会注意到一些公共的回调方法看起来对用户界面事件有用。这些方法在该对象的相关动做发生时被Android框架调用。好比,当一个视图(如一个按钮)被触摸时,该对象上的onTouchEvent()方法会被调用。不过,为了侦听这个事件,你必须扩展这个类并重写该方法。很明显,扩展每一个你想使用的视图对象(只是处理一个事件)是荒唐的。这就是为何视图类也包含了一个嵌套接口的集合,这些接口含有实现起来简单得多的回调函数。这些接口叫作事件侦听器event listeners,是用来截获用户和你的界面交互动做的“门票”。 框架
当你更为广泛的使用事件侦听器来侦听用户动做时,总有那么一次你可能得为了建立一个自定义组件而扩展一个视图类。也许你想扩展按钮Button类来使某些事更花哨。在这种状况下,你将可以使事件处理器event handlers类来为你的类定义缺省事件行为。 函数
事件侦听器是视图View类的接口,包含一个单独的回调方法。这些方法将在视图中注册的侦听器被用户界面操做触发时由Android框架调用。下面这些回调方法被包含在事件侦听器接口中: 布局
onClick() 学习
包含于View.OnClickListener。当用户触摸这个item(在触摸模式下),或者经过浏览键或跟踪球聚焦在这个item上,而后按下“确认”键或者按下跟踪球时被调用。 ui
onLongClick() this
包含于View.OnLongClickListener。当用户触摸并控制住这个item(在触摸模式下),或者经过浏览键或跟踪球聚焦在这个item上,而后保持按下“确认”键或者按下跟踪球(一秒钟)时被调用。 spa
onFocusChange() 对象
包含于View.OnFocusChangeListener。当用户使用浏览键或跟踪球浏览进入或离开这个item时被调用。
onKey()
包含于View.OnKeyListener。当用户聚焦在这个item上并按下或释放设备上的一个按键时被调用。
onTouch()
包含于View.OnTouchListener。当用户执行的动做被当作一个触摸事件时被调用,包括按下,释放,或者屏幕上任何的移动手势(在这个item的边界内)。
onCreateContextMenu()
包含于View.OnCreateContextMenuListener。当正在建立一个上下文菜单的时候被调用(做为持续的“长点击”动做的结果)。参阅建立菜单Creating Menus章节以获取更多信息。
这些方法是它们相应接口的惟一“住户”。要定义这些方法并处理你的事件,在你的活动中实现这个嵌套接口或定义它为一个匿名类。而后,传递你的实现的一个实例给各自的View.set...Listener() 方法。(好比,调用setOnClickListener()并传递给它你的OnClickListener实现。)
下面的例子说明了如何为一个按钮注册一个点击侦听器:
// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
public void onClick(View v) {
// do something when the button is clicked
}
};
protected void onCreate(Bundle savedValues) {
...
// Capture our button from layout
Button button = (Button)findViewById(R.id.corky);
// Register the onClick listener with the implementation above
button.setOnClickListener(mCorkyListener);
...
}
你可能会发现把OnClickListener做为活动的一部分来实现会便利的多。这将避免额外的类加载和对象分配。好比:
public class ExampleActivity extends Activity implements OnClickListener {
protected void onCreate(Bundle savedValues) {
...
Button button = (Button)findViewById(R.id.corky);
button.setOnClickListener(this);
}
// Implement the OnClickListener callback
public void onClick(View v) {
// do something when the button is clicked
}
...
}
注意上面例子中的onClick()回调没有返回值,可是一些其它事件侦听器必须返回一个布尔值。缘由和事件相关。对于其中一些,缘由以下:
· onLongClick() – 返回一个布尔值来指示你是否已经消费了这个事件而不该该再进一步处理它。也就是说,返回true 表示你已经处理了这个事件并且到此为止;返回false 表示你尚未处理它和/或这个事件应该继续交给其余on-click侦听器。
· onKey() –返回一个布尔值来指示你是否已经消费了这个事件而不该该再进一步处理它。也就是说,返回true 表示你已经处理了这个事件并且到此为止;返回false 表示你尚未处理它和/或这个事件应该继续交给其余on-key侦听器。
· onTouch() - 返回一个布尔值来指示你的侦听器是否已经消费了这个事件。重要的是这个事件能够有多个彼此跟随的动做。所以,若是当接收到向下动做事件时你返回false,那代表你尚未消费这个事件并且对后续动做也不感兴趣。那么,你将不会被该事件中的其余动做调用,好比手势或最后出现向上动做事件。
记住按键事件老是递交给当前焦点所在的视图。它们从视图层次的顶层开始被分发,而后依次向下,直到到达恰当的目标。若是你的视图(或者一个子视图)当前拥有焦点,那么你能够看到事件经由dispatchKeyEvent()方法分发。除了从你的视图截获按键事件,还有一个可选方案,你还能够在你的活动中使用onKeyDown() and onKeyUp()来接收全部的事件。
注意: Android 将首先调用事件处理器,其次是类定义中合适的缺省处理器。这样,从这些事情侦听器中返回true 将中止事件向其它事件侦听器传播而且也会阻塞视图中的缺事件处理器的回调函数。所以当你返回true时确认你但愿终止这个事件。
若是你从视图建立一个自定义组件,那么你将可以定义一些回调方法被用做缺省的事件处理器。在建立自定义组件Building Custom Components的文档中,你将学习到一些用做事件处理的通用回调函数,包括:
· onKeyDown(int, KeyEvent) - 当一个新的按键事件发生时被调用。
· onKeyUp(int, KeyEvent) - 当一个向上键事件发生时被调用。
· onTrackballEvent(MotionEvent) - 当一个跟踪球运动事件发生时被调用。
· onTouchEvent(MotionEvent) - 当一个触摸屏移动事件发生时调用。
· onFocusChanged(boolean, int, Rect) - 当视图得到或者丢失焦点时被调用。
你应该知道还有一些其它方法,并不属于视图类的一部分,但能够直接影响你处理事件的方式。因此,当在一个布局里管理更复杂的事件时,考虑一下这些方法:
· Activity.dispatchTouchEvent(MotionEvent) - 这容许你的活动能够在分发给窗口以前捕获全部的触摸事件。
· ViewGroup.onInterceptTouchEvent(MotionEvent) - 这容许一个视图组ViewGroup 在分发给子视图时观察这些事件。ViewParent.requestDisallowInterceptTouchEvent(boolean) - 在一个父视图之上调用这个方法来表示它不该该经过onInterceptTouchEvent(MotionEvent)来捕获触摸事件。
触摸模式Touch Mode
当用户使用方向键或跟踪球浏览用户界面时,有必要给用户可操做的item(好比按钮)设置焦点,这样用户能够知道哪一个item将接受输入。不过,若是这个设备有触摸功能,并且用户经过触摸来和界面交互,那么就不必高亮items,或者设定焦点到一个特定的视图。这样,就有一个交互模式 叫“触摸模式”。
对于一个具有触摸功能的设备,一旦用户触摸屏幕,设备将进入触摸模式。自此之后,只有isFocusableInTouchMode()为真的视图才能够被聚焦,好比文本编辑部件。其余可触摸视图,如按钮,在被触摸时将不会接受焦点;它们将只是在被按下时简单的触发on-click侦听器。任什么时候候用户按下方向键或滚动跟踪球,这个设备将退出触摸模式,而后找一个视图来接受焦点,用户也许不会经过触摸屏幕的方式来恢复界面交互。
触摸模式状态的维护贯穿整个系统(全部窗口和活动)。为了查询当前状态,你能够调用isInTouchMode() 来查看这个设备当前是否处于触摸模式中。
处理焦点Handling Focus
框架将根据用户输入处理常规的焦点移动。这包含当视图删除或隐藏,或者新视图出现时改变焦点。视图经过isFocusable()方法代表它们想获取焦点的意愿。要改变视图是否能够接受焦点,能够调用setFocusable()。在触摸模式中,你能够经过isFocusableInTouchMode()查询一个视图是否容许接受焦点。你能够经过setFocusableInTouchMode()方法来改变它。焦点移动基于一个在给定方向查找最近邻居的算法。少有的状况是,缺省算法可能和开发者的意愿行为不匹配。在这些状况下,你能够经过下面布局文件中的XML属性提供显式的重写:nextFocusDown, nextFocusLeft, nextFocusRight, 和nextFocusUp。为失去焦点的视图增长这些属性之一。定义属性值为拥有焦点的视图的ID。好比:
<LinearLayout
android:orientation="vertical"
... >
<Button android:id="@+id/top"
android:nextFocusUp="@+id/bottom"
... />
<Button android:id="@+id/bottom"
android:nextFocusDown="@+id/top"
... />
</LinearLayout>
一般,在这个竖向布局中,从第一个按钮向上浏览或者从第二个按钮向下都不会移动到其它地方。如今这个顶部按钮已经定义了底部按钮为nextFocusUp (反之亦然),浏览焦点将从上到下和从下到上循环移动。
若是你但愿在用户界面中声明一个可聚焦的视图(一般不是这样),能够在你的布局定义中,为这个视图增长android:focusable XML 属性。把它的值设置成true。你还能够经过android:focusableInTouchMode在触摸模式下声明一个视图为可聚焦。
想请求一个接受焦点的特定视图,调用requestFocus()。
要侦听焦点事件(当一个视图得到或者失去焦点时被通知到),使用onFocusChange(),如上面事件侦听器Event Listeners一章所描述的那样。