Android 片段中的 onCreateOptionsMenu() 不替换 ActionBar 菜单

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23314472/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:00:37  来源:igfitidea点击:

onCreateOptionsMenu() in fragment not replacing ActionBar menus

androidandroid-fragmentsandroid-actionbarnavigation-drawerandroid-menu

提问by e-nature

I'm using the NavigationDrawer in my app and replace the fragment when clicking a item in the drawer. My problem I have is that the menu items in the ActionBar are not updated when I change the fragment.

我在我的应用程序中使用 NavigationDrawer 并在单击抽屉中的项目时替换片段。我的问题是,当我更改片段时,ActionBar 中的菜单项没有更新。

I've followed this tutorial https://www.grokkingandroid.com/adding-action-items-from-within-fragments/closely but it's still not working in my app.

我已经密切关注本教程https://www.grokkingandroid.com/adding-action-items-from-within-fragments/但它仍然无法在我的应用程序中运行。

Adding some code snippets of the parent activity and one of the Fragments here. What I need is to display the other menu items of the contact form fragment (R.menu.contactform_send_menu) when the initial fragment gets replaced with ContactFormFragment.java.

在此处添加父活动的一些代码片段和其中一个片段。我需要的是在初始片段被 ContactFormFragment.java 替换时显示联系表单片段 (R.menu.contactform_send_menu) 的其他菜单项。

public class MainActivity extends FragmentActivity implements ActionBar.OnNavigationListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle(R.string.app_name);

        // Set up the action bar to show a dropdown list.
        ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
        actionBar.setDisplayShowTitleEnabled(true);
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setHomeButtonEnabled(true);

        createNavigationDrawer(savedInstanceState);
    }

    private final int DRAWER_MAIN = 0;
    private final int DRAWER_CONTACT = 5;

    // update the main content by replacing fragments
    private void selectItem(int position) {
        Fragment fragment = null;
        Bundle args = new Bundle();
        boolean isFragment = false;

        switch (position) {
        case DRAWER_MAIN:
            fragment = new WelcomeSectionFragment();
            args.putString(WelcomeSectionFragment.ITEM_NAME, dataList.get(position).getItemName());
            args.putInt(WelcomeSectionFragment.IMAGE_RESOURCE_ID, dataList.get(position).getImgResID());
            getActionBar().setTitle(R.string.app_name);
            isFragment = true;
            break;
        case DRAWER_CONTACT:
            fragment = new ContactFormFragment();
            args.putString(ContactFormFragment.ITEM_NAME, dataList.get(position).getItemName());
            args.putInt(ContactFormFragment.IMAGE_RESOURCE_ID, dataList.get(position).getImgResID());
            getActionBar().setTitle(R.string.contactform_title);
            isFragment = true;
            break;
        default:
            break;
        }

        if (isFragment) {
            fragment.setArguments(args);
            FragmentManager frgManager = getFragmentManager();
            frgManager.beginTransaction().replace(R.id.content_frame, fragment).commit();

            mDrawerList.setItemChecked(position, true);
            setTitle(dataList.get(position).getItemName());
            mDrawerLayout.closeDrawer(mDrawerList);
        }
    }

}

and the fragment:

和片段:

public class ContactFormFragment extends Fragment {

    public ContactFormFragment() {

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ca = getActivity();
        Reachability.registerReachability(ca.getApplicationContext());

        settings = ca.getSharedPreferences(Konstanten.PREFERENCES_FILE, 0);
        member = new Gson().fromJson(settings.getString(Konstanten.MEMBER_OBJECT, null), Member.class);

        latoFontLight = Tools.getFont(ca.getAssets(), "Lato-Light.ttf");
        latoFontBold = Tools.getFont(ca.getAssets(), "Lato-Bold.ttf");

        // Update action bar menu items?
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // Do something that differs the Activity's menu here
        super.onCreateOptionsMenu(menu, inflater);

        menu.clear();

        if (Build.VERSION.SDK_INT >= 11) {
            // selectMenu(menu);
            inflater.inflate(R.menu.contactform_send_menu, menu);
        }
    }
}

When debugging I can see that setHasOptionsMenu(true); gets called in onCreate() and I also get into the onCreateOptionsMenu() of ContactFormFragment.java. I just don't understand why the action bar keeps its initial menu items and doesn't replace them. What am I missing?

调试时我可以看到 setHasOptionsMenu(true); 在 onCreate() 中被调用,我也进入了 ContactFormFragment.java 的 onCreateOptionsMenu()。我只是不明白为什么操作栏会保留其初始菜单项而不替换它们。我错过了什么?

Thanks for any help.

谢谢你的帮助。

回答by tricknology

Try putting setHasOptionsMenu(true);inside the onCreateView()of your ChildFragment.javaI don't see one in the code you posted.

尝试把setHasOptionsMenu(true);里面的onCreateView()你的ChildFragment.java我没有看到一个在你发布的代码。

回答by e-nature

I got it working! The problem I had was that I added a custom drop down menu to the main fragment. So each time I change the fragment through the drawer navigation I manually have to remove that drop down menu and when returning to the main fragment I will re-add it.

我让它工作了!我遇到的问题是我向主片段添加了一个自定义下拉菜单。因此,每次我通过抽屉导航更改片段时,我都必须手动删除该下拉菜单,当返回主片段时,我将重新添加它。

Here is what I did:

这是我所做的:

In the parent activity:

在父活动中:

MainActivity.java:

主活动.java:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.signin_menu, menu);

    getMenuInflater().inflate(R.menu.clear_search_history_menu, menu);

    // Search
    // Associate searchable configuration with the SearchView
    getMenuInflater().inflate(R.menu.search_menu, menu);
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView();
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));

    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    menu.clear();
    getMenuInflater().inflate(R.menu.signin_menu, menu);
    getMenuInflater().inflate(R.menu.clear_search_history_menu, menu);

    // Search
    // Associate searchable configuration with the SearchView
    getMenuInflater().inflate(R.menu.search_menu, menu);
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView();
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));

    // If the nav drawer is open, hide action items related to the content
    // view
    boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
    menu.findItem(R.id.search).setVisible(!drawerOpen);

    return super.onPrepareOptionsMenu(menu);
}

// This is the selection of the drawer (stripped some code to keep it short)
private void selectItem(int position) {
    Fragment fragment = null;
    Bundle args = new Bundle();
    boolean isFragment = false;

    ActionBar actionBar = getActionBar();

    switch (position) {
    case DRAWER_MAIN:
        fragment = new WelcomeSectionFragment();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
        actionBar.setListNavigationCallbacks(new GameSystemsAdapter(getActionBarThemedContextCompat(), allSystemsPlusEmpty), this);
        actionBar.setTitle(R.string.app_name);
        isFragment = true;
        break;
    case DRAWER_FAVORITES:
        fragment = new FavoritesMainFragment();
        // Remove System-Select Drop-Down
        actionBar.setListNavigationCallbacks(null, null);
        actionBar.setNavigationMode(0);
        actionBar.setTitle(R.string.favorites);
        isFragment = true;
        break;
    case DRAWER_TOP_MEMBERS:
        fragment = new TopMembersFragment();            
        // Remove System-Select Drop-Down
        actionBar.setListNavigationCallbacks(null, null);
        actionBar.setNavigationMode(0);
        actionBar.setTitle(R.string.top_members_top_helping);
        isFragment = true;
        break;
    default:
        break;
    }

    if (isFragment) {
        fragment.setArguments(args);
        FragmentManager frgManager = getFragmentManager();
        frgManager.beginTransaction().replace(R.id.content_frame, fragment).commit();

        mDrawerList.setItemChecked(position, true);
        setTitle(dataList.get(position).getItemName());
        mDrawerLayout.closeDrawer(mDrawerList);
    }

}

and here the part of the fragment(s):

这里是片段的一部分:

ChildFragment.java

子片段.java

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);

    if (Build.VERSION.SDK_INT >= 11) {
        selectMenu(menu);
    }
}

@Override
public void onPrepareOptionsMenu(Menu menu) {
    selectMenu(menu);
}

private void selectMenu(Menu menu) {
    parentActivity.getMenuInflater().inflate(R.menu.contactform_send_menu, menu);
}

If there are any better solutions I'm very interested in your ideas.

如果有更好的解决方案,我对您的想法很感兴趣。

回答by Wolfram Rittmeyer

There are two cases to consider:

有两种情况需要考虑:

  1. You want all action items to come from within fragments exclusively.
  2. You also have action items that should be global and are defined within the activity.
  1. 您希望所有操作项都来自片段内。
  2. 您还有应该是全局的并在活动中定义的操作项。

Let's begin with option 2 since it's the most common case.

让我们从选项 2 开始,因为它是最常见的情况。

If you have fragment specific items and global items at the same time, you do not want to use onCreateOptionsMenu()within the fragment. The reason is that it would look weird - even if it worked. The fragment actions would be added right after creating the fragment, while the global items would be added after the drawer has closed (by default). I think no user would like that.

如果您同时拥有片段特定项和全局项,则不想onCreateOptionsMenu()在片段内使用。原因是它看起来很奇怪——即使它有效。片段动作将在创建片段后立即添加,而全局项目将在抽屉关闭后添加(默认情况下)。我认为没有用户会喜欢那样。

What you could do to still let the fragment decide which items to display is to create an interface for all fragments to implement. This could define one method which would return the menu id for the menu to inflate or -1if no menu should be inflated.

您仍然可以让片段决定显示哪些项目是为所有片段创建一个接口来实现。这可以定义一种方法,该方法将返回菜单 id 以供膨胀或-1不应该膨胀菜单。

In case of option 1, I can only assume that you clear()the menu within the Activity's onCreateOptionsMenu(). Otherwise it wouldn't delete the fragments' menu entries. So just get rid of the clear()and all should be fine.

在选项 1 的情况下,我只能假设您clear()在 Activity 的onCreateOptionsMenu(). 否则它不会删除片段的菜单条目。所以只要摆脱它clear(),一切都应该没问题。