安卓 Input Events(输入事件)

在安卓中,有不止一种方法从你的应用截取用户交互事件。在你的用户界面中考虑事件,途径就是从用户界面中的一个指定的view对象中捕获事件。该view提供了这样作的方法。java

在你用来组成你布局的不一样的view类中,你或许注意到了一些公共的回调方法彷佛看起来对UI事件有用。这些方法由安卓的框架调用,当各自的操做在对象中发生时。例如,当一个view (一个按钮)被触摸,在这个对象中的onTouchEvent() 方法就会被调用。然而,为了拦截这个事件,你必须继承该类(button )而且重写该方法(onTouchEvent)。然而,为了处理这样的一个事件而继承每个view对象或许不实际。这就是为何View 类常常包含一组嵌套的调用接口让你能够跟方便的定义(事件处理方法)。这些接口,叫作事件监听者(  event listeners),用来捕获用户与UI的交互。
当你更加日常的为你的用户交互使用事件监听者,当你想继承一个view类,为了建立一个自定义组件,或许可使用一次。或许你想要继承 Button类来让一些东西更加精美。在这样的状况下,你或许须要为你的类定义一个默认事件行为,使用该类的事件处理者( event handlers.).

 事件监听者(Event Listeners)

一个事件监听者是在view类中的一个接口,它包含了一个简单的回调函数。这些方法将会被安卓框架调用,当该view的监听者已经被注册而且经过用户ui 项被触发。
包含了事件监听者接口的都有以下回调方法:
onClick() 来自View.OnClickListener.。当用户触摸该item(触摸模式下),或者使用导航键或轨迹球使焦点汇集在该项上而且按下了适当的"enter"(进入)按键或者在轨迹球上执行了按下操做。
onLongClick()来自  View.OnLongClickListener.。当用户持续触摸item时(触摸模式下),或者使用导航键或轨迹球使焦点汇集在该项上而且持续按着适当的"enter"(进入)按键或者在轨迹球上执行持续按下操做(持续一秒)。
onFocusChange()来自  View.OnFocusChangeListener 当用户使用导航键或者轨迹球导航到或者离开该item 时。
onKey() 来自View.OnKeyListener. 当用户聚焦在了项目上而且按下或松开设备上的按键时
onTouch() 来自View.OnTouchListener.当用户执行一个合格的触摸操做,包括按下,释放或者任何屏幕上的手势动做(在项目的边界内)
onCreateContextMenu() 来自View.OnCreateContextMenuListener. 当上下文菜单开始构建时调用(如持续“长按”的结果)。查看在  Menus开发向导中关于上下文菜单的讨论。
这些方法是它们各自接口的惟一方法。为定义其中的一个方法而且处理你的事件,在你的activity中实现嵌套的接口,或者做为一个匿名类定义它。而后,传递一个你的实例引用给各自的View.set...Listener()方法。 method (例如,调用 setOnClickListener()而且传递一个你实例化的 OnClickListener
下面一个案例展现了如何为一个按钮注册一个on-click监听者。
// 为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 ,做为activity的一部分。这将会避免额外的类加载和对象分配。以下:
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-click监听者。
  • onTouch() - 该方法返回一个布尔类型来代表你是否消耗了该事件。重要的是该事件能够有多个符合触发条件的操做。所以,当按下事件被接受到,若是你返回了false,代表你没有处理该事件而且对这个事件的后续行动不感兴趣。所以,你不会为每个操做都调用该事件,如手势动做,或者最后的抬手动做(up action event)。
请记住,硬件按钮事件老是传递给当前焦点视图。从view的顶层开始向下分发,直到到达适当的地方。若是你的view(或者在view中的子view)得到了焦点,以后你能够经过 dispatchKeyEvent()方法查看到事件的移动。做为一个备选方法来从你的view中捕获按键事件,你还能够在你activity中的 onKeyDown() 和 onKeyUp().内收到各类事件。
而且,当你的应用输入文本时,须要注意的是许多设备只有软件的输入方法。这些方法不须要按键支持,或使用声音输入,手写,等等。即便一个输入方法呈现了一个相似键盘的界面,它一般也不会触发 onKeyDown()这类的事件。你永远不该该建立UI来约束指定按键的按压,除非你想要限制你应用使用设备的硬件盘。特别的,当用户按下返回按钮时,不要依赖于这些方法来确认输入;改成使用像 IME_ACTION_DONE同样的操做来代表该输入方法而且让你的应用程序作出怎样的反应。这可能会以一种有意义的方式来改变它的UI。避免设想一个软件输入方法应该是如何工做的,而且只须要信任它来为你的应用支持已经格式化的文本。
注意:安卓将会首先调用事件处理者,以后调用类中定义的适当的默认处理者。一样的,从这些事件监听者中返回true将会中止事件传播给其它事件监听者,而且阻塞view中的默认事件处理的回调。所以,当你返回true时,肯定你想要终止该事件。

 事件处理者(Event Handlers)

若是你想自定义一个view组件,那么你可能会定义一些回调方法做为默认的事件处理者来使用。在 Custom Components, 这篇文章中,你将会看到一些被用做事件处理的公共回调函数,包括:
这还有其余的一些你须要注意的方法,它们不是view类的一部分,可是能够直接影响你能处理事件的方式。所以,当在你的布局中管理更多复合事件时,考虑这些方法:

 触摸模式(Touch Mode)

当用户使用方向键或轨迹球在用户界面上移动时,给予活动项(如按钮)焦点是必须的,这样用户能够看见什么输入将会被接受。若是该设备有触摸能力,而且用户开始经过触摸来与界面交互,那么并不须要高亮显示项目,或者给指定view 一个焦点。所以,有一个交互模式叫作“触摸模式”(当今的安卓手机主要是该模式,因它没有硬件输入设备)
对于一个可触摸的设备,移动用户触摸了屏幕,设备将会进入触摸模式。今后刻开始,只有当view由于 isFocusableInTouchMode()为true时才可被聚焦,如文本编辑组件。其它view都是可触摸的,如按钮,在触摸时将不会得到焦点;当按下时,他们仅仅的激活他们的on-click 监听者。
任什么时候候,用户点击一个方向键或滑动轨迹球,设备将会退出触摸模式而且找到一个view使其得到焦点。如今,用户能够继续与用户界面交互,不使用触摸屏幕这种方式。
触摸模式状态一直维持在整个系统中(全部Windows和activitys ).为查询当前状态,你能够调用 isInTouchMode() 来查看设备当前是否处于触摸模式。

处理焦点(Handling Focus )

框架将会处理常规响应用户输入时的的焦点移动。这包括当view移除或隐藏时改变焦点,或一个新的view变为可用。view经过 isFocusable()方法来代表他们得到焦点的意愿。改变view是否能得到焦点,调用 setFocusable()。当处于触摸模式,你或许须要经过 isFocusableInTouchMode()查询一个view是否容许聚焦。经过使用 setFocusableInTouchMode()你能够改变它。
焦点的移动是基于一个算法的,它顺着一个给定的方向寻找最近的(view)。少数状况下,默认算法或许不符合开发者的要求。在这种状况下,你能够提供详细的覆盖,经过在布局文件中使用以下xml 属性: nextFocusDown, nextFocusLeftnextFocusRight, 和  nextFocusUp。将其中的一个属性添加到view上。该属性的值是下一个须要获取焦点的view的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设置同样(反之亦然),focus  焦点将会上-下 下-上的循环移动。
若是你想要在你UI中什么一个view是可聚焦的(当它通常状况下不是时),为view添加 android:focusable xml属性,在你的布局文件中声明。设置该值为true。你也能够声明该view的可聚焦性,当在触摸模式时经过 android:focusableInTouchMode.
为请求一个特别的view得到焦点,调用 requestFocus()
为监听焦点事件(当一个view得到或失去焦点时通知),使用 onFocusChange(),在上文 #事件监听者(Event Listeners)中讨论的。
相关文章
相关标签/搜索