简体   繁体   English

拦截Fragment中的ActionBar Home按钮

[英]Intercepting ActionBar Home button in Fragment

I can successfully intercept the ActionBar home button from my NavigationDrawerFragment , which is added to my MainActivity , like so: 我可以成功拦截我的NavigationDrawerFragmentActionBar主页按钮,它被添加到我的MainActivity ,如下所示:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (!loggedIn() && item.getItemId() == android.R.id.home) {
        login();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

However, in my ComposeActivity with ComposeFragment this does not work. 但是,在我的ComposeActivity with ComposeFragment这不起作用。 onOptionsItemSelected is not called on the fragment. 不会在片段上调用onOptionsItemSelected

I have debugged the code and the issue seems to come down to the design of the Android support library. 我调试了代码,问题似乎归结为Android支持库的设计。 It appears that both FragmentActivity and Activity have their own references to a FragmentManager . 似乎FragmentActivityActivity都有自己对FragmentManager的引用。

FragmentActivity first checks if Activity can handle the event before checking any of its fragments, which is consistent with the docs : FragmentActivity首先检查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;
    }
}

As seen in the snippet below, Activity handles the home button as a last resort, after checking if either it or any of its fragments can handle the event. 如下面的代码片段所示,在检查主页按钮或其任何片段是否可以处理事件之后, Activity会将主页按钮作为最后的手段处理。 But this reference to FragmentManager does not contain any fragments, the fragments are in the FragmentActivity 's manager. 但是这个对FragmentManager引用不包含任何片段,片段在FragmentActivity的管理器中。 Therefore the event will get swallowed by the Activity class if ActionBar.DISPLAY_HOME_AS_UP is set. 因此,如果设置了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;
    /* ... */
}

It turns out that my MainActivity , being the root of my application and using a navigation drawer, did not have this flag set and so did not swallow the event. 事实证明,我的MainActivity是我的应用程序的根,并使用导航抽屉,没有设置此标志,因此不会吞下事件。 But my ComposeActivity has a parent activity and I need this flag to be set so it is not possible to intercept the action bar home button. 但我的ComposeActivity有一个父活动,我需要设置此标志,因此无法拦截操作栏主页按钮。

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. 总结问题:无法从设置了DISPLAY_HOME_AS_UP的活动中的片段拦截操作栏主页按钮上的单击。

So is this a bug in the support library? 这是支持库中的一个错误吗? It doesn't look like it would occur if I targeted a later Android version and dropped the support library. 如果我针对以后的Android版本并删除支持库,它看起来不会发生。

Regarding workarounds for this, I guess I could: 关于这方面的解决方法,我想我可以:

  • In my ComposeActivity 's onOptionsItemSelected I can manually pass the event to each of my fragments, seeing if they can handle it before calling super. 在我的ComposeActivityonOptionsItemSelected我可以手动将事件传递给我的每个片段,看看他们是否可以在调用super之前处理它。
  • Override onMenuItemSelected in ComposeActivity and do the same thing. 覆盖ComposeActivity中的ComposeActivity并执行相同的操作。

Anybody encountered this before? 以前有人遇到过这个吗? Should I log a bug somewhere? 我应该在某处记录错误吗? Any other ideas of ways around this issue? 关于这个问题的任何其他想法?

As you have explained, due to the flow of how the event is dispatched in Android, it seems the child fragment will never intercept the event because it's consumed by the Activity first. 正如您所解释的,由于在Android中调度事件的流程,似乎子片段永远不会拦截事件,因为它首先被Activity使用。

It's a workaround, but what I'm doing is passing the event to child fragments before is handled in the Activity. 这是一种解决方法,但我正在做的是将事件传递给子片段,然后在Activity中处理。

In the 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM