片段中的Android选项菜单

时间:2011-11-29 09:48:14

标签: android android-fragments android-optionsmenu

我正在尝试从一组片段中将选项添加到选项菜单中。

我创建了一个新的MenuFragment类,并为我希望包含菜单项的片段扩展了这个。这是代码:

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

出于某种原因,onCreateOptionsMenu似乎无法运行。

21 个答案:

答案 0 :(得分:564)

调用超级方法:

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

在代码中放置日志语句,以查看是否未调用该方法,或者代码是否未修改该菜单。

同时确保您在SetHasOptionsMenu中调用onCreate来通知片段它应该参与选项菜单处理。

答案 1 :(得分:185)

我遇到了同样的问题,但我认为最好总结一下并介绍最后一步让它运转起来:

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

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

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

  4. 一个例子:

    <强> 活动

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

答案 2 :(得分:152)

如果您发现未调用onCreateOptionsMenu(Menu menu, MenuInflater inflater)方法,请务必从Fragment的onCreate(Bundle savedInstanceState)方法中调用以下内容:

setHasOptionsMenu(true)

答案 3 :(得分:50)

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

<强>片段

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>

答案 4 :(得分:23)

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

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

}

答案 5 :(得分:16)

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

答案 6 :(得分:11)

TL; DR

使用android.support.v7.widget.Toolbar并执行以下操作:

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

独立工具栏

大多数建议的解决方案,例如setHasOptionsMenu(true)仅在父活动的布局中具有工具栏并通过setSupportActionBar()声明时才有效。然后,片段可以参与此确切的 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.Fragmentandroid.support.v7.widget.Toolbar(还请确保在AppCompatActivity中使用AppCompatstyles.xml主题)。 / p>

答案 7 :(得分:9)

就我而言,这是步骤。

步骤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);
}

答案 8 :(得分:7)

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

答案 9 :(得分:7)

如果您想添加菜单自定义

@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 :(得分:3)

菜单文件:

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

答案 11 :(得分:3)

你的代码很好。方法中只缺少超级:

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

答案 12 :(得分:2)

我变得疯狂,因为这里没有任何答案对我有用。

要显示我必须致电的菜单: setSupportActionBar(toolbar)

完成!

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

希望这个答案可以帮助你。

答案 13 :(得分:1)

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

    /**
     * Array adapter for main vendor listview
     */
    private class VendorMainListAdapter extends ArrayAdapter<String> {

        ArrayList<String> VendorNameArrayList = new ArrayList<String>();

        private Activity activity;
        public VendorMainListAdapter(Activity a, int resource, ArrayList<String> VendorNameArrayList) {
            super(a, resource, VendorNameArrayList);

            activity = a;
            this.VendorNameArrayList = VendorNameArrayList;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            final View row = inflater.inflate(R.layout.activity_vendor_list_item, parent, false);

            final TextView tvVendorName=(TextView)row.findViewById(R.id.tvVendorNames);
            final GridView gvCakeList=(GridView) row.findViewById(R.id.gvCakeList);
            tvVendorName.setText(VendorNameArrayList.get(position));

             int size=CakeNameArrayList.size();
            // Calculated single Item Layout Width for each grid element ....
            int width = 150 ;

            DisplayMetrics dm = new DisplayMetrics();
            HomeScreen.this.getWindowManager().getDefaultDisplay().getMetrics(dm);
            float density = dm.density;

            int totalWidth = (int) (width * size * density);
            singleItemWidth = (int) (width * density);

            int height= 100;
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    totalWidth, singleItemWidth);

            gvCakeList.setLayoutParams(params);
            gvCakeList.setColumnWidth(singleItemWidth);

            gvCakeList.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
            gvCakeList.setNumColumns(size);

            gvCakeList.setHorizontalSpacing(10);

//Here I have set the adapter for the gridview 

            gvCakeList.setAdapter(new CakeListGridViewAdapter(HomeScreen.this,CakeIdArrayList,CakeNameArrayList,
                    CakePriceArrayList,CakePicArrayList));
            gvCakeList.setSelection(mSelected);

//this is the onitemclicklistener for this gridview

            gvCakeList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                    Log.e("item clicked ", String.valueOf(i));
                }
            });

            row.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.e("oops","you clicked parent");
                }
            });
            return row;

        }

    }

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

<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" />

现在只需在片段类

中设置菜单xml文件
implement SearchView.OnQueryTextListener    in your fragment class



@Override
 public void onViewCreated(View view, Bundle savedInstanceState) {    
  super.onViewCreated(view, savedInstanceState);
  setHasOptionsMenu(true);

}

答案 14 :(得分:1)

我要补充一点,以及它不适合我的原因。

这与Napster的答案相似。

  1. 确保您的片段的托管活动延伸AppCompatActivity,而不是FragmentActivity

    public class MainActivity extends AppCompatActivity {
    
    }
    

    从FragmentActivity的Google参考Documentation

      

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

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

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

  4. 注意:android.support.v7.app.AppCompatActivityandroid.support.v4.app.FragmentActivity类的子类(请参阅AppCompatActivity参考文档)。

答案 15 :(得分:1)

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

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

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

答案 16 :(得分:1)

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

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

答案 17 :(得分:0)

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

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

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

答案 18 :(得分:0)

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

答案 19 :(得分:0)

如果应用程序的主题带有setHasMenuOptions(true),例如Actionbar,则

Set Theme.MaterialComponents.DayNight.DarkActionBar是有效的,或者Activity具有它自己的工具栏,否则片段中的onCreateOptionsMenu不会被调用

如果您想使用独立的工具栏,则需要激活并通过以下方式将工具栏设置为支持操作栏:

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

这将使您的片段onCreateOptionsMenu被调用。

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

扩展项目监听器
toolbar.setOnMenuItemClickListener {
   // do something
   true
}

答案 20 :(得分:0)

这是我分别在加载和销毁片段时隐藏和取消隐藏所有菜单选项的操作。它消除了将 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()
}