Android studio viewpager fragment

Android

ViewPager

В Android есть компонент ViewFlipper, который позволяет прокручивать экран влево-вправо. Но он имеет ряд недостатков. ViewFlipper не позволяет с лёгкостью добиться эффекта привязки, когда экраны двигаются вместе с пальцем. Также нужен механизм автоматической доводки экранов в ту или иную сторону.

Google предложила другой вариант — использовать компонент ViewPager, который входит в состав Support Package. В новых проектах необходимая библиотека добавляется автоматически, поэтому мы сразу можем попробовать написать демонстрационный пример.

Так как компонент относится к пакету совместимости, то используемые фрагменты должны относиться к классу android.support.v4.app.Fragment, даже если вы собираетесь писать приложение для новых устройств, которые поддерживают стандартные фрагменты. На данный момент библиотека переписывается на AndroidX, поэтому я буду по возможности заменять старые примеры. Все названия классов и методов остаются, меняется только имя пакета.

ViewPager относится к категории ViewGroup и схож по работе с компонентами на основе AdapterView (ListView и Gallery). На панели инструментов Android Studio компонент можно найти в разделе Containers. При использовании ViewPager в разметке используйте полное имя класса. Старый вариант.

Данные для отображения компонент берёт из адаптеров:

  • PagerAdapter (фрагменты не обязательны)
  • FragmentPagerAdapter (если используется мало фрагментов)
  • FragmentStatePagerAdapter (если много фрагментов)

Вам нужно унаследовать класс от нужного адаптера и реализовать свои методы. Добавление и удаление экранов реализуется с помощью методов instantiateItem() и destroyItem() соответственно. Элементы View для отображения можно создавать прямо в адаптере. Такой подход хорош тем, что ViewPager можно настраивать так, чтобы в адаптере не хранились все экраны сразу. По умолчанию адаптер хранит текущий экран, и по одному слева и справа от него. Это может сэкономить память, если содержание экранов слишком сложное.

Когда пользователь переключается на другой фрагмент, то вызывается метод onDestroyView(), а не onDestroy().

FragmentPagerAdapter

Рассмотрим простой пример с минимальным количеством кода для первого знакомства. Создадим новый проект. В activity_main.xml добавим ViewPager из примера выше.

Подготовим разметки для фрагментов.

Сначала создадим ещё один файл разметки res/layout/fragment_1.xml:

И ещё один файл res/layout/fragment_2.xml:

Создадим новый класс для первого фрагмента Fragment1:

Класс для второго фрагмента Fragment2:

Фрагменты подготовлены. Теперь в основном классе MainActivity создадим адаптер на основе FragmentPagerAdapter и напишем остальной код:

В методе getCount() следует возвращать количество страниц. В методе getItem() по номеру позиции нужно вернуть фрагмент.

Если у нас имеется три экрана, то может быть удобно сразу показать второй экран, чтобы можно было прокручивать или влево к первому экрану или вправо к третьему экрану. Это достигается вызовом метода setCurrentItem(1).

В нашем примере мне было лень создавать третий фрагмент, поэтому второй фрагмент используется два раза. В качестве фрагмента по умолчанию я установил первый фрагмент. Запустите пример и подвигайте экраны приложения вправо-влево.

Сам принцип теперь понятен? Нужно подготовить фрагменты и через адаптер сменять их.

PageTransformer

Если хочется добавить анимации при смене фрагментов, то воспользуйтесь специальным классом PageTransformer. Попробуем менять прозрачность фрагмента.

Класс PageTransformer заслуживает отдельной статьи.

PagerTitleStrip

Рассмотрим другой вариант и изучим другие возможности. Для примера будем использовать всего один фрагмент, содержимое которого будем менять динамически. А сверху добавим специальную полоску с заголовками.

Изменим разметку для фрагмента (fragment_1.xml):

Создадим два строковых массива в ресурсах (res/values/strings.xml):

Теперь подготовим класс для фрагмента CatFragment:

При создании фрагмент извлекает данные из объекта Bundle и использует их для заполнения текстов и картинки.

Создадим класс для адаптера в отдельном файле для удобства с помощью мастера создания класса, указав в качестве суперкласса FragmentPagerAdapter.

У адаптера должен быть пустой конструктор и два обязательных метода getItem() и getCount(). Немного переделаем конструктор, чтобы он использовал контекст, необходимый для извлечения данных из ресурсов.

Для подсчёта количества экранов используется свойство массива length. А для формирования содержимого экрана мы помещаем нужные данные в объект Bundle, которые затем будут переданы фрагменту. Данные находятся в трёх массивах: короткий текст, длинный текст и ссылка на изображение в ресурсах.

Метод getPageTitle() позволяет задать заголовок для фрагмента. Сам заголовок мы зададим в следующем шаге.

Приготовления почти закончены. Изменим разметку главной активности, чтобы у отдельного экрана появились заголовки. Для этого добавляется тег PagerTitleStrip:

Читайте также:  Что такое черная дыра андроид что это такое

Если вы хотите видеть заголовок внизу фрагмента, то используйте android:layout_gravity=»bottom».

Загружаем ViewPager и подключаем адаптер.

Пример на планшете в альбомной ориентации:

Свойства PagerTitleStrip можно изменить программно, например, поменять размер и цвет заголовков.

Тег PagerTitleStrip можно заменить на PagerTabStrip. В этом случае заголовке станут ещё и кнопками-вкладками. Ничего переписывать не придётся. Вы по-прежнему можете перелистывать страницы пальцами или нажимать на заголовки.

У ViewPager есть обработчик событий OnPageChangeListener с тремя методами:

Например, метод onPageSelected() позволяет получить номер текущего экрана при пролистывании (отсчёт от 0).

Метод onPageScrolled() даёт представление о текущем значении скрола при пролистывании.

Метод onPageScrollStateChanged() позволяет узнать о состоянии, в котором находится скрол (SCROLL_STATE_IDLE – экраны не листаются, SCROLL_STATE_DRAGGING – пользователь «тащит» страницу, SCROLL_STATE_SETTLING – палец пользователя «доводит» страницу до конца.

Сейчас данный слушатель помечен как устаревший.

Адаптер FragmentStatePagerAdapter

Это старый вариант примера, когда компонент только появился. Я не стал делать ревизию, оставляю вам для самостоятельного изучения.

Адаптер FragmentPagerAdapter держит все фрагменты в памяти, а FragmentStatePagerAdapter создаёт их заново по мере необходимости. В этом их принципиальное отличие. Напишем пример и добавим поддержку кнопки Back.

Создадим разметку для отдельной страницы (pager.xml):

Создадим класс фрагмента с минимальным кодом

Разметку активности оставим минимальной:

Код для активности. Тут всё уже знакомо.

Заключение

В Android Studio в некоторых шаблонах встречается реализация ViewPager из коробки. Недавно Гугл представила бета-версию ViewPager2, которая должна заменить старый компонент.

Источник

Перелистывание страниц и ViewPager2

ViewPager2 и разделение приложения на страницы

Нередко можно встретить приложения, которые реализуют систему перелистывания, а само приложение предстает в виде набора страниц, которые можно пролистывать влево и вправо. В приложении Android для создания подобного эффекта можно использовать элемент ViewPager2 из комплекта JetPack. Для создания эффекта страниц ViewPager2 использует фрагменты.

Итак, создадим новый проект. Добавим в папку res/layout файл разметки для фрагмента, который будет представлять страницу. Назовем его fragment_page.xml и определим в нем следующий код:

Фрагмент будет отображать текстовое поле с номером страницы.

Теперь добавим в проект сам класс фрагмента. Назовем его PageFragment :

Переменная pageNumber указывает на номер текущей страницы. Номер страницы будет передаваться извне через фабричный метод newInstance() . Передача номера происходит путем добавления значения в аргумент «num»

Затем при создании фрагмента в методе onCreate() этот номер будет извлекаться из аргумента «num» (если аргументы определены):

В методе onCreateView() полученный номер страницы будет отображаться в текстовом поле.

Сам по себе фрагмент еще не создает функциональность постраничной навигации. Для этого нам нужен один из классов PagerAdapter . Android SDK содержит ряд встроенных реализаций PagerAdapter, в частности, класс FragmentStateAdapter . Этот класс являются абстрактным, поэтому напрямую мы его использовать не можем, и нам нужно создать класс-наследник. Для этого добавим в проект новый класс, который назовем MyAdapter :

Класс FragmentStateAdapter определяет два метода:

int getItemCount() : возвращает количество страниц, которые будут в ViewPager2 (в нашем случае 10)

Fragment createFragment(int position) : по номеру страницы, передаваемому в качестве параметра position, возвращает объект фрагмента

Стоит отметить, что в качестве параметра конструктор FragmentStateAdapter принимает контекст выполнения — обычно это объект FragmentActivity, но также это может быть объект Fragment

В завершении установим в файле activity_main.xml элемент ViewPager2:

И также изменим код MainActivity :

Класс MainActivity наследуется от AppCompatActivity — класса, который в свою очередь наследуется от FragmentActivity, и поэтому ее текущий объект мы можем передать в качестве параметра в конструктор MyAdapter (а через него — в конструктор FragmentStateAdapter). Чтобы перелистывание заработало, для ViewPager2 устанавливается адаптер MyAdapter.

И запустив проект, мы сможем с помощью перелистывания перемещаться по страницам:

Источник

Как работать с ViewPager2

Прошло не так много времени с тех пор, как 7 февраля 2019 года Google выпустила альфа-версию Android ViewPager2. Более подробную информацию об этом релизе можно найти здесь. А сейчас давайте посмотрим, что из себя представляет ViewPager2.

Новые фичи

Что изменилось?

ViewPager2 выпущен для Android X, поэтому, если вы хотите его использовать, ваш проект должен использовать Android X. Давайте посмотрим, как мы можем использовать этот новый ViewPager2.

Добавление зависимости

Добавьте следующую зависимость в файл build.gradle на уровне приложения:

После этого синхронизируйте свой проект.

Настройка

Добавьте виджет ViewPager2 в вашу Activity или фрагмент:

Давайте создадим layout для страницы, которая будет отображаться во ViewPager2:

Далее нам нужно создать Adapter для ViewPager2. Это самая интересное. Для этого мы можем использовать RecyclerView.Adapter . Разве это не круто?

Читайте также:  Mtk droid tools для android

Это такой же адаптер, который мы используем для обычного RecyclerView, и с ViewPager2 он работает так же хорошо.

Последний шаг, установим адаптер для ViewPager2:

Вот и всё! Получаем тот же результат, как и при использовании старого ViewPager с PagerAdapter:

Вертикальная прокрутка

Раньше нужно было использовать сторонние библиотеки для реализации вертикальной прокрутки, т.к. до сих пор Google не предоставляла такой возможности «из коробки». В этом новом ViewPager2 теперь есть поддержка вертикальной прокрутки. Просто измените ориентацию во ViewPager2 и вертикальная прокрутка будет включена. Очень просто!

Вот, что получается в итоге:

Использование FragmentStateAdapter

Вы также можете использовать фрагменты в качестве страниц, как и в старом ViewPager. Для этого есть FragmentStateAdapter. Давайте посмотрим, как мы можем его использовать.

Прежде всего, нам нужно создать фрагмент:

Теперь мы создадим адаптер для ViewPager2. В его конструктор мы передадим FragmentManager, который будет управлять фрагментами:

Теперь установим этот новый адаптер во ViewPager2, и всё готово:

Улучшенный OnPageChangeCallback

В старом ViewPager интерфейс OnPageChangeListner был предназначен для получения событий изменения/прокрутки страницы. И это была очень неудобно, т.к. нам нужно было переопределять все три метода ( onPageScrollStateChanged , onPageScrolled , onPageSelected ), даже если мы этого не хотели.

Теперь у нас есть OnPageChangeCallback , абстрактный класс с неабстрактными методами. Что буквально означает, что нам не нужно переопределять все эти методы, мы можем просто переопределить те, которые нам нужны или которые мы хотим использовать. Вот так, например, мы можем отслеживать события смены страницы:

Внимание!

Поскольку ViewPager2 находится в альфа-версии, есть некоторые функции старого ViewPager, которые ещё не были реализованы или не работают должным образом в этой версии.

Известные проблемы согласно документации:

  • ClipToPadding,
  • Отсутствует интеграция с TabLayout,
  • Отсутствует контроль за пределами экрана,
  • Нельзя установить ширину страницы (100% по умолчанию)

Больше информации об известных проблемах — здесь. Надеюсь, что всё это будет исправлено в ближайших обновлениях. Я с нетерпением жду стабильной версии этого нового ViewPager2. А до тех пор, хорошего всем кода!

Источник

Полный список

— разбираемся с ViewPager

ViewPager позволяет нам организовать удобный и красивый просмотр данных с возможностью перелистывания влево-вправо. Сам ViewPager отвечает за показ и прокрутку. Но ему нужен еще PagerAdapter, который отвечает за предоставление данных.

PagerAdapter – это базовый абстрактный класс, для которого разработчик дописывает реализацию так, как ему надо. Существует распространенная стандартная (частичная) реализация PagerAdapter, которая работает с фрагментами – это FragmentPagerAdapter. Разработчику остается только создать фрагмент и определить кол-во страниц.

Напишем простой пример и рассмотрим основные возможности ViewPager и FragmentPagerAdapter.

Project name: P1251_ViewPager
Build Target: Android 2.3.3
Application name: ViewPager
Package name: ru.startandroid.develop.p1251viewpager
Create Activity: MainActivity

В main.xml пишем:

Только компонент ViewPager.

Здесь только TextView, который будет показывать содержимое страницы.

Метод newInstance создает новый экземпляр фрагмента и записывает ему в атрибуты число, которое пришло на вход. Это число – номер страницы, которую хочет показать ViewPager. По нему фрагмент будет определять, какое содержимое создавать в фрагменте.

В onCreate читаем номер страницы из аргументов. Далее формируем цвет из рандомных компонентов. Он будет использоваться для фона страниц, чтобы визуально отличать одну страницу от другой.

В onCreateView создаем View, находим на нем TextView, пишем ему простой текст с номером страницы и ставим фоновый цвет.

Т.е. на вход у нас идет номер страницы, а на выходе получаем фрагмент, который отображает этот номер и имеет случайный фоновый цвет.

Фрагмент готов, пишем MainActivity.java:

В onCreate создаем адаптер и устанавливаем его для ViewPager. Также для ViewPager создаем обработчик событий. Он имеет три метода:

onPageSelected – дает номер текущей отображенной страницы

onPageScrolled – достаточно сложно объяснить на словах. Метод дает нам представление о текущем значении скроллера при пролистывании. Рекомендую поставить там запись в лог, полистать и посмотреть, что получается.

onPageScrollStateChanged – сообщает нам о состоянии, в котором находится скроллер (SCROLL_STATE_IDLE – ничего не скролится, SCROLL_STATE_DRAGGING – пользователь «тащит» страницу, SCROLL_STATE_SETTLING – скроллер долистывает страницу до конца)

Класс FragmentPagerAdapter — абстрактный. Нам надо реализовать в нем пару методов. Для этого создаем класс MyFragmentPagerAdapter. В нем реализуем методы:

getItem – по номеру страницы нам надо вернуть фрагмент, используем наш метод newInstance

getCount – здесь мы должны возвращать кол-во страниц, используем константу

Все сохраняем и запускаем приложение.

Полистаем страницы, в логах видим:

onPageSelected, position = 1
onPageSelected, position = 2
onPageSelected, position = 3
onPageSelected, position = 4
onPageSelected, position = 3
onPageSelected, position = 2
onPageSelected, position = 1
onPageSelected, position = 0

Срабатывает обработчик перелистываний.

Читайте также:  Вернуть клавиши навигации android

PagerTitleStrip

К ViewPager можно прикрутить элемент, который будет показывать заголовки – PagerTitleStrip.

Помещаем PagerTitleStrip внутрь ViewPager.

А в коде адаптера надо добавить метод getPageTitle, чтобы PagerTitleStrip знал какой текст показывать в заголовке. В класс MyFragmentPagerAdapter в MainActivity.java дописываем:

Будем возвращать просто «Title» и номер страницы

Сверху появились заголовки.

PagerTabStrip

Заголовки могут участвовать в навигации. Для этого используется компонент PagerTabStrip. Это аналог PagerTitleStrip, но при нажатии на заголовок он перелистывает страницу. Его встраивание полностью аналогично только что рассмотренному PagerTitleStrip

Он также требует от адаптера метод getPageTitle, который у нас уже реализован в MyFragmentPagerAdapter.

Понажимайте на левый и правый заголовки, страницы будут перелистываться.

Lifecycle

Давайте подробнее рассмотрим, что происходит с фрагментами в моменты перелистывания. Для этого перепишем PageFragment.java:

В onCreate мы добавили запись в лог и попытку чтения сохраненного значения из savedInstanceState.

В onSaveInstanceState сохраняем номер страницы.

В onDestroy просто пишем лог.

Тем самым мы увидим, пересоздается ли фрагмент и может ли он при этом восстанавливать сохраненные значения.

Все сохраним, запустим приложение.

Создался фрагмент для нулевой и первой страницы. Хотя видна сейчас только нулевая. Адаптер разумно заранее создает следующую к показу страницу, чтобы при пролистывании не было тормозов. Фрагменты создаются первый раз, вытаскивать из savedInstanceState нечего, поэтому видим savedPageNumber = -1.

Перелистнем на первую страницу

onPageSelected, position = 1
onCreate: 2
savedPageNumber = -1

Первую показал, вторую заранее создал.

Перелистнем еще пару страниц

onPageSelected, position = 2
onCreate: 3
savedPageNumber = -1
onPageSelected, position = 3
onCreate: 4
savedPageNumber = -1

Все также и остается. Заметьте, что не срабатывает onDestroy. Т.е. все страницы не уничтожаются, а хранятся в памяти.

onPageSelected, position = 2
onPageSelected, position = 1
onPageSelected, position = 0

Т.к. не было никаких уничтожений, то нет и никаких созданий. Достает страницы-фрагменты из памяти и показывает.

Можно сделать вывод. Этот адаптер быстрый, т.к. не требует пересоздания. Но затратный, т.к. все держит в памяти. Т.е. подходит для небольшого количества страниц. Например, набор вкладок или визард.

Правда есть нюанс: хоть сами фрагменты и не уничтожаются, но уничтожается их View-структура и потом создается заново. Вставьте лог в метод onCreateView и убедитесь. Хранится структура только текущей страницы и по одной справа и слева. Это кол-во соседних страниц с сохраняемой View-структурой может быть настроено методом setOffscreenPageLimit.

FragmentStatePagerAdapter

Этот адаптер аналогичен FragmentPagerAdapter, он также работает с фрагментами. Но использует другие механизмы работы с страницами. Он не хранит страницы в памяти, а каждый раз создает их. Давайте используем его. Для этого надо в MainActivity.java просто заменить FragmentPagerAdapter на FragmentStatePagerAdapter в секции импорта и в описании класса MyFragmentPagerAdapter.

И все. Сохраняем, запускаем.

Открылась нулевая страница. В логах видим:

onCreate: 0
savedPageNumber = -1
onCreate: 1
savedPageNumber = -1

Перелистнем на первую страницу

onPageSelected, position = 1
onCreate: 2
savedPageNumber = -1

Пока что поведение не отличается от прошлого адаптера.

Перелистнем на вторую страницу.

onPageSelected, position = 2
onDestroy: 0
onCreate: 3
savedPageNumber = -1

Вот и отличие. Видим, что также открылась вторая страница, также создалась третья, но при этом уничтожилась нулевая.

Перелистнем на третью:

onPageSelected, position = 3
onDestroy: 1
onCreate: 4
savedPageNumber = -1

Та же ситуация: отобразилась третья, уничтожилась первая, создалась четвертая.

Перелистнем обратно на вторую:

onPageSelected, position = 2
onDestroy: 4
onCreate: 1
savedPageNumber = 1

Отобразилась вторая, уничтожилась четвертая, создалась первая (и прочла сохраненное значение из savedInstanceState).

Т.е. видно, что адаптер хранит только текущую страницу и по одной соседней (справа и слева), чтобы быстро можно было перелистнуть.

Можно сделать вывод. Этот адаптер не очень быстрый, он будет подтормаживать при многократном перелистывании в обе стороны, т.к. постоянно пересоздает страницы. Но при этом он требует минимум памяти. Т.е. он подходит для большого количества страниц. Например, просмотр писем, смс, страниц книги.

Используйте тот адаптер, который вам больше подходит в данной ситуации. Или наследуйте класс PagerAdapter и создавайте адаптер под свои нужды.

Программное перелистывание

Чтобы программно перелистнуть страницу ViewPager используйте метод setCurrentItem. А чтобы узнать текущую страницу — getCurrentItem.

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Оцените статью