【问题标题】:onCreateOptionsMenu() in fragment not replacing ActionBar menus片段中的 onCreateOptionsMenu() 不替换 ActionBar 菜单
【发布时间】:2014-04-26 17:41:52
【问题描述】:

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

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

在此处添加父活动的一些代码 sn-ps 和片段之一。 当初始片段被替换为 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()。我只是不明白为什么操作栏保留其初始菜单项并且不替换它们。我错过了什么?

感谢您的帮助。

【问题讨论】:

  • 调试时它会在你的Activity之后调用onCreateOptionsMenu()吗(即关闭抽屉后)?
  • @WolframRittmeyer 是的。抽屉关闭后,在父 Activity 中再次调用 onCreateOptionsMenu()。我想这会破坏片段中的菜单项。我怎样才能避免这种情况?
  • 尝试在 super.onCreateOptionsMenu() 之前调用 menu.clear() 和 inflater.inflate

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


【解决方案1】:

尝试将setHasOptionsMenu(true); 放在您的ChildFragment.javaonCreateView() 中 我在您发布的代码中没有看到。

【讨论】:

    【解决方案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);
    }
    

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

    【讨论】:

      【解决方案3】:

      有两种情况需要考虑:

      1. 您希望所有操作项仅来自片段内。
      2. 您还有应该是全局的并在活动中定义的操作项。

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

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

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

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

      【讨论】:

      • 我已经尝试将 menu.clear() 添加到 Activity 中的 onCreateOptionsMenu() 中。但这对在片段之间切换时更改操作栏菜单没有任何影响。您能否更详细地解释一下我将如何使用您建议的界面来执行此操作?谢谢。
      • 我找到了解决方案并通过自己的问题回答。主要问题是我在一个片段中有一个下拉菜单,在切换片段时它没有消失。因此,每次从片段 0 更改为片段 n 时,我都必须手动删除它。
      • 首先,您可以根据抽屉状态直接在片段上调用setHasOptionsMenu(true/false),而不是在片段上实现接口。但是,使用嵌套片段时还有一个问题 - 活动必须向下进入其片段树并搜索所有片段以关闭菜单。因此,最好翻转范式,让所有片段都使用 getActivity() 并在 Activity 上实现一个接口以显示抽屉打开/关闭状态。
      猜你喜欢
      • 2013-03-17
      • 2012-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多