如何添加选项菜单碎片在Android

我试图从一组片段中添加一个项目到选项菜单。

我已经创建了一个新的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似乎没有运行。

334435 次浏览

调用super方法:

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)来通知片段它应该参与选项菜单处理。

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

setHasOptionsMenu(true)

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

我也遇到了同样的问题,但我认为最好总结并介绍让它工作的最后一步:

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

  2. 重写Fragment中的onCreateOptionsMenu(Menu menu, MenuInflater inflater)(如果你想在Fragment的菜单中做一些不同的事情)和onOptionsItemSelected(MenuItem item)方法。

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

一个例子:

< em > < / em >活动

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

< em > < / em >片段

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

如果你需要一个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>

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

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

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中可用的__abc1方法来更改(添加/删除)。

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


}

在膨胀菜单之前,您需要使用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);
}

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

所以要明确的是,如果你在片段中覆盖onCreateOptionsMenu(Menu menu, MenuInflater inflater),确保你的活动类继承了这个片段的android.support.v7.app.ActionBarActivity(以防你想要支持低于API级别11)。

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

除此之外,我还要补充一件事,以及它不适合我的原因。

这与Napster的答案相似。

  1. < p > 确保你的片段的托管活动扩展了__ABC0,而不是FragmentActivity!

    public class MainActivity extends AppCompatActivity {
    
    
    }
    

    FragmentActivity的谷歌引用文档:

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

    李< /引用> < / >
  2. 要更新Napster的答案——ActionBarActivity现在已被弃用,请改用AppCompatActivity

  3. 当使用AppCompatActivity时,也要确保你设置了“活动主题为__abc1或类似的主题”(谷歌Doc)。

注意:android.support.v7.app.AppCompatActivityandroid.support.v4.app.FragmentActivity类的子类(参见AppCompatActivity ref doc)。

菜单文件:

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

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

如果它没有运行,也许你的Android主题不支持操作栏。 打开AndroidManifest.xml,设置android:theme的值,主题支持操作栏:

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

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

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

在菜单文件夹中创建一个.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);


}

现在只需在fragment class中设置你的菜单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
}
});


}

在你的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);
}

你的代码很好。方法中只少了super:

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

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

为了显示菜单,我不得不打电话: setSupportActionBar(toolbar)

完成了!

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

希望这个答案能帮助到你。

在我的例子中,下面是步骤。

步骤1

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);


// Here notify the fragment that it should participate in options menu handling.
setHasOptionsMenu(true);
}

步骤2

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

步骤3

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

博士TL;

使用android.support.v7.widget.Toolbar并执行:

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

独立的工具栏

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

Fragment. oncreateoptionsmmenu():初始化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.Fragmentandroid.support.v7.widget.Toolbar(也一定要在你的styles.xml中使用AppCompatActivityAppCompat主题)。

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

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

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

它让你的fragment onCreateOptionsMenu被调用。

其他的选择是,你可以用toolbar.inflateMenu(R.menu.YOUR_MENU)和项目监听器来膨胀你的工具栏自己的菜单

toolbar.setOnMenuItemClickListener {
// do something
true
}

这是我所做的隐藏和取消隐藏所有的菜单选项时,片段分别被加载和销毁。它减少了为R.id.your_menu_item指向null的风险,并允许我在其他地方重用这个片段。

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

如果上面的选项都不适合你,在你的片段中试试这个:

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




override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
....
toolBar = rootView.findViewById(R.id.import_contacts_toolbar)
toolBar?.title = "Your title"
toolBar?.subtitle = "yor subtitile"
contactsActivity().setSupportActionBar(toolBar)
toolBar?.inflateMenu(R.menu.import_contacts_menu)
...
}






override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.1 -> {


return true
}
R.id.2 -> {


return true
}
}
    

return false
}










override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.clear()
inflater.inflate(R.menu.import_contacts_menu, menu)
super.onCreateOptionsMenu(menu, inflater)


val search = menu.findItem(R.id.action_search)
val searchView = search.actionView as SearchView
searchView.requestFocus()


val txtSearch = searchView.findViewById<View>(androidx.appcompat.R.id.search_src_text) as EditText
txtSearch.hint = "Search..."
txtSearch.setHintTextColor(Color.WHITE);
txtSearch.setTextColor(Color.WHITE)


try {
val f: Field = TextView::class.java.getDeclaredField("mCursorDrawableRes")
f.setAccessible(true)
f.set(txtSearch, R.drawable.search_edit_text_cursor)
} catch (ignored: Exception) {
Log.d(TAG, "failed to expose cursor drawable $ignored")
}


searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}


override fun onQueryTextChange(newText: String): Boolean {


return true
}
})
searchView.setOnCloseListener {
            

}
}

在我的例子中,我有一个搜索菜单项,它被设置为始终可见。这是它的xml文件:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">


<item
android:id="@+id/action_search"
app:showAsAction="always"
app:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="Search"/>


<item android:id="@+id/1"
android:title="1">
</item>


<item android:id="@+id/2"
android:title="2">
</item>
</menu>

自从androidx.activity:activity:1.4.0之后,就有了一种新的方法

你应该使用MenuProvider API。

它的用法如下:

你应该在onViewCreated中调用addMenuProvider,而不是调用super.setHasOptionMenu并实现onCreateOptionsMenu

一个例子:

class ExampleFragment : Fragment(R.layout.fragment_example) {


override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// The usage of an interface lets you inject your own implementation
val menuHost: MenuHost = requireActivity()
  

// Add menu items without using the Fragment Menu APIs
// Note how we can tie the MenuProvider to the viewLifecycleOwner
// and an optional Lifecycle.State (here, RESUMED) to indicate when
// the menu should be visible
menuHost.addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
// Add menu items here
menuInflater.inflate(R.menu.example_menu, menu)
}


override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Handle the menu selection
return true
}
}, viewLifecycleOwner)
}

来源:活动的更新日志

现在在2022年,谷歌弃用了setHasOptionsMenu,你应该使用MenuProvider代替。根据我的经验,当我使用setHasOptionsMenu方法时,我在一些android 11,12上得到了NoSuchMethodException

当使用MenuProvider为您的活动提供菜单时,不再需要此方法,它取代了onCreateOptionsMenu作为推荐的方式来提供一致的、可选的生命周期感知的、模块化的方式来处理菜单创建和项目选择。

这是你如何添加菜单到你的活动/片段atm:

/**
* Using the addMenuProvider() API directly in your Activity
**/
class ExampleActivity : ComponentActivity() {


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)


// Add menu items without overriding methods in the Activity
addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
// Add menu items here
menuInflater.inflate(R.menu.example_menu, menu)
}


override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Handle the menu selection
return true
}
})
}
}


/**
* Using the addMenuProvider() API in a Fragment
**/
class ExampleFragment : Fragment() {


override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// The usage of an interface lets you inject your own implementation
val menuHost: MenuHost = requireActivity()
  

// Add menu items without using the Fragment Menu APIs
// Note how we can tie the MenuProvider to the viewLifecycleOwner
// and an optional Lifecycle.State (here, RESUMED) to indicate when
// the menu should be visible
menuHost.addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
// Add menu items here
menuInflater.inflate(R.menu.example_menu, menu)
}


override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Handle the menu selection
return true
}
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
}

这是参考链接

啊,对于像我这样懒惰的人,你必须加上这个:

dependencies {
val activity_version = "1.5.1"


// Java language implementation
implementation("androidx.activity:activity:$activity_version")
// Kotlin
implementation("androidx.activity:activity-ktx:$activity_version")
}