Перегортання сторінок і ViewPager2

Нерідко можна зустріти додатки, які реалізують систему перегортання, а сам додаток постає у вигляді набору сторінок, які можна перегортати ліворуч і праворуч. У додатку Android для створення подібного ефекту можна використовувати елемент ViewPager2 з комплекту JetPack. Для створення ефекту сторінок ViewPager2 використовує фрагменти.

Отже, створимо новий проєкт. Додамо в папку res/layout файл розмітки для фрагмента, який представлятиме сторінку. Назвемо його fragment_page.xml і визначимо в ньому такий код:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/displayText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

Фрагмент відображатиме текстове поле з номером сторінки.

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

package com.example.viewpagerapp;
 
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
 
import androidx.fragment.app.Fragment;
 
public class PageFragment extends Fragment {
 
    private int pageNumber;
 
    public static PageFragment newInstance(int page) {
        PageFragment fragment = new PageFragment();
        Bundle args=new Bundle();
        args.putInt("num", page);
        fragment.setArguments(args);
        return fragment;
    }
 
    public PageFragment() {
    }
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        pageNumber = getArguments() != null ? getArguments().getInt("num") : 1;
    }
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View result=inflater.inflate(R.layout.fragment_page, container, false);
        TextView pageHeader = result.findViewById(R.id.displayText);
        String header = "Фрагмент " + (pageNumber+1);
        pageHeader.setText(header);
        return result;
    }
}

Змінна pageNumber вказує на номер поточної сторінки. Номер сторінки буде передаватися ззовні через фабричний метод newInstance(). Передача номера відбувається шляхом додавання значення в аргумент "num"

Потім при створенні фрагмента в методі onCreate() цей номер буде витягуватися з аргументу "num" (якщо аргументи визначені):

pageNumber = getArguments() != null ? getArguments().getInt("num") : 1;

У методі onCreateView() отриманий номер сторінки буде відображатися в текстовому полі.

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

package com.example.viewpagerapp;
 
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
 
public class MyAdapter extends FragmentStateAdapter {
    public MyAdapter(FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }
 
    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return(PageFragment.newInstance(position));
    }
 
    @Override
    public int getItemCount() {
        return 10;
    }
}

Клас FragmentStateAdapter визначає два методи:

  • int getItemCount(): повертає кількість сторінок, які будуть у ViewPager2 (у нашому випадку 10)
  • Fragment createFragment(int position): за номером сторінки, що передається як параметр position, повертає об'єкт фрагмента

Варто зазначити, що як параметр конструктор FragmentStateAdapter приймає контекст виконання - зазвичай це об'єкт FragmentActivity, але також це може бути об'єкт Fragment

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

<androidx.viewpager2.widget.ViewPager2
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"  />

І також змінимо код MainActivity:

package com.example.viewpagerapp;
 
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
 
import android.os.Bundle;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        ViewPager2 pager = findViewById(R.id.pager);
        FragmentStateAdapter pageAdapter = new MyAdapter(this);
        pager.setAdapter(pageAdapter);
    }
}

Клас MainActivity наслідує AppCompatActivity - класу, який своєю чергою наслідує FragmentActivity, і тому її поточний об'єкт ми можемо передати як параметр у конструктор MyAdapter (а через нього - у конструктор FragmentStateAdapter). Щоб перегортання запрацювало, для ViewPager2 встановлюється адаптер MyAdapter.

І запустивши проєкт, ми зможемо за допомогою перегортання переміщатися сторінками: