Проблема: фрагмент onResume()
в ViewPager
запускается прежде, чем фрагмент становится фактически видимым.
Например, у меня есть 2 фрагмента с ViewPager
и FragmentPagerAdapter
. Второй фрагмент доступен только для авторизованных пользователей, и мне нужно попросить пользователя войти в систему, когда фрагмент станет видимым (используя диалоговое окно с предупреждением).
НО ViewPager
создает второй фрагмент, когда первый видим, чтобы кэшировать второй фрагмент, и делает его видимым, когда пользователь начинает считывание.
Таким образом, onResume()
событие запускается во втором фрагменте задолго до того, как оно становится видимым. Вот почему я пытаюсь найти событие, которое срабатывает, когда второй фрагмент становится видимым, чтобы показать диалог в соответствующий момент.
Как это может быть сделано?
ViewPager
. В двухстраничном пейджере обе страницы будут загружены сразу, нравится вам это или нет. Предполагается, что пользователь воспринимаетViewPager
контент сразу после считывания, а не через некоторое время. Вот почемуViewPager
страница инициализируется впереди того, что видно, чтобы обеспечить удобство работы пользователя.Ответы:
Вы можете сделать следующее, переопределив
setUserVisibleHint
в вашемFragment
:источник
isResumed()
чтобы избежать NPE. Работает нормально для меня.setUserVisibleHint
сейчас устарелОБНОВЛЕНИЕ : в библиотеке поддержки Android (версия 11) наконец-то исправлена проблема с видимыми подсказками для пользователя. Теперь, если вы используете библиотеку поддержки для фрагментов, вы можете безопасно использовать
getUserVisibleHint()
или переопределить,setUserVisibleHint()
чтобы зафиксировать изменения, как описано в ответе Горна.ОБНОВЛЕНИЕ 1 Вот одна маленькая проблема с
getUserVisibleHint()
. Это значение по умолчаниюtrue
.Так что может возникнуть проблема, когда вы пытаетесь использовать его до того, как
setUserVisibleHint()
был вызван. В качестве обходного пути вы можете установить значение вonCreate
методе, как этот.Устаревший ответ:
В большинстве случаев,
ViewPager
показывать только одну страницу за раз, но предварительно кэшированные фрагменты также переводятся в «видимое» состояние (фактически невидимое), если вы используетеFragmentStatePagerAdapter
вAndroid Support Library pre-r11
.Я переопределяю:
Чтобы зафиксировать состояние фокуса фрагмента, которое, я думаю, является наиболее подходящим состоянием «видимости», которое вы имеете в виду, поскольку только один фрагмент в ViewPager может фактически размещать свои пункты меню вместе с элементами родительского действия.
источник
true
для getUserVisibleHint (), когдаonCreateOptionsMenu
вызывается, и когдаsetUserVisibleHint
вызывается, меню, кажется, еще не было создано. В конечном итоге я получаю две опции меню, которые добавляются, когда мне нужно только меню из фрагмента, который виден. Есть предложения на этот счет?setUserVisibleHint
сейчас устарелЭто, кажется, восстанавливает нормальное
onResume()
поведение, которое вы ожидаете. Это хорошо работает с нажатием клавиши домой, чтобы выйти из приложения, а затем снова войти в приложение.onResume()
не вызывается дважды подряд.источник
setUserVisibleHint
вызовом раньшеonCreateView
иsetUserVisibleHint
не вызывается, если приложение переходит в фоновый режим, а затем на передний план. Потрясающие! Спасибо!onVisibleToUser()
метод и вызывать его изonResume()
и из,setUserVisibleHint(boolean)
а не вызыватьonResume()
себя и вмешиваться в обратные вызовы жизненного цикла. В противном случае я думаю, что этот подход работает хорошо, спасибо!Вот еще один способ использования
onPageChangeListener
:источник
setUserVisibleHint()
вызывается иногда доonCreateView()
и иногда после чего вызывает проблемы.Чтобы преодолеть это, вы должны проверить
isResumed()
также и внутреннийsetUserVisibleHint()
метод. Но в данном случае я понял ,setUserVisibleHint()
вызывается только если фрагмент возобновляется и видно, НЕ при создании.Поэтому, если вы хотите что-то обновить, когда Fragment установлен
visible
, поместите функцию обновления вonCreate()
иsetUserVisibleHint()
:ОБНОВЛЕНИЕ: Тем не менее я понял, что
myUIUpdate()
иногда вызывается дважды, причина в том, что если у вас есть 3 вкладки, и этот код находится на 2-й вкладке, когда вы впервые открываете 1-ю вкладку, 2-я вкладка также создается, даже если она не видна иmyUIUpdate()
вызывается. Затем при переходе ко 2-й вкладке вызываетсяmyUIUpdate()
fromif (visible && isResumed())
и, как результат,myUIUpdate()
может вызываться дважды в секунду.Другая проблема заключается
!visible
в том, что она вызываетсяsetUserVisibleHint
как 1) при выходе из экрана фрагмента и 2) перед его созданием при первом переключении на экран фрагмента.Решение:
Объяснение:
fragmentResume
,fragmentVisible
: УбеждаетсяmyUIUpdate()
вonCreateView()
вызывается только когда фрагмент создан и видимый, а не резюме. Это также решает проблему, когда вы находитесь на первой вкладке, вторая вкладка создается, даже если она не видна. Это решает это и проверяет, виден ли фрагмент экрана когдаonCreate
.fragmentOnCreated
: Гарантирует, что фрагмент не виден и не вызывается при первом создании фрагмента. Так что теперь это, если предложение вызывается только когда вы проводите из фрагмента.Обновление Вы можете поместить весь этот код в
BaseFragment
код, подобный этому, и переопределить метод.источник
setUserVisibleHint
вызов не был получен . ! а внутриonCreateView
методfragmentVisible
былfalse
! так что фрагмент оказался пустым! Какие-нибудь мысли.?Чтобы обнаружить
Fragment
вViewPager
видимом, я совершенно уверен, что только использованиеsetUserVisibleHint
недостаточно.Вот мое решение, чтобы проверить, является ли фрагмент видимым или невидимым. Сначала при запуске viewpager переключайтесь между страницами, переходите к другому виду деятельности / фрагменту / фону / переднему плану`
ОБЪЯСНЕНИЕ Вы можете внимательно проверить logcat ниже, тогда я думаю, вы знаете, почему это решение будет работать
Первый запуск
Перейти на страницу 2
Перейти на страницу 3
Перейти к фону:
Перейти на передний план
ДЕМО проект здесь
Надеюсь, это поможет
источник
SubChildContainerFragment
используется для обнаруженияa fragment has another view pager which also consists fragment
. Можно смешиватьSubChildContainerFragment
иChildContainerFragment
до 1 класса. Надеюсь, это поможет. Я отправлю полный ответ позжеисточник
setUserVisibleHint
УстаревшийВ
ViewPager2
иViewPager
из версииandroidx.fragment:fragment:1.1.0
вы можете просто использоватьonPause
иonResume
обратные вызовы, чтобы определить, какой фрагмент в настоящее время видим для пользователя.onResume
обратный вызов вызывается, когда фрагмент становится видимым иonPause
когда он перестает быть видимым.В случае ViewPager2 это поведение по умолчанию, но такое же поведение можно легко включить для старого блага
ViewPager
.Чтобы включить это поведение в первом ViewPager, вы должны передать
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
параметр в качестве второго аргументаFragmentPagerAdapter
конструктора.Примечание:
setUserVisibleHint()
метод иFragmentPagerAdapter
конструктор с одним параметром теперь устарели в новой версии Fragment from android jetpack.источник
Переопределить
setPrimaryItem()
вFragmentPagerAdapter
подклассе. Я использую этот метод, и он работает хорошо.источник
Переопределите
Fragment.onHiddenChanged()
для этого.источник
Я понял, что
onCreateOptionsMenu
иonPrepareOptionsMenu
методы, вызываемые только в том случае, если фрагмент действительно виден. Я не смог найти какой-либо метод, который ведет себя так, как это, я также пытался,OnPageChangeListener
но он не работал для ситуаций, например, мне нужна переменная, инициализированная вonCreate
методе.Таким образом, эти два метода могут быть использованы для решения этой проблемы в качестве обходного пути, особенно для небольших и коротких рабочих мест.
Я думаю, что это лучшее решение, но не лучшее. Я буду использовать это, но в то же время буду ждать лучшего решения.
С уважением.
источник
Другое решение, размещенное здесь, переопределяющее setPrimaryItem в pageradapter Крисом Ларсоном, почти сработало для меня. Но этот метод вызывается несколько раз для каждой настройки. Также я получил NPE из представлений и т. Д. Во фрагменте, так как он не готов в первые несколько раз, когда вызывается этот метод. Со следующими изменениями это сработало для меня:
источник
Добавить следующий код внутри фрагмента
источник
Я столкнулся с той же проблемой при работе с
FragmentStatePagerAdapters
3 вкладками. Мне приходилось показывать Dilaog каждый раз, когда нажимали первую вкладку, и скрывать его при нажатии на другие вкладки.Одно
setUserVisibleHint()
только переопределение не помогло найти текущий видимый фрагмент.При нажатии на 3-й вкладке -----> 1-й вкладке. Это сработало дважды для 2-го фрагмента и для 1-го фрагмента. Я совместил это с методом isResumed ().
источник
У нас есть особый случай с MVP, когда фрагмент должен уведомить докладчика о том, что представление стало видимым, и докладчик введен в Dagger
fragment.onAttach()
.setUserVisibleHint()
недостаточно, мы обнаружили 3 разных случая, которые необходимо рассмотреть (onAttach()
упоминается, чтобы вы знали, когда докладчик доступен):Фрагмент был только что создан. Система делает следующие звонки:
Фрагмент уже создан и нажата домашняя кнопка. При восстановлении приложения на передний план это называется:
Изменение ориентации:
Мы хотим, чтобы подсказка о видимости попала к докладчику только один раз, поэтому мы делаем это так:
источник
Обнаружение по
focused view
!Это работает для меня
источник
Я столкнулся с этой проблемой, когда пытался заставить таймер срабатывать, когда фрагмент в окне просмотра был на экране для просмотра пользователем.
Таймер всегда запускается непосредственно перед тем, как пользователь увидит фрагмент. Это потому, что
onResume()
метод во фрагменте вызывается до того, как мы увидим фрагмент.Мое решение состояло в том, чтобы сделать проверку в
onResume()
методе. Я хотел вызвать определенный метод 'foo ()', когда фрагмент 8 был текущим фрагментом представления пейджеров.Надеюсь это поможет. Я видел, как эта проблема всплывала много. Кажется, это самое простое решение, которое я видел. Многие другие не совместимы с более низкими API и т. Д.
источник
Я была такая же проблема.
ViewPager
выполняет другие события жизненного цикла фрагмента, и я не мог изменить это поведение. Я написал простой пейджер, используя фрагменты и доступные анимации. SimplePagerисточник
Я использовал это, и это сработало!
источник
Я поддерживаю SectionsPagerAdapter с дочерними фрагментами, поэтому после большой головной боли я наконец-то получил рабочую версию, основанную на решениях из этой темы:
источник
Обратите внимание, что
setUserVisibleHint(false)
не вызывается при остановке активности / фрагмента. Вам все еще нужно будет проверить старт / стоп, чтобы правильноregister/unregister
прослушивать любые прослушиватели и т. Д.Кроме того, вы получите,
setUserVisibleHint(false)
если ваш фрагмент начинается в невидимом состоянии; Вы не хотитеunregister
туда, так как вы никогда не регистрировались в этом случае.источник
Простой способ реализации - проверка, вошел ли пользователь в систему, прежде чем перейти к фрагменту.
В вашей MainActivity вы можете сделать что-то подобное внутри метода onNavigationItemSelected .
Однако, если вы используете навигационный ящик, выбор в нем будет изменен на Профиль, хотя мы не перешли к ProfileFragment.
Чтобы сбросить выбор до текущего выбора, запустите код ниже
источник
setUserVisibleHint (логическое видимое) теперь не рекомендуется, так что это правильное решение
В ViewPager2 и ViewPager из версии
androidx.fragment:fragment:1.1.0
вы можете просто использоватьonPause()
иonResume()
определить, какой фрагмент в данный момент виден пользователю.onResume()
вызывается, когда фрагмент становится видимым иonPause
когда он перестает быть видимым.Чтобы включить это поведение в первом ViewPager, вы должны передать
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
параметр в качестве второго аргументаFragmentPagerAdapter
конструктора.источник
Я переопределил метод Count связанного FragmentStatePagerAdapter, и он возвращает общее количество минус количество страниц, которые нужно скрыть:
Таким образом, если в ViewPager изначально добавлено 3 фрагмента, и до тех пор, пока не будет выполнено какое-либо условие, должны отображаться только первые 2 фрагмента, переопределите счетчик страниц, задав для TrimmedPages значение 1, и он должен показывать только первые две страницы.
Это хорошо работает для страниц в конце, но не очень помогает для страниц в начале или в середине (хотя есть много способов сделать это).
источник