Android强行进阶—按键事件&焦点事件攻略,androidsdk开发封装

if (mPrimaryActionMode != null) {
if (action == KeyEvent.ACTION_UP) {
mPrimaryActionMode.finish();
}
return true;
}
}
//在View层次结构进行派发
if (super.dispatchKeyEvent(event)) {
return true;
}

//如果View层次结构不消费,且ViewRootImpl不为空,
//则在ViewRootImpl对象处理
return (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);
}
复制代码

View层次结构大概如下图所示,这里先看看KeyEvent在View层次结构的分发。

我们知道,DecorView继承至FrameLayout,而FrameLayout是ViewGroup的子类。 ViewGroup类的dispatchKeyEvent()函数如下:

//ViewGroup

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onKeyEvent(event, 1);
}
//ViewGroup是focused或者设置了具体的大小,则交给它实现
if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
== (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
//在View中的实现
if (super.dispatchKeyEvent(event)) {
return true;
}
} else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
== PFLAG_HAS_BOUNDS) {
//mFocused表示当前ViewGroup中获得焦点或者包含焦点的View(子View)
if (mFocused.dispatchKeyEvent(event)) {
return true;
}
}

if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
}
return false;
}
复制代码

从上面代码可以看出,子View想要获得焦点,处理KeyEvent,需要设置focusable属性为true。KeyEvent会优先派发给符合条件的ViewGroup处理,而不是子View。mFocused.dispatchKeyEvent(event)中的dispatchKeyEvent()可能会迭代调用,因为子View也可能是ViewGroup。

这里看看View中事件分发。

//View

/**

  • Dispatch a key event to the next view on the focus path. This path runs
  • from the top of the view tree down to the currently focused view. If this
  • view has focus, it will dispatch to itself. Otherwise it will dispatch
  • the next node down the focus path. This method also fires any key
  • listeners.
  • @param event The key event to be dispatched.
  • @return True if the event was handled, false otherwise.
    */
    public boolean dispatchKeyEvent(KeyEvent event) {
    if (mInputEventConsistencyVerifier != null) {
    mInputEventConsistencyVerifier.onKeyEvent(event, 0);
    }

// Give any attached key listener a first crack at the event.
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
//如果我们给View设置了OnKeyListener且View是ENABLED状态,
//则会回调我们的了OnKeyListener
if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLE
D_MASK) == ENABLED
&& li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
return true;
}
//调用KeyEvent.dispatch方法,并将view对象本身作为参数传递进去,view的各种callback方法在这里被触发
if (event.dispatch(this, mAttachInfo != null
? mAttachInfo.mKeyDispatchState : null, this)) {
return true;
}

if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
return false;
}
复制代码

ViewGroup和View的dispatchKeyEvent()就构成了View层次结构的KeyEvent分发,且总是从树根DecorView开始到具体的View。注意到此处在View不消费KeyEvent会调用KeyEvent.dispatch方法,在Activity也会调用该方法。

//KeyEvent
public final boolean dispatch(Callback receiver, DispatcherState state,
Object target) {
switch (mAction) {
case ACTION_DOWN: {
mFlags &= ~FLAG_START_TRACKING;
//回调Callback对象receiver的onKeyDown函数,上文知道Activity和View都实现Callback
boolean res = receiver.onKeyDown(mKeyCode, this);
if (state != null) {//通常成立
if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {//判断是否轨迹事件
state.startTracking(this, target);
} else if (isLongPress() && state.isTracking(this)) {
try {
//处理长按事件
i

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值