拦截Fragment中的ActionBar Home按钮

时间:2014-02-21 15:28:11

标签: android android-fragments android-actionbar android-fragmentactivity android-appcompat

我可以成功截取ActionBar的{​​{1}}主页按钮,该按钮会添加到我的NavigationDrawerFragment,如下所示:

MainActivity

但是,在我的@Override public boolean onOptionsItemSelected(MenuItem item) { if (!loggedIn() && item.getItemId() == android.R.id.home) { login(); return true; } return super.onOptionsItemSelected(item); } ComposeActivity中,这不起作用。没有在片段上调用ComposeFragment

我调试了代码,问题似乎归结为Android支持库的设计。似乎onOptionsItemSelectedFragmentActivity都有自己对Activity的引用。

FragmentManager首先检查FragmentActivity是否可以在检查任何碎片之前处理该事件,这与docs一致:

Activity

如下面的代码段所示,/** * 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; } } 在检查主页按钮或其任何片段是否可以处理该事件后,作为最后的手段处理主页按钮。但是对Activity的引用不包含任何片段,片段在FragmentManager的管理器中。因此,如果设置了FragmentActivity,则Activity类会吞下该事件。

ActionBar.DISPLAY_HOME_AS_UP

事实证明,作为我的应用程序的根目录并使用导航抽屉的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有父活动,我需要设置此标志,因此无法拦截操作栏主页按钮。

  

总结问题:无法拦截点击   操作栏主页按钮来自活动中的片段与   DISPLAY_HOME_AS_UP设置。

这是支持库中的一个错误吗?如果我针对以后的Android版本并删除了支持库,它看起来不会发生。

关于这方面的解决方法,我想我可以:

  • 在我ComposeActivity的{​​{1}}我可以手动将事件传递给我的每个片段,看看他们是否可以在调用super之前处理它。
  • 覆盖ComposeActivity中的onMenuItemSelected并执行相同的操作。

之前有人遇到过这个吗?我应该在某处记录错误吗?关于这个问题的任何其他想法?

1 个答案:

答案 0 :(得分:4)

正如您所解释的,由于在Android中调度事件的流程,似乎子片段永远不会拦截事件,因为它首先被Activity占用。

这是一种解决方法,但我正在做的是将事件传递给子片段,然后再在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);
}