Android强行进阶—按键事件&焦点事件攻略

}
//一些保护措施
//在View层次结构不消费事件,判断窗口是否有输入事件或者已经停止和销毁
if (shouldDropInputEvent(q)) {
return FINISH_NOT_HANDLED;
}

if (mUnhandledKeyManager.dispatch(mView, event)) {
return FINISH_HANDLED;
}
//用来保存焦点事件方向
int groupNavigationDirection = 0;
//处理tab键,判断焦点的方向
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
//metaStateHasModifiers()根据指定的meta状态按下特定时返回true
//如果按的是组合键则返回false
if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_META_ON)) {
groupNavigationDirection = View.FOCUS_FORWARD;
} else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),
KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON)) {
groupNavigationDirection = View.FOCUS_BACKWARD;
}
}

// If a modifier is held, try to interpret the key as a shortcut.
if (event.getAction() == KeyEvent.ACTION_DOWN
&& !KeyEvent.metaStateHasNoModifiers(event.getMetaState())
&& event.getRepeatCount() == 0
&& !KeyEvent.isModifierKey(event.getKeyCode())
&& groupNavigationDirection == 0) {
if (mView.dispatchKeyShortcutEvent(event)) {
return FINISH_HANDLED;
}
if (shouldDropInputEvent(q)) {
return FINISH_NOT_HANDLED;
}
}

// 应用 fallback 策略
// 具体实现见PhoneFallbackEventHandler中dispatchKeyEvent()方法
// 主要是对媒体键,音量键,通话键等做处理
if (mFallbackEventHandler.dispatchKeyEvent(event)) {
return FINISH_HANDLED;
}
if (shouldDropInputEvent(q)) {
return FINISH_NOT_HANDLED;
}

//View层次结构不处理KeyEvent,那么变成了寻找焦点的过程
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (groupNavigationDirection != 0) {
if (performKeyboardGroupNavigation(groupNavigationDirection)) {
return FINISH_HANDLED;
}
} else {
if (performFocusNavigation(event)) {
return FINISH_HANDLED;
}
}
}
return FORWARD;
}
复制代码

processKeyEvent()函数中,我们主要关心按键事件在View层次结构的分发(mView.dispatchKeyEvent(event))和函数最后自动处理焦点事件两大过程。

KeyEvent在View层次结构的分发

在上一小节中,会调用ViewPostImeInputStage对象内processKeyEvent()函数,使KeyEvent在View的层次结构中分发。 其中mView是DecorView对象,并调用其dispatchKeyEvent()函数。

// DecorView
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
final int keyCode = event.getKeyCode();
final int action = event.getAction();
final boolean isDown = action == KeyEvent.ACTION_DOWN;
//第一次按下,处理panel快捷键
if (isDown && (event.getRepeatCount() == 0)) {
if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
boolean handled = dispatchKeyShortcutEvent(event);
if (handled) {
return true;
}
}

if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
return true;
}
}
}
//重点分析的地方
//当Window未destoryed且callback非null,
//交给Window对象的callback处理
if (!mWindow.isDestroyed()) {
final Window.Callback cb = mWindow.getCallback();
// mFeatureId < 0 表示是application的DecorView,比如Activity、Dialog
final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)//事件派发给callback对象
: super.dispatchKeyEvent(event);//派发给ViewGroup(View层次结构)
if (handled) {
return true;
}
}
//只有View不消费事件,才将事件交给Window对象
return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
: mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
}
复制代码

我们知道Activity和Dialog都是实现了CallBack接口,因此这里先分析KeyEvent在Activity中分发,再看看View层次结构分发。因为PhoneWindow是Window的唯一实现类,所以最后需要看看PhoneWindow的onKeyDown()onKeyUp()函数。

//Activity.java

public boolean dispatchKeyEvent(KeyEvent event) {
onUserInteraction();

final int keyCode = event.getKeyCode();
//处理KEYCODE_MENU键,Activity有ActionBar且消费该按键
if (keyCode == KeyEvent.KEYCODE_MENU &&
mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
return true;
}

Window win = getWindow();
//这里KeyEvent交给Window对象分发
if (win.superDispatchKeyEvent(event)) {
return true;
}
View decor = mDecor;
if (decor == null) decor = win.getDecorView();

//Window对象win不消费Key事件,则将事件交给KeyEvent自身
return event.dispatch(this, decor != null
? decor.getKeyDispatcherState() : null, this);
}
复制代码

通过后面的学习,可以KeyEvent在Window对象的分发其实是在View的层次结构分发。在View层次结构中不消费KeyEvent事件,那么会交给KeyEvent自身处理,会调用Activity相关方法,如onKeyDown()

我们知道PhoneWindow是Window的具体实现

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值