我可以从我的 NavigationDrawerFragment
中成功拦截 ActionBar
主页按钮,它被添加到我的 MainActivity
中,如下所示:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!loggedIn() && item.getItemId() == android.R.id.home) {
login();
return true;
}
return super.onOptionsItemSelected(item);
}
但是,在我的带有 ComposeFragment
的 ComposeActivity
中,这不起作用。 onOptionsItemSelected
未在 fragment 上调用。
我已经调试了代码,问题似乎归结为 Android 支持库的设计。看来 FragmentActivity
和 Activity
都有自己对 FragmentManager
的引用。
FragmentActivity
首先检查 Activity
是否可以处理事件,然后再检查其任何 fragment ,这与 docs 一致:
/**
* Dispatch context and options menu to fragments.
*/
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (super.onMenuItemSelected(featureId, item)) {
return true;
}
switch (featureId) {
case Window.FEATURE_OPTIONS_PANEL:
return mFragments.dispatchOptionsItemSelected(item);
case Window.FEATURE_CONTEXT_MENU:
return mFragments.dispatchContextItemSelected(item);
default:
return false;
}
}
如以下代码 fragment 所示,Activity
在检查它或其任何 fragment 是否可以处理该事件后,将处理主页按钮作为最后的手段。但是这个对 FragmentManager
的引用不包含任何 fragment , fragment 在 FragmentActivity
的管理器中。因此,如果设置了 ActionBar.DISPLAY_HOME_AS_UP
,该事件将被 Activity
类吞没。
public boolean onMenuItemSelected(int featureId, MenuItem item) {
/* ... */
if (onOptionsItemSelected(item)) {
return true;
}
if (mFragments.dispatchOptionsItemSelected(item)) {
return true;
}
if (item.getItemId() == android.R.id.home && mActionBar != null &&
(mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
if (mParent == null) {
return onNavigateUp();
} else {
return mParent.onNavigateUpFromChild(this);
}
}
return false;
/* ... */
}
事实证明,我的 MainActivity
作为我的应用程序的根并使用抽屉导航,没有设置此标志,因此没有吞下该事件。但是我的 ComposeActivity
有一个父 Activity ,我需要设置这个标志,这样就不可能拦截操作栏主页按钮。
To sum up the issue: It is not possible to intercept a click on the Action Bar home button from a fragment in an activity with with DISPLAY_HOME_AS_UP set.
那么这是支持库中的错误吗?如果我针对更高版本的 Android 并删除支持库,它看起来不会发生。
关于解决方法,我想我可以:
- 在我的
ComposeActivity
的onOptionsItemSelected
中,我可以手动将事件传递到我的每个 fragment ,看看它们是否可以在调用 super 之前处理它。 - 重写
ComposeActivity
中的 onMenuItemSelected 并做同样的事情。
有人遇到过这个吗?我应该在某处记录错误吗?关于解决此问题的任何其他想法?
最佳答案
正如您所解释的,由于事件在 Android 中的调度流程,子 fragment 似乎永远不会拦截事件,因为它首先被 Activity 使用。
这是一种变通方法,但我正在做的是在 Activity 处理之前将事件传递给子 fragment 。
在 Activity 中:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Due to a problem of not being able to intercept android.R.id.home in fragments,
// we start passing the event to the currently displayed fragment.
// REF: http://stackoverflow.com/questions/21938419/intercepting-actionbar-home-button-in-fragment
final Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.XXXXXXX);
if (currentFragment != null && currentFragment.onOptionsItemSelected(item)) {
return true;
}
switch (item.getItemId()) {
case XXX:
...
return true;
case YYY:
...
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}
关于android - 拦截Fragment中的ActionBar Home按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21938419/