在Activity中的OnOptionsItemSelected方法会在Fragment中的OnOptionsItemSelected方法之前被调用。还有其他可能的方式吗?

13

我有一个活动可以包含几个片段。每个片段都可以在ActionBar中拥有自己的菜单项。到目前为止,这很好,每个项目都是可点击的并执行所需的操作。

我的问题如下。在MainActivity中,我声明了以下行来拦截对ActionBar的HomeIcon的调用:

public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            clearBackStack();
                    setHomeFragment();
            return true;
        default:
            return super.onOptionsItemSelected(item);

        }
    }

我将其声明在Activity中,因为我希望每个Fragment都调用它,这样我就不必在每个Fragment中捕获android.R.id.home的情况。

在一个Fragment中,我使用setDisplayHomeAsUpEnabled(true),以便在ActionBar图标左侧获得小箭头。当在此片段中单击HomeIcon时,我不想设置HomeFragment,而是要设置最后显示的Fragment。因此,我在Fragment中有一个onOptionsItemSelected方法:

@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {

    switch (menuItem.getItemId()) {
    case android.R.id.home:
        setLastFragment();
               return true;
    ...
然而,这并没有按照我所期望的方式起作用。Activity 的 onOptionsItemSelected 方法首先被调用,捕获 MenuItem 并重定向到 HomeFragment。我可以在其他片段中声明的其他菜单项中检查相同的行为。Activity 首先被调用,不会捕获 MenuItem(默认情况),然后重定向到 super.onOptionsItemSelected(item)。
因此,似乎这是 Android 处理菜单点击的方式。首先是 Activity,然后是 Fragment。有没有办法改变这个?我不想在每个片段中都放置 android.R.id.home-case 并在那里处理它。有没有更好的方法来做这件事?
4个回答

13

我刚遇到了这个问题,我使用以下代码使它工作。

在活动的onOptionsItemSelected函数中添加:

if (id == android.R.id.home){
        Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
        if(null != currentFragment && currentFragment.onOptionsItemSelected(item)){
            return true;
        }
    }

在片段的onOptionsItemSelected方法中,您处理相应的事情。这样,如果片段对菜单项有任何事情要做,它将执行并返回true以停止任何其他进程。如果该片段与此项目无关,则会返回false或调用super.onOptionsItemSelected方法,后者可能最终返回false以让其他人处理它。


5
根据开发者文档,"Return false to allow normal menu processing to proceed, true to consume it here."。因此,在Activity的onOptionsItemSelected()方法中,默认返回'false',这样事件如果没有被捕获,就会传递到Fragment的实现中。

11
这不是MrHill所要求的!我也遇到了同样的问题。通常活动处理“主页UP”按钮。有时,当某个片段当前处于活动状态时,我们希望在按下“主页UP”按钮时执行特殊操作。在Activity onOptionsItemSelected上返回false可以防止活动处理该情况。 - Francesco

1
你可以像@Surely写的那样做,这是一个很好的想法,但在这种情况下,你将在不知道哪个片段的情况下调用onOptionsItemSelected方法,并且你应该在所有的片段中重写onOptionsItemSelected方法。
如果你只想为特定的片段调用此方法,你应该通过标签找到它们,这是添加它们时使用的标签:
case android.R.id.home:
            Fragment frag = getSupportFragmentManager()
                    .findFragmentByTag(FRAGMENT_TAG);

            if(frag != null && frag.isVisible() && frag.onOptionsItemSelected(item)) {
                return true;

标签的指定方式如下:

fragmentManager.beginTransaction()
            .add(containerId, fragment, FRAGMENT_TAG)

1

我不确定这是否可能。在此处提供的官方文档中:

http://developer.android.com/guide/topics/ui/actionbar.html#ActionEvents

有一个注释,内容如下:

[...] 然而,活动(Activity)有机会首先处理事件,因此系统在调用片段(Fragment)的相同回调之前,首先调用活动(Activity)上的onOptionsItemSelected()方法。


1
只要在Fragment的生命周期早期,例如在onCreateView()中调用setHasOptionsMenu(true),就可以实现这一点。 - Tash Pemhiwa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接