【问题标题】:How to add Options Menu to Fragment in Android如何在 Android 中将选项菜单添加到 Fragment
【发布时间】:2012-01-08 16:05:52
【问题描述】:

我正在尝试从一组片段中向选项菜单中添加一个项目。

我创建了一个新的MenuFragment 类并将其扩展为我希望在其中包含菜单项的片段。代码如下:

Java:

public class MenuFragment extends Fragment {

    MenuItem fav;

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

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

科特林:

class MenuFragment : Fragment {

    lateinit var fav: MenuItem

    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

由于某种原因,onCreateOptionsMenu 似乎没有运行。

【问题讨论】:

标签: android android-fragments android-optionsmenu


【解决方案1】:

调用超级方法:

Java:

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

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // TODO Add your menu entries here
        super.onCreateOptionsMenu(menu, inflater);
    }

科特林:

    override fun void onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        // TODO Add your menu entries here
        super.onCreateOptionsMenu(menu, inflater)
    }

将日志语句放入代码中,以查看是否没有调用该方法,或者您的代码是否没有修改菜单。

还要确保您在onCreate(Bundle) 中调用setHasOptionsMenu(boolean) 以通知片段它应该参与选项菜单处理。

【讨论】:

  • 感谢您的帮助,我添加了 super 方法,并意识到我已经删除了 @Override 所以又添加了这个,eclipse 抛出了一个错误,所以我替换了 MenuInflater 以导入 android.view.MenuInflater;而不是导入 android.support.v4.view.MenuInflater;现在一切正常
  • 在 Fragment 的 onCreate 中不调用 setHasOptionsMenu(true) 已经让我两次了
  • 我正在将我的 Activity 转移到 Fragment 并遇到了这个问题。方法签名已从 public boolean 更改为 public void,并且参数也已更改。请务必注意这一点!
  • 请注意,Fragment.onCreateOptionsMenu(Menu, MenuInflater) 是一个空方法,因此根本不需要调用 super。这里唯一的错误是错误的方法签名,并且可能在 onCreate() 中缺少 setHasOptionsMenu()
  • 将 super.onCreateOptionsMenu 替换为 inflater.inflate(R.menu.menu_custom, menu);
【解决方案2】:

我遇到了同样的问题,但我认为最好总结并介绍最后一步以使其正常工作:

  1. 在 Fragment 的 onCreate(Bundle savedInstanceState) 方法中添加 setHasOptionsMenu(true) 方法。

  2. 在 Fragment 中覆盖 onCreateOptionsMenu(Menu menu, MenuInflater inflater)(如果您想在 Fragment 的菜单中执行不同的操作)和 onOptionsItemSelected(MenuItem item) 方法。

  3. 在onOptionsItemSelected(MenuItem item) Activity 的方法中,确保在onOptionsItemSelected(MenuItem item) Fragment 的方法中实现菜单项操作时返回false。

一个例子:

活动

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getSupportMenuInflater();
    inflater.inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Do Activity menu item stuff here
            return true;

        case R.id.fragment_menu_item:

            // Not implemented here
            return false;
        default:
            break;
    }

    return false;
}

片段

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    ....
}

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

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Not implemented here
            return false;
        case R.id.fragment_menu_item:

            // Do Fragment menu item stuff here
            return true;

        default:
            break;
    }

    return false;
}

【讨论】:

  • 只是失踪了setHasOptionsMenu(true); 谢谢
  • 在某些设备上的 viewPager 上,菜单仅在您第二次转到片段时显示
  • @Marco HC 您的代码运行良好。但是,如果我想隐藏 Activity 或 Fragment 的某些菜单怎么办?您提到了在哪里实现哪个选项菜单(在活动和片段中)。但是如果我想隐藏一些菜单呢?
  • @iDroidExplorer 只需保留对该 MenuItem 的引用并将可见性设置为消失或不可见。这是你的问题?
  • @iDroidExplorer 我尝试了他的代码,但我不知道如何,但是当我切换到其他片段时它会自动隐藏菜单。
【解决方案3】:

如果您发现 onCreateOptionsMenu(Menu menu, MenuInflater inflater) 方法没有被调用,请确保您从 Fragment 的 onCreate(Bundle savedInstanceState) 方法中调用以下内容:

setHasOptionsMenu(true)

【讨论】:

  • 它给了我类似 NullPointerException 的错误
  • 好点。我从静态 newInstance 方法调用 setHasOptionMenu 方法。因为我只是在 savedInstanceState 为空时附加我的片段,所以当屏幕配置更改时,不会创建菜单。片段的 onCreate 方法是将 setHasOptionMenu 设置为 true 的正确位置。
  • 我使用的是Toolbar,必须在onCreateView() 中调用setHasOptionsMenu(true) 而不是onCreate() 才能完成。
【解决方案4】:

如果您需要 menu 来刷新特定 Fragment 内的 webview,您可以使用:

片段:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

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

    // TODO Add your menu entries here
    inflater.inflate(R.menu.menu, menu);
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.exit:
        System.exit(1);
        break;

    case R.id.refresh:
        webView.reload();
        break;
    }
    return true;

}

menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/exit" android:title="Exit" android:icon="@drawable/ic_action_cancel" />
    <item android:id="@+id/refresh" android:title="Refresh" android:icon="@drawable/ic_action_refresh" />
</menu>

【讨论】:

  • 这是一个很好的答案,我正在寻找一种方法来合并来自活动的应用栏和来自片段的其他选项,谢谢!
【解决方案5】:

TL;DR

使用android.support.v7.widget.Toolbar 就可以了:

toolbar.inflateMenu(R.menu.my_menu)
toolbar.setOnMenuItemClickListener {
    onOptionsItemSelected(it)
}

独立工具栏

大多数建议的解决方案(如 setHasOptionsMenu(true))仅在 父 Activity 的布局中有工具栏并通过 setSupportActionBar() 声明时才有效。然后 Fragments 可以参与到这个确切的 ActionBar 的菜单填充中:

Fragment.onCreateOptionsMenu():初始化Fragment宿主的标准选项菜单的内容。

如果您想要一个特定片段的独立工具栏和菜单,您可以执行以下操作:

menu_custom_fragment.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_save"
        android:title="SAVE" />
</menu>

custom_fragment.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    ...

CustomFragment.kt

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater.inflate(layout.custom_fragment, container, false)
    val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
    toolbar.inflateMenu(R.menu.menu_custom_fragment)
    toolbar.setOnMenuItemClickListener {
        onOptionsItemSelected(it)
    }
    return view
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.menu_save -> {
            // TODO: User clicked the save button
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

是的,就是这么简单。您甚至不需要覆盖 onCreate() 或 onCreateOptionsMenu()。

PS:这仅适用于 android.support.v4.app.Fragment 和 android.support.v7.widget.Toolbar(也请务必在 styles.xml 中使用 AppCompatActivity 和 AppCompat 主题)。

【讨论】:

  • 对我帮助很大
  • 在这种情况下是否有替代onPrepareOptionsMenu 的方法?
  • 这是我的问题!谢谢!
【解决方案6】:

在menu.xml 中您应该添加所有菜单项。然后,您可以隐藏在初始加载时不想看到的项目。

menu.xml

<item
    android:id="@+id/action_newItem"
    android:icon="@drawable/action_newItem"
    android:showAsAction="never"
    android:visible="false"
    android:title="@string/action_newItem"/>

在 onCreate() 方法中添加 setHasOptionsMenu(true) 以调用 Fragment 类中的菜单项。

FragmentClass.java

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

您无需再次在 Fragment 类中覆盖 onCreateOptionsMenu。可以通过覆盖 Fragment 中的 onPrepareOptionsMenumethod 来更改(添加/删除)菜单项。

@Override
public void onPrepareOptionsMenu(Menu menu) {
    menu.findItem(R.id.action_newItem).setVisible(true);
    super.onPrepareOptionsMenu(menu);

}

【讨论】:

    【解决方案7】:

    就我而言,这是步骤。

    步骤一

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        // Here notify the fragment that it should participate in options menu handling.
        setHasOptionsMenu(true);
    }
    

    第二步

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // First clear current all the menu items
        menu.clear();
    
        // Add the new menu items
        inflater.inflate(R.menu.post_stuff, menu);
    
        super.onCreateOptionsMenu(menu, inflater);
    }
    

    第三步

     @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.post_stuff:
                Log.d(TAG, "Will post the photo to server");
                return true;
            case R.id.cancel_post:
                Log.d(TAG, "Will cancel post the photo");
                return true;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }
    

    【讨论】:

    • 我已经在主要活动上有菜单,使用menu.clear() 清除了上一个菜单。为我工作:)
    • 我有带有片段的 ViewPager,menu.clear() 是缺少的部分,谢谢!
    【解决方案8】:

    你需要在膨胀菜单之前使用 menu.clear()。

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

    和

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

    【讨论】:

    • 当您想要不同片段中的不同菜单并且您正在添加片段而不是替换它们时,这是正确的。
    • 谢谢! menu.clear() 帮我去掉Activity的菜单选项。
    【解决方案9】:

    如果你想添加你的菜单自定义

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }
    
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_custom, menu);
    }
    

    【讨论】:

    • 如果有一个标签视图并且你想为每个片段膨胀不同的菜单怎么办?
    【解决方案10】:

    我遇到了同样的问题,我的片段是 ViewPager 的页面。发生这种情况的原因是我在实例化 FragmentPagerAdapter 时使用了子片段管理器而不是活动支持片段管理器。

    【讨论】:

      【解决方案11】:

      菜单文件:

      <?xml version="1.0" encoding="utf-8"?>
      <menu xmlns:android="http://schemas.android.com/apk/res/android">
          <item
              android:id="@+id/play"
              android:titleCondensed="Speak"
              android:showAsAction="always"
              android:title="Speak"
              android:icon="@drawable/ic_play">
          </item>
          <item
              android:id="@+id/pause"
              android:titleCondensed="Stop"
              android:title="Stop"
              android:showAsAction="always"
              android:icon="@drawable/ic_pause">
          </item>
      </menu>
      

      活动代码:

      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          MenuInflater inflater = getMenuInflater();
          inflater.inflate(R.menu.speak_menu_history, menu);
          return true;
      }
      
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          switch (item.getItemId()) {
      
              case R.id.play:
                  Toast.makeText(getApplicationContext(), "speaking....", Toast.LENGTH_LONG).show();
                  return false;
      
              case R.id.pause:
                  Toast.makeText(getApplicationContext(), "stopping....", Toast.LENGTH_LONG).show();
                  return false;
      
              default:
                  break;
          }
      
          return false;
      }
      

      片段代码:

      @Override
      
      public void onCreate(Bundle savedInstanceState) {
          // TODO Auto-generated method stub
          super.onCreate(savedInstanceState);
          setHasOptionsMenu(true);
      }
      
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          switch (item.getItemId()) {
      
              case R.id.play:
                  text = page.getText().toString();
                  speakOut(text);
      
                  // Do Activity menu item stuff here
                  return true;
      
              case R.id.pause:
                  speakOf();
      
                  // Not implemented here
                  return true;
      
              default:
                  break;
          }
          return false;
      }
      

      【讨论】:

        【解决方案12】:

        您的代码很好。该方法中仅缺少超级:

        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            // TODO add your menu : 
            inflater.inflate(R.menu.my_menu, menu);
            //TODO call super
            super.onCreateOptionsMenu(menu, inflater);
        }
        

        【讨论】:

          【解决方案13】:

          我快疯了,因为这里的答案都不适合我。

          要显示我必须调用的菜单: setSupportActionBar(toolbar)

          完成!

          注意:如果您的 toolbar 视图不在同一个活动布局中,则不能直接从活动类中使用上述调用,在这种情况下,您需要从片段类中获取该活动,然后拨打setSupportActionBar(toolbar)。记住:您的活动类应该扩展 AppCompatActivity。

          希望这个答案对你有所帮助。

          【讨论】:

            【解决方案14】:

            如果应用程序有一个带有Actionbar 的主题,例如Theme.MaterialComponents.DayNight.DarkActionBar 或Activity 有它自己的工具栏,则设置setHasMenuOptions(true) 有效,否则片段中的onCreateOptionsMenu 不会被调用。

            如果您想使用独立的工具栏,您需要获取活动并将您的工具栏设置为支持操作栏

            (requireActivity() as? MainActivity)?.setSupportActionBar(toolbar)
            

            这让你的片段 onCreateOptionsMenu 被调用。

            另一种选择是,您可以使用toolbar.inflateMenu(R.menu.YOUR_MENU) 扩展工具栏自己的菜单,并使用

            toolbar.setOnMenuItemClickListener {
               // do something
               true
            }
            

            【讨论】:

            • 这就是为什么无论我做什么我的菜单都不会显示的原因。解决方案有效,谢谢!!!!
            【解决方案15】:

            在创建片段视图后设置选项菜单对我来说效果很好。

            @Override
            public void onActivityCreated(Bundle savedInstanceState) {
                super.onActivityCreated(savedInstanceState);
                setHasOptionsMenu(true);        
            }
            

            【讨论】:

              【解决方案16】:

              我的问题略有不同。我做的一切都是正确的。但是我为托管片段的活动继承了错误的类。

              所以要明确一点,如果您在片段中覆盖onCreateOptionsMenu(Menu menu, MenuInflater inflater),请确保承载此片段的活动类继承android.support.v7.app.ActionBarActivity(以防您希望支持低于 API 级别 11)。

              我继承了 android.support.v4.app.FragmentActivity 以支持低于 11 的 API 级别。

              【讨论】:

                【解决方案17】:

                我要补充一点,以及它对我不起作用的原因。

                这与 Napster 的回答类似。

                1. 确保片段的托管活动扩展 AppCompatActivity,而不是 FragmentActivity!

                  public class MainActivity extends AppCompatActivity {
                  
                  }
                  

                  来自 Google 参考 Documentation 的 FragmentActivity:

                  注意:如果您想实现一个包含操作栏的活动,您应该改用 ActionBarActivity 类,它是该类的子类,因此允许您在 API 级别 7 及更高级别上使用 Fragment API。

                2. 要更新 Napster 的答案 -- ActionBarActivity 现已弃用,请改用 AppCompatActivity。

                3. 使用AppCompatActivity时,还要确保将“活动主题设置为Theme.AppCompat或类似主题”(Google Doc)。

                注意:android.support.v7.app.AppCompatActivity 是 android.support.v4.app.FragmentActivity 类的子类(参见 AppCompatActivity 参考文档)。

                【讨论】:

                  【解决方案18】:

                  在您的菜单文件夹中创建一个 .menu xml 文件并添加此 xml

                  <item
                      android:id="@+id/action_search"
                      android:icon="@android:drawable/ic_menu_search"
                      android:title="@string/action_search"
                      app:actionViewClass="android.support.v7.widget.SearchView"
                      app:showAsAction="always|collapseActionView" />
                  

                  在你的片段类中覆盖这个方法和

                  implement SearchView.OnQueryTextListener    in your fragment class
                  
                  
                  
                  @Override
                   public void onViewCreated(View view, Bundle savedInstanceState) {    
                    super.onViewCreated(view, savedInstanceState);
                    setHasOptionsMenu(true);
                  
                  }
                  

                  现在只需在片段类中设置菜单 xml 文件

                  @Override
                  public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
                      inflater.inflate(R.menu.menu_main, menu);
                  
                      final MenuItem item = menu.findItem(R.id.action_search);
                      final SearchView searchView = (SearchView)    
                      MenuItemCompat.getActionView(item);
                  
                  
                      MenuItemCompat.setOnActionExpandListener(item,
                              new MenuItemCompat.OnActionExpandListener() {
                                  @Override
                                  public boolean onMenuItemActionCollapse(MenuItem item) {
                                      // Do something when collapsed
                  
                                      return true; // Return true to collapse action view
                                  }
                  
                                  @Override
                                  public boolean onMenuItemActionExpand(MenuItem item) {
                                      // Do something when expanded
                                      return true; // Return true to expand action view
                                  }
                              });
                  
                  }
                  

                  【讨论】:

                    【解决方案19】:

                    如果以上所有方法都不起作用,您需要调试并确保函数 onCreateOptionsMenu 已被调用(通过放置调试或写入日志...)

                    如果没有运行,可能是您的 Android 主题不支持操作栏。 打开 AndroidManifest.xml 并使用主题支持操作栏设置android:theme 的值:

                     <activity
                         android:name=".MainActivity"
                         android:label="@string/app_name"
                         android:theme="@style/Theme.AppCompat">
                    

                    【讨论】:

                      【解决方案20】:

                      在您的 onCreate 方法上添加 setHasOptionMenu()

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

                      然后覆盖你的onCreateOptionsMenu

                      @Override
                      public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
                          menu.add("Menu item")
                                  .setIcon(android.R.drawable.ic_delete)
                                  .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
                      }
                      

                      【讨论】:

                        【解决方案21】:

                        这就是我在片段加载和销毁时分别隐藏和取消隐藏所有菜单选项的操作。它消除了将 null 指向 R.id.your_menu_item 的风险,并允许我在其他地方重用该片段。

                        lateinit var optionsMenu: Menu
                        
                        override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
                            menu.iterator().forEach {
                                it.isVisible = false
                            }
                            optionsMenu = menu
                            super.onCreateOptionsMenu(menu, inflater)
                        }
                        
                        override fun onDestroyView() {
                            optionsMenu.iterator().forEach {
                                it.isVisible = true
                            }
                            super.onDestroyView()
                        }
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 2014-02-17
                          • 1970-01-01
                          • 2013-02-05
                          • 1970-01-01
                          • 2013-07-19
                          • 1970-01-01
                          • 2023-03-12
                          • 1970-01-01
                          相关资源
                          最近更新 更多