Android:通过更改片段更改菜单项的可见性

Posted

技术标签:

【中文标题】Android:通过更改片段更改菜单项的可见性【英文标题】:Android: Changing visibility on menu items with changing fragment 【发布时间】:2013-01-02 16:18:30 【问题描述】:

当我更改活动中的片段时,我想更改片段活动 (abs) 的菜单项的可见性。片段是 SherlockListFragments。

我要显示/隐藏的菜单项是我在创建菜单时创建的微调器:

public boolean onCreateOptionsMenu(Menu menu) 
    // Inflate the menu; this adds items to the action bar if it is present.
    MenuInflater inflater = getSupportMenuInflater();

    IcsSpinner herbSortSpinner = new IcsSpinner(this, null, R.attr.actionDropDownStyle);
    SpinnerAdapter herbSortSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.herb_sort_elements, android.R.layout.simple_spinner_dropdown_item);
    herbSortSpinner.setAdapter(herbSortSpinnerAdapter);
    herbSortSpinner.setOnItemSelectedListener(this);
    herbSortSpinner.setId(HERB_SPINNER_ID);
    menu.add(R.string.menu_sort).setActionView(herbSortSpinner).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

    IcsSpinner noteSortSpinner = new IcsSpinner(this,  null, R.attr.actionDropDownStyle);
    SpinnerAdapter noteSortSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.note_sort_elements, android.R.layout.simple_spinner_dropdown_item);
    noteSortSpinner.setAdapter(noteSortSpinnerAdapter);
    noteSortSpinner.setOnItemSelectedListener(this);
    noteSortSpinner.setId(NOTE_SPINNER_ID);
    menu.add(R.string.menu_sort).setActionView(noteSortSpinner).setVisible(false).setEnabled(false).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

    inflater.inflate(R.menu.activity_lexicon, menu);
    menuHolder.setMenu(menu);
    return true;

我切换片段的逻辑是:

public boolean onNavigationItemSelected(int position, long itemId) 

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    switch(position) 
    case 0:
        List<Herb> herbList = findHerbsByIntent(getHerbLocale());
        HerbListFragment herbListFragment = new HerbListFragment();
        herbListFragment.setListAdapter(new HerbListAdapter(this, getHerbLocale(), herbList));
        fragmentTransaction.replace(R.id.fragment_container, herbListFragment, HERB_LIST_FRAGMENT_TAG);
        //menuHolder.showHerbsSpinner();
        break;
    case 1:
        SymptomListFragment symptomListFragment = new SymptomListFragment();
        symptomListFragment.setListAdapter(new SymptomListAdapter(this, getDefaultSymptomLocale()));
        fragmentTransaction.replace(R.id.fragment_container, symptomListFragment, SYMPTOM_LIST_FRAGMENT_TAG);
        //menuHolder.showHerbsSpinner();
        break;
    case 2:
        NoteRepository noteRepository = new NoteRepository(this);
        List<Note> notes = noteRepository.getNoticables(ReferedType.HERB);
        NoteListFragment noteListFragment = new NoteListFragment();
        noteListFragment.setListAdapter(new NoteListAdapter(this, getHerbLocale(), notes));
        fragmentTransaction.replace(R.id.fragment_container, noteListFragment, NOTE_LIST_FRAGMENT_TAG);
        //menuHolder.showNotesSpinner();
        break;
    case 3:
        FavoriteRepository favoriteRepository = new FavoriteRepository(this);
        Set<Integer> favoriteHerbs = favoriteRepository.getFavorables(ReferedType.HERB);
        List<Herb> favoriteHerbList = herbRepository.getHerbsByIds(favoriteHerbs, getHerbLocale());
        FavoriteHerbListFragment favoriteHerbListFragment = new FavoriteHerbListFragment();
        favoriteHerbListFragment.setListAdapter(new HerbListAdapter(this, getHerbLocale(), favoriteHerbList));
        fragmentTransaction.replace(R.id.fragment_container, favoriteHerbListFragment, HERB_LIST_FRAGMENT_TAG);
        //menuHolder.showHerbsSpinner();
        break;
    
    fragmentTransaction.commit();

    return true;

我的第一个想法是将菜单对象保存在一个持有者类中,并在我切换片段时在那里操作它(在上面的每个 case 语句中)。

static class MenuHolder 

    private Menu mMenu;

    void setMenu(Menu menu) 
        mMenu = menu;
    

    void showNotesSpinner() 
        if (mMenu != null) 
            mMenu.findItem(HERB_SPINNER_ID).setVisible(false).setEnabled(false);
            mMenu.findItem(NOTE_SPINNER_ID).setVisible(true).setEnabled(true);
        
    

    void showHerbsSpinner() 
        if (mMenu != null) 
            mMenu.findItem(NOTE_SPINNER_ID).setVisible(false).setEnabled(false);            
            mMenu.findItem(HERB_SPINNER_ID).setVisible(true).setEnabled(true);
        
    

我的问题是没有给定 ID 的菜单项是活动本地常量。我在这里得到一个 NPE。有人知道我该如何解决吗?有没有更好的方法来改变切换片段时的菜单?

最好的问候 卡斯滕

【问题讨论】:

昨天帮助了自己。我已经清理了杂乱的代码(仅在 onCreate 中实例化片段一次)并将菜单项直接存储到持有人中。现在它就像一个魅力。 【参考方案1】:

有没有更好的方法来改变切换片段时的菜单?

可能是的:)。

在您的片段onCreate 中,添加以下内容:

setHasOptionsMenu (true);

文档:

报告此片段希望通过接收对 onCreateOptionsMenu(Menu, MenuInflater) 和相关方法的调用来参与填充选项菜单。

覆盖片段类中的onPrepareOptionMenu 方法。

准备要显示的屏幕标准选项菜单。每次显示菜单时,都会在显示菜单之前调用它。您可以使用此方法有效地启用/禁用项目或以其他方式动态修改内容。

然后,在此方法中,尝试通过 ID 查找您的菜单项,并使其可见/不可见、启用/禁用,如下所示:

@Override
public void onPrepareOptionsMenu(Menu menu)     
    menu.findItem(HERB_SPINNER_ID).setVisible(false).setEnabled(false);

Read More

【讨论】:

这个答案值得更多的支持。然而,在 PreferenceFragment 中,必要的 Override-declaration 将是: public void onPrepareOptionsMenu(Menu menu) /*..*/ 不过,你为我节省了很多工作。谢谢。 :) 也帮助了我,谢谢,mMenu 应该是菜单,它不应该返回任何东西,因为它是一个空。【参考方案2】:

就我而言,我有 2 个片段具有不同的菜单项。

在我的 MainActivity 上:

FragmentA fragmentA = new FragmentA();
fragmentA.setTargetFragment(fragmentA, 0);
FragmentB fragmentB = new FragmentB();
fragmentB.setTargetFragment(fragmentB, 1);

而 FragmentA 和 FragmentB 有:

@Override
public void onHiddenChanged(boolean hidden) 
    super.onHiddenChanged(hidden);
    if(hidden) 
        getTargetFragment().setMenuVisibility(false);
    else
        getTargetFragment().setMenuVisibility(true);
    

这将使片段 A 的菜单在 B 离开时可见。如果从 B 回到 A,则可以看到 A 的旧菜单。

参考:here

【讨论】:

以上是关于Android:通过更改片段更改菜单项的可见性的主要内容,如果未能解决你的问题,请参考以下文章

更改组件可见性时 Android Studio 空对象引用错误

在菜单项的可见性模式之间进行动画处理

如何从活动中更改片段中视图的可见性

显示/隐藏片段并以编程方式更改可见性属性

在异步任务中更改 onPostexecute 中的可见性设置

如果 MutableList 为空,如何更改 TextView 的可见性? (安卓/科特林)