Я использую ViewPager
вместе с собой FragmentStatePagerAdapter
три разных фрагмента:
- [Fragment1]
- [FRAGMENT2]
- [Fragment3]
Когда я хочу получить Fragment1
от ViewPager
в FragmentActivity
.
В чем проблема, и как мне это исправить?
источник
Я использую ViewPager
вместе с собой FragmentStatePagerAdapter
три разных фрагмента:
Когда я хочу получить Fragment1
от ViewPager
в FragmentActivity
.
В чем проблема, и как мне это исправить?
Основной ответ основан на имени, сгенерированном фреймворком. Если это когда-либо изменится, то это больше не будет работать.
Как насчет этого решения, переопределения instantiateItem()
и destroyItem()
вашего Fragment(State)PagerAdapter
:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return ...;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(...);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
Кажется, это работает для меня при работе с фрагментами, которые доступны. Фрагменты, которые еще не были созданы, при вызове возвращают ноль getRegisteredFragment
. Но я использовал это главным образом, чтобы получить ток Fragment
из ViewPager
: adapater.getRegisteredFragment(viewPager.getCurrentItem())
и это не вернется null
.
Я не знаю никаких других недостатков этого решения. Если таковые имеются, я хотел бы знать.
Fragment
в,WeakReference
чтобы гарантировать, что вы не предотвратите сборку уничтоженного фрагмента? Просто кажется, что это правильно ...MyPagerAdapter
неregisterdFragments
будет потеряно из-за жизненного цикла (то есть поворота) ? Придется ли сохранить файлActivity
/Fragment
using , а затем обновить его с помощью новой ссылки?MyPagerAdapter
onSaveInstanceState
FragmentManager
getItem
не вызывается снова при повороте (для любых уже созданных фрагов), так какFragmentManager
восстанавливает состояния, которыеFragments
он держит в пейджере. ЕслиinstantiateItem
вызывается, когда каждыйFragment
восстанавливается, то это решение на самом деле является более безопасным и более надежным в будущем, чем мое или принятый ответ. Я подумаю попробовать это сам.Для получения фрагментов из ViewPager есть много ответов здесь и в других связанных с этим темах / блогах. Все, кого я видел, сломаны, и обычно они попадают в один из двух типов, перечисленных ниже. Существуют и другие допустимые решения, если вы хотите получить только текущий фрагмент, как этот другой ответ в этой теме.
При использовании
FragmentPagerAdapter
см. Ниже. Если использоватьFragmentStatePagerAdapter
его стоит посмотреть на это . Захват индексов, которые не являются текущими в FragmentStateAdapter, не так полезен, так как по своей природе они будут полностью снесены, вне поля зрения / вне границ ScScreenLimit.Несчастные пути
Неправильно: ведите свой собственный внутренний список фрагментов, добавленный к тому, когда
FragmentPagerAdapter.getItem()
вызываетсяSparseArray
илиMap
getItem
вызывается только в первый раз, когда страница прокручивается (или получается, еслиViewPager.setOffscreenPageLimit(x)
> 0) вViewPager
, если хостингActivity
/Fragment
убит или перезапущен, то внутреннееSpaseArray
будет уничтожено, когда пользовательский FragmentPagerActivity будет воссоздан, но за кулисами ViewPagers внутренние фрагменты будут воссозданы, иgetItem
будет НЕ называться любой из индексов, поэтому возможность получить фрагмент из индекса будут потеряны навсегда. Вы можете объяснить это за счет экономии, и восстановление этих ссылок фрагментов с помощьюFragmentManager.getFragment()
и ,putFragment
но это начинает запутаться ИМХО.Неправильно. Создайте свой собственный идентификатор тега, соответствующий тому, что используется внутри,
FragmentPagerAdapter
и используйте его для извлечения фрагментов страницы изFragmentManager
ViewPager
этому. изменить в любое время или для любой версии ОС.Метод, воссозданный для этого решения,
СЧАСТЛИВЫЙ ПУТЬ:
ViewPager.instantiateItem()
Подход, аналогичный
getItem()
описанному выше, но не нарушающий жизненный цикл, заключается в том, чтобы подключиться к нему,instantiateItem()
а не так,getItem()
как первый будет вызываться при каждом создании / обращении к индексу. Смотрите этот ответСЧАСТЛИВЫЙ ПУТЬ: Построй свой собственный
FragmentViewPager
Создайте свой собственный
FragmentViewPager
класс из источника последней библиотеки поддержки и измените метод, используемый внутри для генерации тегов фрагмента. Вы можете заменить его ниже. Преимущество этого в том, что вы знаете, что создание тега никогда не изменится, и вы не полагаетесь на частный API / метод, который всегда опасен.Затем, как говорит документ, когда вы хотите получить фрагмент, используемый для индекса, просто вызовите что-то вроде этого метода (который вы можете поместить в пользовательский
FragmentPagerAdapter
или подкласс), зная, что результат может быть нулевым, если getItem еще не был вызван для эта страница, т.е. она еще не была создана.Это простое решение, которое решает проблемы в двух других решениях, которые можно найти в Интернете.
источник
instantiateItem()
когда вы хотите получить доступ к фрагменту, который еще не был посещен после того, как произошло событие жизненного цикла и было посещено до события жизненного цикла. Небольшая разница, которую я знаю, но она привела к незначительной ошибке в моей программе, поэтому я изучаю это.getItemId(pos)
внутриFragmentStatePagerAdapter
Добавьте следующие методы в ваш FragmentPagerAdapter:
getActiveFragment (0) должен работать.
Вот решение, реализованное в ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Если что-то не получится, вы увидите хороший журнал аварий.
источник
Еще одно простое решение:
источник
setPrimaryItem()
называется после того, какViewPager.OnPageChangeListener#onPageSelected()
я не могу его использовать :-(Я знаю, что у этого есть несколько ответов, но, возможно, это поможет кому-то. Я использовал относительно простое решение, когда мне нужно было получить
Fragment
от меняViewPager
. В вашемActivity
илиFragment
удерживаяViewPager
, вы можете использовать этот код для циклического перебора всего, чтоFragment
он содержит.Если вы знаете свою позицию
Fragment
вViewPager
, вы можете просто позвонитьgetItem(knownPosition)
.Если вы не знаете своего положения
Fragment
вViewPager
, вы можете попросить своих детейFragments
реализовать интерфейс с подобным методомgetUniqueId()
и использовать его для их дифференциации. Или вы можете перебрать всеFragments
и проверить тип класса, такой какif(viewPagerFragment instanceof FragmentClassYouWant)
!!! РЕДАКТИРОВАТЬ !!!
Я обнаружил, что он
getItem
вызывается только тогда,FragmentPagerAdapter
когда каждыйFragment
должен быть создан в первый раз , после этого кажется, чтоFragments
они перерабатываются с использованиемFragmentManager
. Таким образом, многие реализацииFragmentPagerAdapter
создают новыеFragment
сgetItem
. Используя мой метод, описанный выше, это означает, что мы будем создавать новыеFragment
s каждый раз, когдаgetItem
вызывается при прохождении всех элементов вFragmentPagerAdapter
. В связи с этим я нашел лучший подход, используя вместо негоFragmentManager
каждыйFragment
(используя принятый ответ). Это более полное решение, и оно хорошо работает для меня.И вам понадобится этот метод.
источник
ViewPager
Сам устанавливает эти теги. Это решение хрупкое, потому что оно основано на знании «скрытого» соглашения об именахViewPager
. Ответ «Улицы Бостона» - гораздо более комплексное решение, которое я сейчас использую в своем проекте (вместо этого подхода).Для моего случая ни одно из вышеперечисленных решений не сработало.
Однако, поскольку я использую дочерний менеджер фрагментов во фрагменте, было использовано следующее:
Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());
Это будет работать только в том случае, если ваши фрагменты в диспетчере соответствуют элементу ViewPager.
источник
источник
Я обработал это, сначала составив список всех фрагментов (
List<Fragment> fragments;
), которые я собирался использовать, затем добавил их в пейджер, упрощая обработку текущего просматриваемого фрагмента.Так:
тогда это можно назвать:
так что тогда я мог бы бросить его в операторе if, который работал бы, только если он был на правильном фрагмент
но это только мой подход к хаку и слэшу, но он сработал для меня, я использую его, чтобы отменить изменения в отображаемом фрагменте, когда нажата кнопка «Назад».
источник
Это основано на ответе Стивена выше. Это вернет фактический экземпляр фрагмента, который уже присоединен к родительскому действию.
источник
Я не мог найти простой, чистый способ сделать это. Однако виджет ViewPager - это просто еще одна ViewGroup, в которой хранятся ваши фрагменты. ViewPager имеет эти фрагменты как непосредственные потомки. Таким образом, вы можете просто перебрать их (используя .getChildCount () и .getChildAt ()) и посмотреть, загружен ли в данный момент искомый экземпляр фрагмента в ViewPager и получить ссылку на него. Например, вы можете использовать какое-то статическое поле уникального идентификатора, чтобы различать фрагменты.
Обратите внимание, что ViewPager, возможно, не загрузил искомый фрагмент, так как это виртуализирующий контейнер, такой как ListView.
источник
FragmentPagerAdapter - это фабрика фрагментов. Чтобы найти фрагмент, основанный на его позиции, если он все еще находится в памяти, используйте это:
Пример кода для поддержки API v4.
источник
Вам не нужно вызывать
getItem()
или какой-либо другой метод на более позднем этапе, чтобы получить ссылку наFragment
размещение внутриViewPager
. Если вы хотите обновить некоторые данные внутри,Fragment
используйте этот подход: динамически обновлять ViewPager?Ключ заключается в том, чтобы установить новые данные внутри,
Adaper
и вызов,notifyDataSetChanged()
который, в свою очередь, будет вызыватьgetItemPosition()
, передавая вам ссылкуFragment
и давая вам возможность обновить ее. Все остальные способы требуют, чтобы вы сохраняли ссылку на себя или какой-то другой взлом, который не является хорошим решением.источник
getItemPosition()
это метод в вашем адаптере. Вы не будете звонить прямо. У вас есть ссылка на ваш адаптер, поэтому вы звоните,adapter.notifyDataSetChanged()
что, в свою очередь, вызоветgetItemPosition()
ваш адаптер, передавая ссылку вашегоFragment
s. Вы можете увидеть полную реализацию в действии здесь stackoverflow.com/questions/19891828/…Fragment
но вопрос о том, как получить ссылку, спорен. Другие решения получить справку сFragmentManager
помощью строки аналогична"android:switcher:"+id
или возвращенияPOSITION_NONE
изgetItemosition()
чего все фрагменты воссоздать себя.Должен распространяться
FragmentPagerAdapter
на ваш класс адаптера ViewPager.Если вы используете,
FragmentStatePagerAdapter
то вы не сможете найтиFragment
его по егоID
Как использовать этот метод: -
источник
Эй, я ответил на этот вопрос здесь . В основном вам нужно переопределить
метод FragmentStatePagerAdapter.
источник
Лучшее решение - использовать расширение, которое мы создали в CodePath и которое называется SmartFragmentStatePagerAdapter . Следуя этому руководству, это значительно упрощает извлечение фрагментов и текущего выбранного фрагмента из ViewPager. Это также лучше справляется с управлением памятью фрагментов, встроенных в адаптер.
источник
Самый простой и краткий способ. Если все ваши фрагменты
ViewPager
относятся к разным классам, вы можете извлечь и различить их следующим образом:источник
Я реализовал это легко с немного другим подходом.
Мой пользовательский метод FragmentAdapter.getItem возвратил не новый MyFragment (), а экземпляр MyFragment, созданный в конструкторе FragmentAdapter.
Затем в своей деятельности я получил фрагмент из адаптера, проверил, является ли он экземпляром необходимого фрагмента, затем произвел приведение и использовал необходимые методы.
источник
Создать целочисленный идентификатор ресурса в /values/integers.xml
Затем в функции getItem PagerAdapter:
Затем в действии напишите эту функцию, чтобы получить ссылку на фрагмент:
Получите ссылку на фрагмент, вызвав вышеупомянутую функцию, а затем приведите ее к вашему пользовательскому фрагменту:
источник
Простой способ перебирать фрагменты в диспетчере фрагментов. Найдите viewpager с аргументом позиции раздела, размещенный в общедоступном статическом PlaceholderFragment newInstance (int sectionNumber) .
источник
Во фрагменте
В FragmentActivity
источник
в TabLayout есть несколько вкладок для фрагмента. Вы можете найти фрагмент по тегу, используя индекс фрагмента.
Например индекс для Fragment1 равен 0, поэтому в
findFragmentByTag()
методе передайте тег для Viewpager.after с помощью фрагмента транзакции, который вы можете добавить, замените фрагмент.String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);
источник
Хорошо для адаптера
FragmentStatePagerAdapter
я финансирую решение:в вашей FragmentActivity:
и создайте метод в своем классе FragmentActivity - чтобы этот метод предоставил вам доступ к вашему фрагменту, вам просто нужно указать ему позицию нужного фрагмента:
в вашем адаптере:
источник
index
это место фрагмента в адаптере, как вы добавилиfragment1
вначале, так что получитеfragment1
проходindex
0 и так далее для отдыхаисточник