【问题标题】:Clear Toolbar menu options added by fragment when it is replaced替换片段时清除片段添加的工具栏菜单选项
【发布时间】:2017-04-14 02:56:50
【问题描述】:

我设置了 3 个“顶级”片段,每个片段都使用自己的子片段管理器来提供向下钻取导航。这些顶级片段通过使用主活动的支持片段管理器进行替换来切换。

其中一个顶级片段有一个子片段,它使用setHasOptionsMenu()onCreateOptionsMenu() 将菜单选项添加到工具栏/操作栏,效果很好。

现在我刚刚注意到的问题是:

当添加新的子片段并且带有菜单项的子片段被隐藏(并且事务添加到顶级片段的后台堆栈)时,菜单项消失。同样,当通过撤消事务再次显示片段时,菜单项将返回。这是期望的行为,似乎完全由 Fragment 框架处理。

但是,如果子片段可见(因此,它的菜单项出现在工具栏中)并且我切换顶级片段,则菜单项仍保留在工具栏中

我本以为菜单项会被清除,因为不仅它所属的子片段已被转储,而且甚至其父片段(在顶级片段中)也已被完全替换(甚至没有添加到backstack,直接替换)。

我想只要传入的顶级片段恢复,我就可以在活动上调用invalidateOptionsMenu(),但我觉得我缺少一些东西来自动处理它,就像在顶级中导航时一样片段。

【问题讨论】:

    标签: android android-fragments android-actionbar android-toolbar android-menu


    【解决方案1】:

    onCreateOptionsMenu 方法在创建或重新创建每个片段后调用。 您需要做的是在扩展新菜单 xml 之前清除菜单。 尝试这样做:

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState){
        super.onViewCreated(view, savedInstanceState);
        setHasOptionsMenu(true);
    }
    
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
        super.onCreateOptionsMenu(menu, inflater);
        menu.clear();
        inflater.inflate(R.menu.your_menu, menu);
    }
    

    【讨论】:

    • OP 建议使用clear() 而不是invalidateOptionsMenu() 的原因是什么?
    • @lucidbrot 我使用 clear() 来清理堆栈菜单,因为如果您首先有另一个片段和另一个菜单项,那么您将拥有所有项目..您需要清除堆栈菜单。另一方面,不推荐使用 invalidateOptionsMenu()。
    • 我认为the AppCompat Version 没有被弃用。如果你先有另一个片段,并替换它,如果你无效,第一个菜单不应该保留
    • 没关系,it is deprecated but you can useActivity.invalidateOptionsMenu
    【解决方案2】:

    最简单的方法是在片段中创建接口,并使用 onAttach/onDetach 方法检查片段可见性:

    public class QuickSetup1Fragment extends Fragment {
       private CallbackListener onCallbackListener;
       public QuickSetup1Fragment() {}
    
       @Override
       public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
           View view = inflater.inflate(R.layout.fragment_quick_setup1, container, false);
           return view;
       }
    
       @Override
       public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
          super.onViewCreated(view, savedInstanceState);
       }
    
       public interface CallbackListener{
          public void onAttach(); //fragment is visible
          public void onDetach(); //fragment is invisible/replace/destroy
       }
    
       @Override
       public void onAttach(Context context) {
           super.onAttach(context);
           try {
               onCallbackListener = (CallbackListener) context;
               onCallbackListener.onAttach();
           } catch (ClassCastException e) {
               throw new ClassCastException(context.toString()
                    + " must implement CallbackListener");
           }
       }
    
       @Override
       public void onDetach() {
           super.onDetach();
           onCallbackListener.onDetach();
           onCallbackListener = null;
       }
    }
    

    并在你的活动类上实现接口方法

    public class QuickSetupActivity extends AppCompatActivity implements QuickSetup1Fragment.CallbackListener{
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_image_view);
           Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
           setSupportActionBar(toolbar);
       }
    
       @Override
       protected void onPostCreate(@Nullable Bundle savedInstanceState) {
           super.onPostCreate(savedInstanceState);
       }
    
       @OnClick(R.id.backBtn)
       public void back(View v){
           super.onBackPressed();
       }
    
       @Override
       public void onAttach(){
          //do something with the menu
       }
    
       @Override
       public void onDetach(){
          //do something with the menu
       }
    }
    

    每次更改片段时,都会触发 onAttach/onDetach。您可以在此处执行特定任务,例如管理菜单。

    【讨论】:

    • 谢谢,我已经有一个与我的顶级片段类似的设置,这些片段实际上只是作为活动自己的后台堆栈的独立后台堆栈的空片段。这些片段与 Activity 交互,用于许多生命周期事件和诸如后退按钮按下之类的事情。我可以通过这种方式轻松使用invalidateOptionsMenu(),但我非常好奇为什么当片段只是隐藏时菜单似乎在子片段管理器中自动管理,而不是在活动片段中。完全替换片段时的管理器。我觉得我错过了什么。
    【解决方案3】:

    尝试在您的父片段中实现一个回调,该回调应该在销毁子片段之前调用!在那个回调里面 oncreateoptions()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-18
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-23
      • 2018-08-21
      相关资源
      最近更新 更多