(Не рекомендуется) Фрагмент onOptionsItemSelected не вызывается

82

РЕДАКТИРОВАТЬ: этот вопрос был для устаревшей панели действий sherlock. Вместо этого теперь следует использовать библиотеку поддержки Android

Я добавил пункт меню панели действий под названием поделиться для моего fragment которая появляется, но событие выбора не перехватывается

Я добавляю это вот так

@Override
public void onCreateOptionsMenu (Menu menu, MenuInflater inflater) {
    MenuItem item = menu.add(0, 7,0, R.string.share);
    item.setIcon(R.drawable.social_share).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}

Пытаюсь запечатлеть это как в том, так fragmentи в fragment activityподобном

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case 7:
            Intent share = new Intent(Intent.ACTION_SEND);
            share.setType("text/plain");
            share.putExtra(Intent.EXTRA_TEXT, "I'm being sent!!");
            startActivity(Intent.createChooser(share, "Share Text"));
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

а у меня setHasOptionsMenu(true);в onCreate().

user1634451
источник

Ответы:

145

У меня были такие же проблемы:

События onMenuItemSelected не вызывались во фрагменте

Поиск в Google не может найти решение, и добавление метода onMenuItemSelected в FragmentActivity не решает его.

Наконец, разрешите его, следуя ссылке на http://developer.android.com/guide/topics/ui/actionbar.html.

Примечание. Если вы добавили элемент меню из фрагмента с помощью обратного вызова onCreateOptionsMenu класса Fragment, то система вызывает соответствующий метод onOptionsItemSelected () для этого фрагмента, когда пользователь выбирает один из элементов фрагмента. Однако действие получает возможность сначала обработать событие, поэтому система вызывает onOptionsItemSelected () для действия перед вызовом того же обратного вызова для фрагмента.

Это означает, что только если у вас нет этого обработчика пунктов меню в onOptionsItemSelected () для действия, будет вызываться onOptionsItemSelected () для фрагмента.

Используйте следующий код ----- Удалите обработчик R.action.add на FragmentActivity):

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case android.R.id.home:
            popBackStack();             
            return true;        
        case R.id.action_search:
            searchAction();
            return true;
        case R.id.action_logout:
            userLogout();
            return true;
        //case R.id.action_add:
            //return true;    
        default:
            return super.onOptionsItemSelected(item);
    }   
}

А обработчик R.action.add on Fragment выглядит так:

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    Log.d("onOptionsItemSelected","yes");
    switch (item.getItemId()) {
        case R.id.action_add:
            add();
            return true;    
        default:
            return super.onOptionsItemSelected(item);
    }
}

Наконец, не забудьте добавить

    setHasOptionsMenu(true);

в вашем методе onCreate во фрагменте

Felixqk
источник
12
Для меня, чтобы перехватить щелчок меню по фрагменту, мне пришлось вернуть «false» для onOptionsItemSelected из FragmentActivity и для onOptionsItemSelected фрагмента, выполнить желаемое поведение.
Эдисон Сантос
1
фрагмент с setHasOptionsMenu (true); в onCreate и общедоступном логическом методе onOptionsItemSelected (MenuItem item) {} творили чудеса
Моисес
@Felixqk У меня такая проблема с фрагментами. У меня есть два фрагмента. Но OnOptionsSelectedItem фрагмента 2 не вызывается. Фрагмент 2 показывает пункт меню фрагмента 1.
Roon13
@ Roon13 Удалите super.onCreateOptionsMenu; из фрагмента onCreateOptionsMenu. + setHasOptionsMenu (правда); работал у меня, не удаляя Activity onOptionsItemSelected.
ahmadalibaloch
129

У меня была та же проблема, но я думаю, что лучше подвести итог и представить последний шаг, чтобы он заработал:

  1. Добавьте setHasOptionsMenu(true)метод в свой onCreate(Bundle savedInstanceState)метод фрагмента .

  2. Переопределение onCreateOptionsMenu(Menu menu, MenuInflater inflater)(если вы хотите сделать что-то другое в меню своего фрагмента) и onOptionsItemSelected(MenuItem item)методы в своем фрагменте.

  3. Внутри onOptionsItemSelected(MenuItem item)метода Activity убедитесь, что вы вернулись, falseкогда действие пункта меню будет реализовано в onOptionsItemSelected(MenuItem item)методе Fragment .

Пример:

Деятельность

@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;
}
Марко ХК
источник
6
return falseна Activity onOptionItemSelected- это ключ. просто заменитеreturn super.onOptionItemSelected(item);
Ёнджэ
1
Работает отлично. Спасибо, Марко.
Rajeev Sahu
2
Отличный ответ. Вы должны изменить onCreateOptionsMenu (меню меню) на onCreateOptionsMenu (меню меню, надувание MenuInflater), когда оно находится во фрагменте
Крис Спраг
1
Отличное решение. Thnakx Marco HC
Дарш Патель
1
Отличное решение дружище! Спасибо!
Хан Тран
5

Я заметил, что решение, которое вам дали люди, заключалось в том, чтобы реализовать код для вашего элемента меню в действии, а не во фрагменте. Я думаю, что это будет выглядеть намного более организованным, если вы внедрили код во фрагмент, а не в действие, потому что, на мой взгляд, это выглядит лучше. Для этого сделайте следующее:

Деятельность

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu, menu);      
        return true;
    }

 @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {            
        switch (item.getItemId())
        {
            case R.id.SomeIDInTheMenueOfTheActivity:
            {
               //something();
                break;
            }
            default:
             //do something default and add the code under : 
             return super.onOptionsItemSelected(item);
        }
        return true;
    }

Фрагмент

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

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

     @Override
        public boolean onOptionsItemSelected(MenuItem item)
        {
            switch (item.getItemId())
            {           
                case R.id.SomeIDInFragmentMenue:
                {             
                    break;
                }

                default:
                    return super.onOptionsItemSelected(item);
            }

            return true;
        }

Теперь строки (и тому подобное): «return super.onOptionsItemSelected (item);» в действии и фрагменте очень важны, потому что, как если бы вы следовали коду при отладке, вы увидите, что функции событий меню будут вызываться сначала в действии, и если элемент не соответствует идентификатору в переключателе действия - case, строка с ошибкой: "super.onOptionsItemSelected (item);" вызовет функцию onOptionsItemSelected для фрагмента, как мы и хотели. (если у вас много фрагментов, убедитесь, что в них тоже есть эта строка, так как вызов hirarchy может быть несколько сложным).

Malfonde
источник
2

Я использую actionbarsherlock. Это сработало для меня:

1) Создайте меню dummy_menu.xml

<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="match_parent" android:layout_width="fill_parent" >
<item
      android:title=""
      android:showAsAction="never"
      android:id="@+id/dummyMenu"
        />

2) В действии раздуйте меню так:

@Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
    com.actionbarsherlock.view.MenuInflater inflater = getSupportMenuInflater();
   inflater.inflate(R.menu.dummy_menu,menu);
   return super.onCreateOptionsMenu(menu);
}

3) Во фрагментах onCreateView вызовите setHasOptionsMenu (true) и переопределите onCreateOptionsMenu и onOptionsItemSelected, также скройте подобное dummyMenu (во фрагменте)

    @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.fragment_actions, menu);
    MenuItem item = menu.findItem(R.id.dummyMenu);
    item.setVisible(false);
    super.onCreateOptionsMenu(menu, inflater);
}

Надеюсь, это кому-то поможет.

оккко
источник
2

Редактировать для использования Шерлока на панели действий

Мне пришлось использовать

public boolean onMenuItemSelected(int featureId, MenuItem item) {

в основном действии, чтобы захватить пункт меню

user1634451
источник
Та же проблема, и она исправлена ​​для меня, спасибо. Вы можете сказать, почему onOptionItemSelected не работал?
nadeem gc 07
Потому что панель действий sherlock не использует этот метод
user1634451
Измените onMenuItemSelected на вызов onOptionItemSelected, чтобы ваш код работал при переходе от ABS к appcompatlib
slott
1
@nadeemgc причина, по которой это не работает, заключается в том, что Android знает о двух типах меню: меню параметров и контекстное меню. Панель действий Шерлок использует контекстное меню, которое вызываетonContextItemSelected вместо onOptionsItemSelected. onMenuItemSelectedПросто пересылает нажмите на правильный метод, поэтому он , как представляется , лучше работать.
Амру Э.
@ Амру. Спасибо, будет полезно в будущем.
nadeem gc 01
2

это настолько просто, что вы можете сделать это в своем фрагменте, чтобы убедиться, что ваше действие будет правильно прослушиваться:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}
Мохамед Хуссиен
источник
0

У меня была такая проблема. Это потому, что я игнорировал неправильный метод

onOptionsItemSelected (элемент com.actionbarsherlock.view.MenuItem) - это то, что я использовал.

Убедитесь, что вы используете правильный!

Барри Галицки
источник
0

Вы не связываетесь с суперклассом в методах действия. Пожалуйста, пусть onCreateOptionsMenu () возвращает super.onCreateOptionsMenu (меню), а onOptionsItemSelected () возвращает super.onOptionsItemSelected (item) (за исключением обрабатываемого вами элемента, который должен возвращать true, чтобы указать, что вы обработали событие)

Дивеш В. Мурани
источник
0

вы должны добавить этот код в toolbar.bringToFront();следующую панель инструментов в своей деятельности

 public class MainActivity extends AppCompatActivity {
     protected void onCreate(Bundle savedInstanceState) {
        ...

        Toolbar toolbar = findViewById(R.id.toolbar);
        toolbar.setTitle("Yazd");
        setSupportActionBar(toolbar);
        toolbar.bringToFront(); // <<= add here
         ...
Махди Афхами
источник