Cách thêm Menu Tùy chọn vào Fragment trong Android


399

Tôi đang cố gắng thêm một mục vào menu tùy chọn từ một nhóm các mảnh.

Tôi đã tạo một MenuFragmentlớp mới và mở rộng lớp này cho các đoạn tôi muốn đưa vào mục menu. Đây là đoạn mã:

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

Kotlin:

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

Đối với một số lý do onCreateOptionsMenuxuất hiện không chạy.


có lẽ là một câu hỏi ngớ ngẩn ... bạn nhấn nút menu phải không?
Ovidiu Latcu

2
..lol ... vâng, tôi đã nhấn nút menu, tôi cũng đã thử nó có và không có: fav.setShowAsAction (MenuItem.SHOW_AS_ACTION_ALWAYS);
misterbassman

Hi, có lẽ này chủ đề sẽ giúp bạn hoặc kiểm tra các bản demo api cho một ví dụ làm việc.
kameny

Câu trả lời:


605

Gọi siêu phương thức:

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

Kotlin:

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

Đặt các câu lệnh log trong mã để xem nếu phương thức không được gọi hoặc nếu menu không được sửa đổi bởi mã của bạn.

Cũng đảm bảo bạn đang gọi setHasOptionsMenu(boolean)trong onCreate(Bundle)thông báo cho mảnh rằng nó nên tham gia vào việc xử lý đơn tùy chọn.


2
Cảm ơn sự giúp đỡ, tôi đã thêm siêu phương thức và nhận ra rằng tôi đã xóa @Override nên đã thêm lại vào đây, nhật thực đã gây ra lỗi nên tôi đã thay thế MenuInflater để nhập android.view.MothyInflater; thay vì nhập android.support.v4.view.MothyInflater; và bây giờ tất cả đang hoạt động
misterbassman

183
không gọi setHasOptionsMothy (đúng) trong onCreate của Fragment đã nhận được tôi hai lần bây giờ
joshkendrick

7
Tôi đã chuyển Hoạt động của mình sang Mảnh vỡ và gặp phải vấn đề này. Chữ ký phương thức đã thay đổi từ boolean công khai sang void công khai và các đối số cũng đã thay đổi. Hãy chắc chắn để lưu ý về điều này!
bạn786

14
Lưu ý rằng Fragment.onCreateOptionsMothy (Menu, MenuInflater) là một phương thức trống, vì vậy việc gọi siêu là hoàn toàn không cần thiết. Lỗi duy nhất ở đây là chữ ký phương thức sai và có thể là một tập hợp bị thiếuHasOptionsMothy () trong onCreate ()
cmende 17/07/13

6
Thay thế super.onCreateOptionsMothy bằng Inflater.inflate (R.menu.menu_custom, menu);
Code_Worm

197

Tôi đã có cùng một vấn đề, nhưng tôi nghĩ tốt hơn là tóm tắt và giới thiệu bước cuối cùng để làm cho nó hoạt động:

  1. Thêm phương thức setHasOptionsMothy (true) trong phương thức Fragment của bạn onCreate(Bundle savedInstanceState).

  2. Ghi đè onCreateOptionsMenu(Menu menu, MenuInflater inflater)(nếu bạn muốn làm một cái gì đó khác trong menu của Fragment) và onOptionsItemSelected(MenuItem item)các phương thức trong Fragment của bạn.

  3. Trong onOptionsItemSelected(MenuItem item)phương thức Activity của bạn , đảm bảo bạn trả về false khi hành động của mục menu sẽ được thực hiện theo onOptionsItemSelected(MenuItem item)phương thức của Fragment.

Một ví dụ:

Hoạt động

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

Miếng

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
Vừa mất tích setHasOptionsMenu(true);Cảm ơn
Chad Bingham

1
Trên viewPager trên một số thiết bị, menu chỉ được hiển thị lần thứ hai khi bạn đi đến đoạn
Roel

3
@Marco HC mã của bạn hoạt động tốt. Nhưng nếu tôi muốn ẩn một số menu cho Activity hoặc cho Fragment thì sao? Bạn đã đề cập về nơi thực hiện menu tùy chọn nào (Trong hoạt động và đoạn). Nhưng nếu tôi muốn ẩn một số menu thì sao?
Shreyash Mahajan 1/03/2015

@iDroidExplorer chỉ cần giữ một tham chiếu đến MenuItem đó và đặt chế độ hiển thị thành biến mất hoặc vô hình. Đó là câu hỏi của bạn?
Marco HC

@iDroidExplorer Tôi đã thử mã của anh ấy và tôi không biết làm thế nào nhưng nó tự động ẩn menu khi tôi chuyển sang các đoạn khác.
Noor Ali Mông

156

Nếu bạn thấy onCreateOptionsMenu(Menu menu, MenuInflater inflater)phương thức không được gọi, hãy đảm bảo bạn gọi các onCreate(Bundle savedInstanceState)phương thức sau từ phương thức của Fragment :

setHasOptionsMenu(true)

Nó mang đến cho tôi Lỗi như NullPulumException
Pratik Butani

2
Điểm tốt. Tôi đã gọi phương thức setHasOptionMothy từ phương thức newInstance tĩnh. Vì tôi chỉ đính kèm đoạn của mình khi được lưuInstanceState là null, khi cấu hình màn hình thay đổi, menu sẽ không được tạo. Phương thức onCreate của đoạn là vị trí chính xác để đặt setHasOptionMothy thành true.
argenkiwi

1
Tôi đang sử dụng một Toolbarvà phải gọi setHasOptionsMenu(true)vào để onCreateView()thay thế onCreate().
ĐÁM MÂY 19/8/2016

60

Nếu bạn cần menulàm mới một webviewbên trong cụ thể Fragment, bạn có thể sử dụng:

Mảnh vỡ :

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>

31

TL; DR

Sử dụng android.support.v7.widget.Toolbarvà chỉ cần làm:

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

Thanh công cụ độc lập

Hầu hết các giải pháp được đề xuất như setHasOptionsMenu(true)chỉ hoạt động khi Activity gốc có Thanh công cụ trong bố cục của nó và khai báo nó thông qua setSupportActionBar(). Sau đó, các mảnh vỡ có thể tham gia vào nhóm thực đơn của ActionBar chính xác này :

Fragment.onCreateOptionsMothy (): Khởi tạo nội dung của menu tùy chọn tiêu chuẩn của máy chủ Fragment.

Nếu bạn muốn một thanh công cụ độc lập và menu cho một Fragment cụ thể bạn có thể làm như sau:

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

Vâng, nó thật dễ dàng. Bạn thậm chí không cần ghi đè onCreate()hoặconCreateOptionsMenu() .

PS: Điều này chỉ hoạt động với android.support.v4.app.Fragmentandroid.support.v7.widget.Toolbar(cũng chắc chắn sử dụng AppCompatActivityvà một AppCompatchủ đề trong của bạn styles.xml).


1
thực sự đã giúp tôi rất nhiều
adigopula brahmy

23

Trong menu.xmlbạn nên thêm tất cả các mục menu. Sau đó, bạn có thể ẩn các mục mà bạn không muốn thấy trong lần tải đầu tiên.

menu.xml

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

Thêm setHasOptionsMenu(true)vào phương thức onCreate () để gọi các mục menu trong lớp Fragment của bạn.

FragmentClass.java

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

Bạn không cần phải ghi đè onCreateOptionsMenutrong lớp Fragment của mình một lần nữa. Các mục menu có thể được thay đổi (Thêm / xóa) bằng onPrepareOptionsMenuphương thức ghi đè có sẵn trong Fragment.

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

}

16

Bạn cần sử dụng menu.clear () trước khi tăng các menu.

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

1
Điều này là chính xác khi bạn muốn các menu khác nhau trong các mảnh khác nhau và bạn đang thêm các mảnh thay vì thay thế chúng.
Akshay Mahajan

Cảm ơn bạn! menu.clear () giúp tôi loại bỏ tùy chọn menu của Activity.
kimcy929

13

Trong trường hợp của tôi, đây là các bước.

Bước 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);
}

Bước 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);
}

Bước 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);
}

Tôi đã có menu trên hoạt động chính, sử dụng menu.clear()menu đã xóa trước đó. Làm việc cho tôi :)
Anbuselvan Rocky

8

Nếu bạn muốn thêm menu tùy chỉnh

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

Điều gì xảy ra nếu có chế độ xem tab và bạn muốn tăng các menu khác nhau cho mỗi phân đoạn?
Jainam Jhaveri

7

Tôi đã có cùng một vấn đề, các mảnh của tôi là các trang của ViewPager. Lý do nó đã xảy ra là tôi đã sử dụng trình quản lý phân đoạn con chứ không phải trình quản lý phân đoạn hỗ trợ hoạt động khi khởi tạo FragmentPagerAd CHƯƠNG.


3

Tập tin thực đơn:

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

Mã hoạt động:

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

Mã phân đoạn:

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

3

Mã của bạn là tốt. Chỉ có siêu bị thiếu trong phương thức:

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

2

Tôi đã phát điên vì không có câu trả lời nào ở đây làm việc cho tôi.

Để hiển thị menu tôi đã phải gọi: setSupportActionBar(toolbar)

Làm xong!

Lưu ý: nếu toolbarchế độ xem của bạn không có cùng bố cục hoạt động, bạn không thể sử dụng cuộc gọi ở trên trực tiếp từ lớp hoạt động của mình, trong trường hợp này, bạn sẽ cần nhận hoạt động đó từ lớp phân đoạn của mình và sau đó gọi chosetSupportActionBar(toolbar) . Ghi nhớ: lớp hoạt động của bạn sẽ mở rộng AppCompatActivity.

Mong rằng câu trả lời này sẽ giúp bạn.


1

Đặt menu tùy chọn sau khi tạo chế độ xem phân đoạn hoạt động tốt với tôi.

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

1

Vấn đề của tôi hơi khác một chút. Tôi đã làm mọi thứ đúng. Nhưng tôi đã kế thừa lớp sai cho hoạt động lưu trữ đoạn.

Vì vậy, để rõ ràng, nếu bạn đang ghi đè onCreateOptionsMenu(Menu menu, MenuInflater inflater)vào đoạn, hãy đảm bảo lớp hoạt động của bạn lưu trữ đoạn này kế thừaandroid.support.v7.app.ActionBarActivity (trong trường hợp bạn muốn hỗ trợ dưới API cấp 11).

Tôi đã kế thừa android.support.v4.app.FragmentActivitymức API hỗ trợ dưới 11.


1

Một điều tôi sẽ thêm vào điều này và lý do nó không làm việc cho tôi.

Nó tương tự như câu trả lời của Napster.

  1. Hãy chắc chắn rằng hoạt động lưu trữ của mảnh của bạn kéo dài AppCompatActivity, không FragmentActivity!

    public class MainActivity extends AppCompatActivity {
    
    }

    Từ Tài liệu tham khảo của Google cho FragmentActivity:

    Lưu ý: Nếu bạn muốn triển khai một hoạt động bao gồm một thanh hành động, thay vào đó, bạn nên sử dụng lớp ActionBarActivity, một lớp con của hoạt động này, vì vậy cho phép bạn sử dụng API Fragment trên API cấp 7 trở lên.

  2. Để cập nhật câu trả lời của Napster - ActionBarActivityhiện không được chấp nhận, AppCompatActivitythay vào đó hãy sử dụng .

  3. Khi sử dụng AppCompatActivity, cũng đảm bảo bạn đặt "chủ đề hoạt động thành Theme.AppCompathoặc một chủ đề tương tự" (Google Doc).

Lưu ý: android.support.v7.app.AppCompatActivitylà một lớp con của android.support.v4.app.FragmentActivitylớp (xem tài liệu tham khảo AppCompatActivity ).


1

Trong thư mục menu của bạn tạo một tệp .menu xml và thêm xml này

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

Trong lớp phân đoạn của bạn giám sát phương thức này và

implement SearchView.OnQueryTextListener    in your fragment class



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

}

Bây giờ chỉ cần thiết lập tệp xml trình đơn của bạn trong lớp phân đoạn

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

}

0

Nếu tất cả các cách trên không hoạt động, bạn cần gỡ lỗi và đảm bảo chức năng onCreateOptionsMothy đã được gọi (bằng cách đặt gỡ lỗi hoặc ghi nhật ký ...)

Nếu nó không chạy, có thể chủ đề Android của bạn không hỗ trợ thanh hành động. Mở AndroidManifest.xml và đặt giá trị cho android:themevới thanh hành động hỗ trợ chủ đề :

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

0

trên phương thức onCreate của bạn, hãy thêm setHasOptionMothy ()

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

Sau đó ghi đè onCreateOptionsMothy của bạn

@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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.