Элементы действия из исходного фрагмента Viewpager не отображаются
В приложении, которое я разрабатываю, я использую ViewPager с фрагментами, и каждый фрагмент строит свое собственное меню независимо от всех других фрагментов в ViewPager.
Проблема в том, что иногда фрагменты, которые инициализируются ViewPager по умолчанию (то есть в исходном состоянии), не имеют своих элементов, заполненных в меню элементов действий. Что еще хуже, эта проблема возникает только периодически. Если я проведу через ViewPager достаточно, чтобы фрагменты были вынуждены повторно инициализировать себя, когда я прокручиваю назад, меню заполняется правильно.
Код операции:
package net.solarnz.apps.fragmentsample;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
public class FragmentSampleActivity extends Activity {
private ViewPagerAdapter mViewPagerAdapter;
private ViewPager mViewPager;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (mViewPagerAdapter == null) {
mViewPagerAdapter = new ViewPagerAdapter(getFragmentManager());
}
mViewPager = (ViewPager) findViewById(R.id.log_pager);
mViewPager.setAdapter(mViewPagerAdapter);
mViewPager.setCurrentItem(0);
}
private class ViewPagerAdapter extends FragmentStatePagerAdapter {
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return 8;
}
@Override
public Fragment getItem(int position) {
Fragment f = Fragment1.newInstance(position);
// f.setRetainInstance(true);
f.setHasOptionsMenu(true);
return f;
}
}
}
Код фрагмента:
package net.solarnz.apps.fragmentsample;
import android.app.Fragment;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
public class Fragment1 extends Fragment {
int mNum;
static Fragment newInstance(int num) {
Fragment1 f = new Fragment1();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mNum = getArguments() != null ? getArguments().getInt("num") : 0;
}
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_list, menu);
}
}
Разметка:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<android.support.v4.view.ViewPager
android:id="@+id/log_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Меню
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_refresh"
android:title="Refresh"
android:icon="@android:drawable/ic_delete"
android:showAsAction="ifRoom|withText" />
</menu>
Запущено меню действий:
http://i.stack.imgur.com/QFMDd.png
Меню действий не заселено:
http://i.stack.imgur.com/sH5Pp.png
Ответы
Ответ 1
Вы должны прочитать это (по xcolw...)
Посредством экспериментов кажется, что основная причина недействительна. OptionsMenu получает вызов более одного без перерыва в основном потоке для обработки заданий в очереди. Угадайте - это было бы важно, если бы какая-то критическая часть создания меню была отложена через почту, оставив панель действий в плохом состоянии до ее запуска.
Это может быть несколько случаев, которые не очевидны:
-
вызов viewPager.setCurrentItem несколько раз для одного и того же элемента
-
вызов viewPager.setCurrentItem в onCreate активности. setCurrentItem вызывает недопустимое недопустимое меню опций, за которым сразу следует меню параметров действия
Обходные пути, которые я нашел для каждого
-
Охранять вызов viewPager.setCurrentItem
if (viewPager.getCurrentItem() != position)
viewPager.setCurrentItem(position);
-
Отложить вызов viewPager.setCurrentItem в onCreate
public void onCreate(...) {
...
view.post(new Runnable() {
public void run() {
// guarded viewPager.setCurrentItem
}
}
}
После этих изменений меню параметров внутри пейджера представления, похоже, работает должным образом. Я надеюсь, что кто-то может пролить больше света на это.
источник http://code.google.com/p/android/issues/detail?id=29472
Ответ 2
Простым ответом является не использование меню в фрагментах в ViewPager.
Если вам нужно использовать меню внутри фрагментов, то я предлагаю загрузить меню через метод onCreateOptionsMenu в родительской активности. Очевидно, вам нужно будет определить, какое меню будет показано.
Я смог добиться этого, используя отражение класса.
Вам также потребуется использовать метод invalidateOptionsMenu при каждом переключении страниц. Вам понадобится OnPageChangeListener, чтобы вызвать это, когда ViewPager меняет страницы.
Ответ 3
У меня тоже была такая же проблема. В моем случае у меня есть одна активность с viewpager, которая содержит два фрагмента, каждый фрагмент раздувает свое собственное меню действий, но меню действий фрагментов не отображается.
Просмотр кода адаптера пейджера
public class ScreensAdapter extends FragmentPagerAdapter {
public TrackerScreensAdapter(Context context, FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return 2;
}
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position){
case 0:
fragment = new Fragment1();
break;
case 1:
fragment = new Fragment2();
break;
}
return fragment;
}
}
Действия по созданию
screensAdapter = new ScreensAdapter(this, getFragmentManager());
viewPager.setAdapter(screensAdapter);
Таким образом, у моего viewPager есть два фрагмента, каждый фрагмент запускает свою собственную задачу в onActivityCreated, получает данные и выводит их макет на основе полученных данных. Также каждый фрагмент имеет onCreateOptionsMenu
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
MyTask task = new MyTask();
task.setTaskListener(this);
task.execute();
}
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
}
Проводил много раз, чтобы решить эту проблему, и выяснить, почему меню фрагментов не отображается.
Все, что мне нужно, это
screenAdapter = new ScreenAdapter(this, getFragmentManager());
viewPager.post(new Runnable() {
public void run() {
viewPager.setAdapter(screenAdapter);
}
});
Ответ 4
Сначала создайте метод в подклассе FragmentPagerAdapter, чтобы получить текущий фрагмент
public SherlockFragment getFragment() {
return currentFragment;
}
@Override
public void onTabSelected(final Tab tab, FragmentTransaction ft) {
((SherlockFragmentActivity) mContext).invalidateOptionsMenu();
Fragment f = ((SherlockFragmentActivity) mContext)
.getSupportFragmentManager().findFragmentByTag(
makeFragmentName(tab.getPosition()));
currentFragment=(SherlockFragment) f;
}
Теперь переопределите ниже методы в главной Actvity
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (mTabsAdapter.getPositionOfTabSelected() != 0) {
menu.add("Read").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Write").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Clear").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Factory data reset").setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
return super.onCreateOptionsMenu(menu);
}
Теперь вызовите onOptionItemSelected из действия в фрагмент
@Override
public boolean onOptionsItemSelected(MenuItem item) {
mTabsAdapter.getFragment().onOptionsItemSelected(item);
return super.onOptionsItemSelected(item);
}
Ответ 5
Я решил очень похожую проблему, в которой значки панели действий, назначенные фрагментом внутри ViewPager, исчезали onPause(). Они появятся снова, когда Фрагмент вернется в поле зрения, и пользователь промахнулся влево или вправо, но не сразу. Решение вызывало notifyDataSetChanged() в PagerAdapter в методе onResume() фрагмента.
@Override
public void onResume() {
mPagerAdapter.notifyDataSetChanged();
}
Ответ 6
У меня возникла проблема с элементами панели действий, когда я использовал HorizontalScrollView, чтобы показать вкладки, но я изменил на PagerTitleStrip, и проблема была решена.
Возможно, эта информация может помочь кому-то другому.
Ответ 7
В моем случае я проследил основную причину проблемы тем, что, по моему мнению, является ошибкой в FragmentStatePagerAdapter, которая вызывает Fragment # setMenuVisibility в false и неспособность правильно установить его обратно в true, когда он восстанавливает состояние.
Обходные:
-
Используйте FragmentPagerAdapter вместо FragmentStatePagerAdapter
-
Если вы должны использовать FragmentStatePagerAdapter, в подклассе адаптера переопределите setPrimaryItem следующим образом:
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
//This is a workaround for a bug in FragmentStatePagerAdapter
Fragment currentItem = getItem(position);
if (currentItem != null) {
currentItem.setMenuVisibility(true);
currentItem.setUserVisibleHint(true);
}
}