ViewPager не перерисовывает содержимое, остается / становится пустым
мы страдаем от очень странной проблемы с ViewPager здесь. Мы вставляем списки на каждой странице ViewPager и запускаем notifyDataSetChanged как на адаптере списка, так и на адаптере пейджера представления при обновлении данных списка.
мы наблюдаем, что иногда страница не обновляет свое дерево просмотра, т. е. остается пустой, а иногда даже исчезает при подкачке к нему. При перелистывании назад и вперед несколько раз, содержание внезапно появится снова. Кажется, что Android отсутствует посмотреть обновление можно здесь. Я также заметил, что при отладке с помощью Hierarchy viewer выбор представления всегда заставит его снова появиться, по-видимому, потому, что Hierarchy viewer заставляет выбранное представление перерисовывать себя.
Я не мог сделать эту работу программно, хотя; аннулирование представления списка или даже всего пейджера представления не имело никакого эффекта.
Это с библиотекой совместимости-v4_r7. Я также попытался использовать последнюю версию, поскольку она утверждает, что исправляет многие проблемы, связанные с просмотр пейджера, но это еще больше ухудшило ситуацию (например, жесты были сломаны, чтобы иногда он не позволял мне перелистывать все страницы.)
кто-нибудь работает в этих вопросах или у вас есть идея, что может быть причиной этого?
11 ответов:
нам наконец-то удалось найти решение. По-видимому, наша реализация пострадала от двух проблем:
- наш адаптер не удалить вида
destroyItem()
.- мы кэшировали представления, так что нам пришлось бы раздувать наш макет только один раз, и, поскольку мы не удаляли представление в
destroyItem()
, мы не добавляли его вinstantiateItem()
но просто возвращает кэшированное представление, соответствующее текущей позиции.Я не заглядывал слишком глубоко в исходный код
ViewPager
- и это не совсем ясно, что вы должны это сделать - но документы говорят:destroyItem()
удалить страницу для данной позиции. Адаптер отвечает за удаление представления из своего контейнера, хотя он должен только гарантировать, что это будет сделано к моменту его возвращения из finishUpdate(ViewGroup).и:
очень простой PagerAdapter может выбрать, чтобы использовать страницу Рассматривает себя как ключевые объекты, возвращая их из instantiateItem (ViewGroup, int) после создания и добавления их в родительскую ViewGroup. Соответствующая реализация destroyItem(ViewGroup, int, Object) удалит представление из родительской ViewGroup, а isViewFromObject(View, Object) может быть реализован как return view == object;.
Итак, мой вывод таков
ViewPager
полагается на свой базовый адаптер для явного добавления / удаления его дочерних элементов вinstantiateItem()
/destroyItem()
. То есть, если ваш адаптер является подклассомPagerAdapter
, ваш подкласс должен реализовать эту логику.Примечание стороны: будьте в курсе этой если вы используете списки внутри
ViewPager
.
если
ViewPager
устанавливается внутри фрагмента сFragmentPagerAdapter
используйтеgetChildFragmentManager()
вместоgetSupportFragmentManager()
в качестве параметра для инициализацииFragmentPagerAdapter
.mAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());
вместо
mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
у меня была точно такая же проблема, но я фактически уничтожил вид в destroyItem (я думал). Однако проблема в том, что я уничтожил его с помощью
viewPager.removeViewAt(index);
вместоviewPager.removeView((View) object);
неправильно:
@Override public void destroyItem(ViewGroup viewPager, int position, Object object) { viewPager.removeViewAt(position); }
правильно:
@Override public void destroyItem(ViewGroup viewPager, int position, Object object) { viewPager.removeView((View) object); }
ViewPager пытается делать умные вещи вокруг повторного использования элементов, но он требует, чтобы вы возвращали новые позиции элементов, когда все изменилось. Попробуйте добавить это в свой PagerAdapter:
public int getItemPosition (Object object) { return POSITION_NONE; }
это в основном говорит ViewPager, что все изменилось (и заставляет его повторно создавать все). Это единственное, что приходит мне в голову.
У меня была проблема с теми же симптомами, но другую причину, которая оказалась глупой ошибкой с моей стороны. Я подумал, что добавлю его сюда, если это кому-то поможет.
У меня был ViewPager с использованием FragmentStatePagerAdapter, который раньше имел два фрагмента, но позже я добавил третий. Однако я забыл, что ограничение по умолчанию для страницы вне экрана равно 1-поэтому, когда я переключусь на новый третий фрагмент, первый будет уничтожен, а затем воссоздан после переключения обратно. Проблема было то, что моя деятельность отвечала за уведомление этих фрагментов для инициализации их состояния пользовательского интерфейса. Это произошло, когда жизненные циклы activity и fragment были одинаковыми, но чтобы исправить это, мне пришлось изменить фрагменты, чтобы инициализировать их собственный пользовательский интерфейс во время их жизненного цикла запуска. В конце концов, я также изменил setOffscreenPageLimit на 2, чтобы все три фрагмента всегда оставались живыми (безопасными в этом случае, поскольку они не были очень интенсивными для памяти).
библиотека поддержки Android имеет демонстрационную активность, которая включает в себя ViewPager с ListView на каждой странице. Вы, вероятно, должны посмотреть и посмотреть, что он делает.
в Eclipse (с Android Dev Tools r20):
- выберите
New > Android Sample Project
- выберите целевой уровень API (я предлагаю самый новый доступный)
- выберите
Support4Demos
- щелкните правой кнопкой мыши проект и выберите
Android Tools > Add Support Library
- запустите приложение и выберите
Fragment
а тоPager
код для этого находится в
src/com.example.android.supportv4.app/FragmentPagerSupport.java
. Удачи вам!
я столкнулся с этим и очень похожие вопросы. Я даже он попросил на переполнение стека.
для меня, в родитель родитель на мой взгляд кто-то подкласса
LinearLayout
и переопределялоrequestLayout()
без вызоваsuper.requestLayout()
. Это помешалоonMeasure
иonLayout
от вызова на моем ViewPager (хотя hierarchyviewer вручную вызывает их). Без измерения они будут отображаться как пустые в ViewPager.так что проверьте ваши содержащие представления. Убедитесь, что они подкласс из поля зрения и не слепо переопределить requestLayout или что-нибудь подобное.
была та же проблема, которая как-то связана с
ListView
(потому что мой пустой взгляд показывает нормально, если список пуст). Я только что звонилrequestLayout()
проблемаListView
. Теперь он отлично рисует!
я столкнулся с этой же проблемой при использовании ViewPager и FragmentStatePagerAdapter. Я попытался использовать обработчик с 3-секундной задержкой для вызова invalidate() и requestLayout (), но это не сработало. Что действительно работало, так это сброс цвета фона viewPager следующим образом:
MyFragment.java
private Handler mHandler; private Runnable mBugUpdater; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = new ViewPager(getActivity()); //...Create your adapter and set it here... mHandler = new Handler(); mBugUpdater = new Runnable(){ @Override public void run() { mVp.setBackgroundColor(mItem.getBackgroundColor()); mHandler = null; mBugUpdater = null; } }; mHandler.postDelayed(mBugUpdater,50); return rootView; } @Override public void onPause() { if(mHandler != null){ //Remove the callback if it hasn't triggered yet mHandler.removeCallbacks(mBugUpdater); mHandler = null; mBugUpdater = null; } super.onPause(); }
для меня проблема заключалась в том, чтобы вернуться к активности после того, как процесс приложения был убит. Я использую пользовательский вид адаптера пейджера, измененный из источников Android.Пейджер представления встроен непосредственно в действие.
вызов
viewPager.setCurrentItem(position, true);
(с анимацией) после установки данных и notifyDataSetChanged (), кажется, работает, но если параметр установлен в false, это не так, и фрагмент пуст. Это крайний случай, который может кому-то помочь.
у меня была аналогичная проблема. Я кэширую представления, потому что мне нужно только 3 представления в
ViewPager
. Когда я скользить вперед все в порядке, но когда я начинаю скользить назад возникает ошибка, он говорит, что "мой взгляд уже есть родитель". Решение-удалить ненужные элементы вручную.@Override public Object instantiateItem(ViewGroup container, int position) { int localPos = position % SIZE; TouchImageView view; if (touchImageViews[localPos] != null) { view = touchImageViews[localPos]; } else { view = new TouchImageView(container.getContext()); view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); touchImageViews[localPos] = view; } view.setImageDrawable(mDataModel.getPhoto(position)); Log.i(IRViewPagerAdpt.class.toString(), "Add view " + view.toString() + " at pos: " + position + " " + localPos); if (view.getParent() == null) { ((ViewPager) container).addView(view); } return view; } @Override public void destroyItem(ViewGroup container, int position, Object view) { // ((ViewPager) container).removeView((View) view); Log.i(IRViewPagerAdpt.class.toString(), "remove view " + view.toString() + " at pos: " + position); } .................. private static final int SIZE = 3; private TouchImageView[] touchImageViews = new TouchImageView[SIZE];