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

时间:2014-04-26 17:41:53

标签: android android-fragments android-actionbar navigation-drawer android-menu

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

我已经仔细阅读了本教程https://www.grokkingandroid.com/adding-action-items-from-within-fragments/,但它仍无法在我的应用中使用。

在此处添加父活动和其中一个片段的一些代码片段。 我需要的是当初始片段被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);
        }
    }

}

和片段:

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

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

感谢您的帮助。

3 个答案:

答案 0 :(得分:8)

尝试将setHasOptionsMenu(true);放入onCreateView()的{​​{1}}内 我在你发布的代码中没有看到一个。

答案 1 :(得分:2)

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

这是我做的:

在父活动中:

MainActivity.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);
    }

}

这里是片段的一部分:

ChildFragment.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);
}

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

答案 2 :(得分:1)

有两种情况需要考虑:

  1. 您希望所有操作项都来自片段内。
  2. 您还拥有应该是全局的行动项目,并在活动中定义。
  3. 让我们从选项2开始,因为它是最常见的情况。

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

    您还可以让片段决定显示哪些项目是为所有片段创建一个接口来实现。这可以定义一种方法,它会返回菜单的菜单ID以使其膨胀,或者-1如果没有菜单应该膨胀。

    如果是选项1,我只能假设您clear()在活动onCreateOptionsMenu()中的菜单。否则它不会删除片段的菜单条目。所以只要摆脱clear(),一切都应该没问题。