Неверный fragment в ViewPager получает onContextItemВыбранный вызов
У меня есть приложение, которое показывает несколько fragmentов (одного типа) в ViewPager
и у меня возникают проблемы с элементами контекстного меню. (Я использую библиотеку поддержки).
Когда в контекстном меню в одном из fragmentов выбирается элемент контекстного меню, неправильный fragment получает onContextItemSelected
события onContextItemSelected
.
Например, если я нахожусь на fragmentе № 3 в пейджере, вместо этого вместо него принимает fragment в позиции # 2. Если я вернусь к fragmentу № 2, вместо этого вместо этого вместо этого получит номер # 3.
- Удалить метки BottomNavigationView
- Есть ли причина использовать библиотеку support.v4 в Android?
- Как работает Android Support Library?
- java.lang.NoClassDefFoundError: android / graphics / drawable / Icon
- Ошибка поддержки библиотеки Android после обновления до 23.3.0
У меня есть образец здесь .
(В настоящее время я работаю над этим в своем приложении, имея переменную mHandleContext
в каждом fragmentе и mHandleContext
/ отключая ее при изменении страницы. Таким образом, вызов onContextItemSelected
будет выходить на все fragmentы до тех пор, пока не будет вызван правый. )
Я что-то делаю неправильно или это ошибка в библиотеке поддержки? В качестве побочной заметки этого не произошло, когда я использовал ActionBarSherlock 3.5.1, у которого была собственная вилка библиотеки поддержки.
- Проблемы с рендерингом в Android Studio v 1.1 / 1.2
- Обновление библиотеки поддержки 23.2.0 build bug
- Строка состояния становится белой и не отображает содержимое за ней
- Разрешенные версии для приложения (22.0.0) и тестового приложения (21.0.3) отличаются
- Навигационная система взломана на JellyBean?
- Обновление библиотеки поддержки Android до 23.2.0 вызывает ошибку: XmlPullParserException Бинарная строка XML-файла # 17 требует viewportWidth> 0
- Как получить позицию, выбранную в RecyclerView?
- Ошибка Android - вызвана: java.lang.NoClassDefFoundError: android.support.v4.util.SparseArrayCompat
Так что это какое-то идиотское дизайнерское решение от Google или что-то, что просто совсем не считалось. Самый простой способ обойти это – обернуть вызов onContextItemSelected
с помощью оператора if:
if (getUserVisibleHint()) { // Handle menu events and return true } else return false; // Pass the event to the next fragment
В библиотеке совместимости в ActionBarSherlock 3.5 был такой хак.
Это происходит из-за этого:
public boolean dispatchContextItemSelected(MenuItem item) { if (mActive != null) { for (int i=0; i
Как вы можете видеть, FragmentManager вызывает Fragment.onContextItemSelected для всех своих собственных fragmentов, пока не вернет true. В вашем примере я могу предложить такое исправление:
public static class TestListFragment extends ListFragment { private int mNumber = 0; private ArrayList mItems; public static TestListFragment newInstance(int number) { Bundle args = new Bundle(); args.putInt("number", number + 1); TestListFragment fragment = new TestListFragment(); fragment.setArguments(args); return fragment; } public TestListFragment() {} @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mNumber = getArguments().getInt("number"); mItems = new ArrayList (); mItems.add("I am list #" + mNumber); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setListAdapter(new ArrayAdapter (getActivity(), android.R.layout.simple_list_item_1, mItems)); registerForContextMenu(getListView()); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.add(mNumber, 0, 0, "Hello, World!"); } @Override public boolean onContextItemSelected(MenuItem item) { if(item.getGroupId() == mNumber){ Log.d("ViewPagerContextMenuBug", "onContextItemSelected called for number " + mNumber); Toast.makeText(getActivity(), "onContextItemSelected called for number " + mNumber, Toast.LENGTH_SHORT).show(); return true; } return false; } }
О, Google, я имею в виду WTF?
Проблема в том, что onContextItemSelected очень общий, и он вызывается для каждого пункта меню каждого fragmentа.
Вы можете использовать MenuItem.OnMenuItemClickListener, чтобы заставить меню fragmentа не использовать все onContextItemSelected , но только ту же функцию этого fragmentа.
Используйте следующую реализацию:
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getActivity().getMenuInflater(); if (v == btnShare) { inflater.inflate(R.menu.share_menu, menu); for (int i = 0; i < menu.size(); ++i) { MenuItem item = menu.getItem(i); item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { onContextItemSelected(item); return true; } }); } } } @Override public boolean onContextItemSelected(MenuItem item) { AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { case R.id.print: // ... } }
Использование намерений для каждого из пунктов меню работало хорошо для меня.
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextmenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = super.getActivity.getMenuInflater(); inflater.infalte(R.menu.list_item, menu); for(int i = 0; i < menu.size(); i++) { MenuItem item = menu.getItem(i); Intent intent = new Intent(); intent.putExtra(KEY_EXTRA_FRAGMENT_ID, this.fragmentId); if (item != null) { item.setIntent(intent); } } } @Override public boolean onContextItemSelected(MeniItem item) { Intent intent = item.getIntent(); if (intent != null) { if (intent.getIntExtra(KEY_EXTRA_FRAGMENT_ID, -1) == this.fragmentId) { // Implement code according the item function. return true; } } return super.onContextItemSelected(item); }
Решение getUserVisibleHint()
не работает для меня – оно всегда возвращает true
даже если fragment отсутствует на экране. Решение getGroupId()
не работает при раздувании меню из XML-ресурса, что является моей ситуацией.
Кажется, что если Android не изменится, любое решение всегда будет немного взломанным. Я создаю глобальную переменную для хранения ссылки идентификатора для текущего fragmentа в onCreateView
. Затем я onCreateContextMenu
его каждому ContextMenu
MenuItem
ContextMenu
в onCreateContextMenu
. Когда элемент выбран, я подтверждаю, что эти два идентификатора совпадают.
private int myFragmentReference; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Initialisation stuff myFragmentReference = 12345; } @Override public void onCreateContextMenu(ContextMenu contextMenu, View v, ContextMenu.ContextMenuInfo contextMenuInfo) { // Usual stuff int size = contextMenu.size(); for (int i = 0; i < size; i++) { MenuItem menuItem = contextMenu.getItem(i); Intent intent = new Intent(); intent.putExtra("id", myFragmentReference); menuItem.setIntent(intent); } } @Override public boolean onContextItemSelected(MenuItem menuItem) { int id = 0; Intent intent = menuItem.getIntent(); if (intent != null) { id = intent.getIntExtra("id", 0); } if (id == myFragmentReference) { // This is the currently displayed fragment } }