Фрагмент, не получающий обратные вызовы меню

У меня есть класс фрагмента, который расширяет Fragment и вызывает setHasOptionsMenu для участия в меню. Этот класс также реализует onCreateOptionsMenu, onPrepareOptionsMenu и onOptionsItemSelected.

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

Я динамически загружаю этот фрагмент с помощью FragmentTransaction в моей Activity (который расширяет FragmentActivity).

Однако ни один из обратных вызовов меню (onCreateOptionsMenu, onPrepareOptionsMenu и onOptionsItemSelected) не вызывается (я отлаживал некоторые точки останова в этих методах), и меню не отображается.

Я что-то упустил? Нужно ли добавлять что-то в свою деятельность?

Я использую библиотеку совместимости Android, компилирую ее с помощью L11 SDK и тестируя в Xoom.

EDIT. Я нашел проблему. Мой AndroidManifest нацелен на L11, это, похоже, скрывает кнопку меню и предотвращает вызов вызываемых вызовов. Однако, если я удалю это из манифеста, я потеряю некоторые другие функции, которые мне нужны (например, активированное состояние в списках). Кто-нибудь знает, как решить эту проблему (включить кнопку меню), не удаляя targetSdkVersion=11 из манифеста?

Ответ 1

Я нашел проблему. AndroidManifest настроен на SDK 11, похоже, скрывает кнопку меню и предотвращает вызов вызываемых вызовов. Я предполагаю, что это нарушает совместимость кнопки меню, которая, кажется, заменяется панелью действий в Android 3.0

Ответ 2

Aromero, Не забудьте переопределить onCreateOptionsMenu, используя версию фрагмента метода, похожую на это:

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

Это относится к фрагменту, кстати, и добавляет в завышенное меню Activity, если таковой есть. У меня была та же проблема, пока я не понял это.

Ким

Ответ 3

Если у вас возникла эта проблема с ActionBarSherlock, вы должны убедиться, что ваши фрагменты - это фразы "Шерлок", а не просто файлы поддержки, и что вы переопределяете

public void onPrepareOptionsMenu (com.actionbarsherlock.view.Menu menu) {

НЕ

public void onPrepareOptionsMenu (android.view.Menu menu) {

Если вы делаете последнее, вы должны получить предупреждение о том, что функция является окончательной, и вы не можете ее переопределить. Это предупреждение о том, что вы пытаетесь переопределить неправильную функцию!

Если вы исправите ошибку, переключив класс из SherlockFragment на простой фрагмент, вы можете создать эту функцию., но он не будет вызван.

Ответ 4

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

  • Добавьте метод setHasOptionsMenu (true) в метод Fragment onCreate(Bundle savedInstanceState).

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

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

Пример:

активность

@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) {
    // Do something that differs the Activity 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;
}

Я надеюсь, что это будет полезно.

Приветствия.

Ответ 5

Если у вас есть активность и фрагмент, каждый из которых загружает элементы меню, вам необходимо особо следить за тем, какие переопределения вы используете.

Действия могут переопределять onOptionsItemSelected и onMenuItemSelected, однако фрагменты могут переопределять только onOptionsItemSelected.

Если вы переопределите onMenuItemSelected в своей деятельности и onOptionsItemSelected в своем фрагменте, переопределение фрагмента никогда не будет запущено.

Вместо этого используйте onOptionsItemSelected как в действии, так и в фрагменте.

Ответ 6

Вам нужно убедиться, что вы вызываете setHasOptionsMenu(true); onCreate или onCreateView вызывается в вашем фрагменте.

Вам также необходимо реализовать переопределение onCreateOptionsMenu внутри вашего фрагмента.

Ответ 7

Другим возможным случаем является использование общего идентификатора для общего действия в каждом фрагменте; например, R.id.action_add

Сегодня у меня была такая ситуация: попадание в меню опций [add] было вызвано "неправильным" onOptionItemSelected, потому что каждый фрагмент (замененный динамически с помощью DrawerLayout) имел тот же R.id.action_add.

Рассказ, если у вас есть такая ситуация, всегда проверяйте, что ваш фрагмент виден:

if (!isVisible()) return false;

Длинная история, обратите внимание на цепочку onOptionItemSelected!

  MainActivity
       |
       |  onOptionItemSelected
       +-----------------------
       |     return false
       |
 MyCoolFragment1
       |
       |  onOptionItemSelected
       +-----------------------
       |     return false
       |
 MyCoolFragment2
       |
       |  onOptionItemSelected
       +-----------------------
       |     return true
       |
[item selection handled]

Если вы добавляете свои фрагменты с помощью (что-то вроде этого):

getSupportFragmentManager()
   .beginTransaction()
   .replace(R.id.content_frame, MyCoolFragment1.newInstance())
   .commit() 

и вы определили один и тот же идентификатор для общего действия (скажем, R.id.action_add) в каждом фрагменте; не забудьте добавить эту строку к каждому: if (! isVisible()) возвращает false;

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (!isVisible()) return false; // <-- Not visible? skip!

    if (item.getItemId() == R.id.action_add) {
        //.TODO whatever
        return true;  //.Handled!
    }

    return false; //.Skip
}

Ответ 8

У меня была эта проблема, когда я использовал ViewPagerIndicator в сочетании с ActionBarSherlock. Хотя оказалось, что это было fixed Я все еще столкнулся с проблемой. Работа, которую я нашел, заключалась в том, чтобы вручную вызвать фрагмент.

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    Toast.makeText(this, "From activity", Toast.LENGTH_SHORT).show(); // TODO
    Fragment currentFragment = mAdapter.getItem(mPager.getCurrentItem());
    if (currentFragment != null && currentFragment instanceof SherlockFragment)
    {
        ((SherlockFragment)currentFragment).onOptionsItemSelected(item);
    }
    return super.onOptionsItemSelected(item);

}

Ответ 9

Я думаю, что вы реализовали onCreateOptionsMenu, onPrepareOptionsMenu и onOptionsItemSelected в классе, который extends Fragment. Попробуйте сделать это в своем классе Activity, где вы загружаете этот фрагмент

Ответ 10

С сайта разработчика Android - ссылка

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

Поэтому Marco HC - лучший ответ.

Ответ 11

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

  • Удалить или прокомментировать любые onOptionsItemSelected(), onMenuItemSelected() даже onPrepareOptionMenu() и оставить только в Activity onCreateOptionsMenu():

    @Override
    public boolean onCreateOptionsMenu(Menu menu){
    MenuInflater inflater=getMenuInflater();
    inflater.inflate(R.layout.menu, menu);
    return true;
    }
    
  • В классе Fragment, в onCreateView(), поставьте:

    setHasOptionsMenu(true);
    
  • В классе Fragment добавьте:

    @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
     super.onCreateOptionsMenu(menu,inflater);      
     }
    
    @Override
     public boolean onOptionsItemSelected(MenuItem item){           
             switch(item.getItemId()){
             case R.id.action_insert:
                //doing stuff
             return true;
             }
             return false;
         }
    

Протестировано и работает на Android 4.4

Ответ 12

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

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    ....
    Toolbar toolbar = (Toolbar)getActivity().findViewById(R.id.toolbar);
    ((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
    setHasOptionsMenu(true);
}

И затем, конечно, переопределить onCreateOptionsMenu, как показано ниже

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

Это единственное решение, которое сработало для меня!