在片段截取动作条Home键片段、动作、Home

2023-09-13 23:38:53 作者:高傲得不顧一屑

我可以成功拦截从动作条 home键我的 NavigationDrawerFragment ,这是添加到我的 MainActivity ,像这样:

I can successfully intercept the ActionBar home button from my NavigationDrawerFragment, which is added to my MainActivity, like so:

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

不过,在我的 ComposeActivity ComposeFragment 这不起作用。 onOptionsItemSelected 不叫段上。

However, in my ComposeActivity with ComposeFragment this does not work. onOptionsItemSelected is not called on the fragment.

我已经调试了code和问题似乎回落到Android支持库的设计。看来,无论 FragmentActivity 活动有自己提述 FragmentManager

I have debugged the code and the issue seems to come down to the design of the Android support library. It appears that both FragmentActivity and Activity have their own references to a FragmentManager.

FragmentActivity 首先检查是否活动检查它的任何片段,这与一致之前,能够处理该事件文档:

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

正如下面的代码片段,活动处理home键作为最后的手段,检查,如果IT或任何其片段可以处理该事件之后。但这种参照 FragmentManager 不包含任何片段,这些片段都在 FragmentActivity 的经理。因此,该事件将获得由活动类,如果 ActionBar.DISPLAY_HOME_AS_UP 设置吞噬。

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. But this reference to FragmentManager does not contain any fragments, the fragments are in the FragmentActivity's manager. Therefore the event will get swallowed by the Activity class if ActionBar.DISPLAY_HOME_AS_UP is set.

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 有一个父活动,我需要这个标志被设置,因此无法拦截行动吧HOME键。

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. 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.

要总结的问题:这是不可能拦截的点击   从片段与一个活动操作栏主页按钮   DISPLAY_HOME_AS_UP集。

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版本和丢弃的支持库会发生。

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.

至于解决方法,我想我可以:

Regarding workarounds for this, I guess I could:

在我的 ComposeActivity onOptionsItemSelected 我可以,如果他们手工传递事件给我的每个片段,看到调用super之前可以处理它。 覆盖onMenuItemSelected在 ComposeActivity 和做同样的事情。 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. Override onMenuItemSelected in ComposeActivity and do the same thing.

任何人都遇到过吗?我应该记录一个错误的地方?办法解决此问题的任何其他的想法?

Anybody encountered this before? Should I log a bug somewhere? Any other ideas of ways around this issue?

推荐答案

正如您所解释,由于该事件是如何分派在Android上的流动,似乎孩子片段永远不会拦截事件,因为它消耗的活动第一。

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.

这是一个解决办法,但我在做什么是传递事件之前,在活动进行处理。子片段

It's a workaround, but what I'm doing is passing the event to child fragments before is handled 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);
}