先说重要点:
要点一: 截断事件
TV:通过 dispatchKeyEvent 分发事件,返回 false 或者 true 截断本类和子类中的事件分发(onKeyDown无法接收到事件),截取某个按键可返回 false 和 ture 都能截断这个按键向下分发,对上层没有影响。
Phone:和上同理知识分发事件的方法为 dispatchTouchEvent ,由onTouchEvent 处理。
要点二: 消耗事件
KeyEvent 事件处理只有两个地方,一个是 Activity,另一个则是具体的View,返回true 表示事件已消耗,返回 false 则表示事件还在。
当KeyEvent 事件分到具体的子 View 的 dispatchEvent() 里时,View 回去先去看有没有设置 OnKeyListener监听器吗,有则回调 OnKeyListener.onKey()方法来处理事件,当返回 false 或者为空的时候,VIew会通过调用KeyEvent的dispatch()来回调View自己的onKeyDown/Up()来处理事件。
调用使用 OnKeyListener 监听器👇
MButton mButton = new MButton(this);
//如果不设置 OnKeyListener 监听器,事件将由 onKeyDown() 方法处理事件
mButton.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
return false;
}
});
如果不想一个事件执行两次,就返回 true
要点二:
如果你在本类中重写了dispatchKeyEvent 方法,记得返回父类的 dispatchKeyEvent(return super.dispatchKeyEvent),因为你重写的 dispatchKeyEvent 没有事件分发,这会导致下面调用的无法接收到事件,相当于截取了全部事件。
运行流程:
(PhoneWindow$)DecorView的dispatchKeyEvent
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
final int keyCode = event.getKeyCode();
final int action = event.getAction();
final boolean isDown = action == KeyEvent.ACTION_DOWN;
if (isDown && (event.getRepeatCount() == 0)) {
// First handle chording of panel key: if a panel key is held
// but not released, try to execute a shortcut in it.
if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
boolean handled = dispatchKeyShortcutEvent(event);
if (handled) {
return true;
}
}
// If a panel is open, perform a shortcut on it without the
// chorded panel key
if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event