在android上, 有多种方法获取用户与应用程序的交互信息. 当考虑UI内部的事件时, 咱们的方法是抓取特定的与用户交互的View对象产生的事件. android
在你用来组成布局的View对象中,你可能会注意到一些用于处理UI事件的回调函数. 这些方法是被Android框架调用的. 例如,当一个View被按下时, 它的onTouchEvent()方法被调用. 可是,为了截获这个信息,你必须扩展这个类并改写这个方法. 而扩展每一个View对象来处理这样的事件多是不实际的. 这就是为何View类还包含一组你能够更方便定义的嵌套接口. 这些接口被称为监听器, 它们是你用来抓取用户动做的利器. 算法
虽然你可能更加经常使用事件监听器来监听用户动做, 有时候你可能确实但愿经过扩展一个View类的方法来作这一点. 可能你但愿扩展Button类来作一些巧妙的事情. 在这个状况下, 你可以使用时间处理器来定义该类的默认的事件行为. 框架
一个事件监听器是View类的一个接口. 该接口包含的方法会在View注册的事件监听器被触发时被Android调用. 函数
在事件监听器中有下列方法: 布局
这些方法只是它们对应接口的惟一方法. 为了定义这些方法, 能够在你的Activity中实现这个接口, 也可使用一个匿名类. 而后, 将实现该接口实例传给对应的View.set...Listener方法. ui
以OnClickListener为例: this
// 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);
...
} spa
你可能以为将OnClickListener 实现为activity的一部分会更加方便. 这能够避免额外的类. 例如: .net
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
}
...
} component
注意 onClick() 没有返回值, 但有些事件监听器必须有一个布尔返回值. 下面是一些缘由:
键事件永远会被发送到当前得到焦点的View. 它们是从View层次的顶端开始分派, 而后向下直到合适的目的地. 若是你的View如今拥有焦点, 那么你能够从dispatchKeyEvent()方法中看到事件的分派过程. 除了使用veiw以外,你也可使用你的Activity的onKeyDown()和onKeyUp()方法来获取全部的时间.
注意: Android将首先调用事件处理器, 而后调用合适的默认处理器. 所以, 从这些事件监听器中返回true将使其它监听器和默认处理器失效. 所以在你返回true时要当心.
若是你从View来建立一个自定义的component,那么你能够定义一些默认事件处理器。在 Building Custom Components文档中,你将看到这些回调函数:
有一些不属于View,可是也能直接影响到事件处理的方法:
但一个用户使用方向键或者轨迹球来在UI上移动时, 须要让可动做的UI元素得到焦点, 这样用户能够看到什么东西将得到他们的输入。若是设备具备触摸能力,用户使用触摸的方式来交互,那么就没有必要给一个元素焦点。所以,有一种交互的模式叫作“触摸模式”。
对于一个可触摸的设备,一旦用户触摸了屏幕,设备就进入触摸模式。在这之后,只有isFocusableInTouchMode()为真的View是能够得到焦点的, 例如文本框。其它的View能够触摸,例如按钮,在触摸的时候不会得到焦点。它们只是启动对应的on-click监听器。在用户按下方向键或者旋转轨迹球时,设备将退出触摸模式,并寻找一个view并使他得到焦点。如今,用户能够不触摸屏幕来交互。
触摸模式状态在整个系统中被维护。你可使用isInTouchMode()来查询当前状态。
android框架会根据用户输入来处理焦点的移动。这包含了在View被移除或隐藏或再次出现时改变焦点。View使用isFocusable()和setFocusable()方法来表示和设置它们可否得到焦点。在触摸模式下,可使用isFocusableInTouchMode()和setFocusableInTouchMode().。
焦点移动时基于在某方向上最近距离元素的算法。在不多见的情形下,默认的算法可能和开发者的想法不同。在这种状况下,你能够提供一个算法,修改如下几个xml属性:nextFocusDown, nextFocusLeft, nextFocusRight和 nextFocusUp. 例如:
<LinearLayout
android:orientation="vertical"
... >
<Button android:id="@+id/top"
android:nextFocusUp="@+id/bottom"
... />
<Button android:id="@+id/bottom"
android:nextFocusDown="@+id/top"
... />
</LinearLayout>
通常来讲,在这个竖直向下的布局中,从第一个按钮向上不会走到哪里。加入上述代码后,从第一个按钮向上会使第二个按钮获取焦点。
若是你但愿将一个View设为可获取焦点,那么加入xml属性android:focusable="true" 和android:focusableInTouchMode = "true".
但愿一个View得到焦点时,调用requestFocus().
要监听焦点事件,使用onFocusChange()。