Le Tutoriel de Android ViewPager2
1. Android ViewPager2 vs ViewPager
Android ViewPager est un composant d'interface introduit dans la bibliothèque de soutien d'Android. Cela permet à l'utilisateur de glisser (swipe) vers la gauche ou vers la droite afin d'afficher une toute nouvelle page (écran).
ViewPager/ViewPager2
Un ViewPager/ViewPager2 dont chaque page remplit l'écran, l'utilisateur peut glisser (swipe) vers la gauche pour passer à la page suivante ou vers la droite pour revenir à la page précédente.
Un ViewPager/ViewPager2 vu dans l'application d'apprentissage de langues étrangères Duolingo.
ViewPager2 vs ViewPager
Comme on le sait, l'équipe d'Android publie régulièrement des mises à jour et améliorations pour Android Framework. L'un des plus grands bénéficiaires est ViewPager2. ViewPager2 remplace ViewPager et dispose d'une meilleure efficience et des fonctions supplémentaires.
Quelles sont les nouveautés de ViewPager2?
- ViewPager2 est une version improvisée de ViewPager qui propose des fonctions supplémentaires et résout des problèmes courants dans ViewPager.
- ViewPager2 est bâti sur RecyclerView. Ainsi, vous pouvez profiter de grands avantages de RecyclerView. Par exemple: vous pouvez utiliser DiffUtils pour calculer efficacement les différences entre les ensembles de données et les améliorations de ViewPager via les animations.
- ViewPager2 soutient l'orientation verticale (Vertical Orientation). Si vous utilisez ViewPager, vous devez composer des personnalisations supplémentaires pour ViewPager pour obtenir les mêmes résultats.
- ViewPager2 soutient Right-to-Left (RTL) et cette fonction est activée automatiquement en fonction d'App Locale.
- Quand vous travaillez avec un ensemble de Fragment(s). Si l'un des Fragment(s) change d'interface, il suffit de lancer la méthode notifyDatasetChanged() pour mettre à jour efficacement l'interface de l'application.
- ViewPager2 soutient les transformations de page (transformation), c'est-à-dire que vous pouvez fournir des animations lors du passage d'une page à l'autre. Vous pouvez également écrire votre PageTransformer personnalisé.
- PagerAdapter est remplacé par RecyclerView.
- FragmentStatePagerAdapter est remplacé par FragmentStateAdapter.
Library
ViewPager2 est un composant non disponible dans la bibliothèque standard d'Android, donc, si vous voulez l'utiliser, il faut l'installer dans votre projet.
Vous pouvez installer ViewPager2 à partir de Palette dans la fenêtre de conception.
Après l'installation finale, vous trouvez la bibliothèque ViewPager2 déclarée dans build.gradle (Module: app).
implementation 'androidx.viewpager2:viewpager2:1.0.0'
2. Example: ViewPager2
Prendre un exemple à propos de ViewPager2 et utiliser Fragment comme plan directeur pour chaque page. Ci-dessous l'image d'aperçu de l'exemple:
- Le fichier fragment_employee_page.xml est un plan d'interface d'une page (Page).
- La classe EmployeePageFragment contient les données de l'objet Employee et les affiche sur une page (Page).
Dans Android Studio, créer un projet:
- File > New > New Project > Empty Activity
- Name: ViewPager2Example
- Package name: org.o7planning.viewpager2example
- Language: Java
Comme mentionné là-dessus, ViewPager2 est un composant non disponible dans la bibliothèque standard d'Android, donc, à l'étape suivante, il faut l'installer dans votre projet à partir de Palette de la fenêtre de design.
Et créer un Fragment (EmployeePageFragment) correspondant à une page (Page) de ViewPager2:
- File > New > Fragment > Fragment (Blank)
- Fragment Name: EmployeePageFragment
- Fragment Layout Name: fragment_page_employee
- Source Language: Java
Vous pouvez constater que deux fichiers sont créés:
Ensuite, ouvrir le fichier fragment_employee_page.xml pour concevoir son interface.
fragment_employee_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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView_fullName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:background="#C4CFB9"
android:gravity="center_horizontal"
android:text="Fullname"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView71"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:text="Position:"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView_fullName" />
<TextView
android:id="@+id/textView_position"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="(Position)"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textView71"
app:layout_constraintTop_toBottomOf="@+id/textView_fullName" />
<TextView
android:id="@+id/textView72"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:text="Email:"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView71" />
<TextView
android:id="@+id/textView_email"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="(Email)"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textView72"
app:layout_constraintTop_toBottomOf="@+id/textView71" />
</androidx.constraintlayout.widget.ConstraintLayout>
EmployeePageFragment.java
package org.o7planning.viewpager2example;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class EmployeePageFragment extends Fragment {
private static final String LOG_TAG = "AndroidExample";
private Employee employee;
private TextView textViewEmail;
private TextView textViewPosition;
private TextView textViewFullName;
private static int counter = 0;
// IMPORTANT:
// Required default public constructor.
// If configuration change.
// For example: User rotate the Phone,
// Android will create new Fragment (EmployeePageFragment) via default Constructor
// so this.employee will be null.
public EmployeePageFragment() {
}
public EmployeePageFragment(Employee employee) {
this.employee = employee;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = (ViewGroup) inflater.inflate(
R.layout.fragment_employee_page, container, false);
counter++;
if(counter % 2 == 0) {
view.setBackgroundColor(Color.parseColor("#ebdef0"));
} else {
view.setBackgroundColor(Color.parseColor("#e8f8f5"));
}
this.textViewFullName = view.findViewById(R.id.textView_fullName);
this.textViewPosition = view.findViewById(R.id.textView_position);
this.textViewEmail = view.findViewById(R.id.textView_email);
return view;
}
// Called when configuration change.
// For example: User rotate the Phone,
// Android will create new Fragment (EmployeePageFragment) object via default Constructor
// so this.employee will be null.
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
Log.i(LOG_TAG, "onSaveInstanceState: save employee data to Bundle");
// Convert employee object to Bundle.
Bundle dataBundle = this.employeeToBundle(this.employee);
outState.putAll(dataBundle);
super.onSaveInstanceState(outState);
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
Log.i(LOG_TAG, "onViewStateRestored");
super.onViewStateRestored(savedInstanceState);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
Log.i(LOG_TAG, "onViewCreated");
super.onViewCreated(view, savedInstanceState);
if(this.employee == null) {
Log.i(LOG_TAG, "Get employee data from savedInstanceState");
// The state was saved by onSaveInstanceState(Bundle outState) method.
this.employee = this.bundleToEmployee(savedInstanceState);
}
this.showInGUI(this.employee);
}
// Call where View ready.
private void showInGUI(Employee employee) {
this.textViewFullName.setText(employee.getFullName());
this.textViewPosition.setText(employee.getPosition());
this.textViewEmail.setText(employee.getEmail());
}
private Bundle employeeToBundle(Employee employee) {
Bundle bundle = new Bundle();
bundle.putString("fullName", employee.getFullName());
bundle.putString("position", employee.getPosition());
bundle.putString("email", employee.getEmail());
return bundle;
}
private Employee bundleToEmployee(Bundle savedInstanceState) {
String fullName = savedInstanceState.getString("fullName");
String position = savedInstanceState.getString("position");
String email = savedInstanceState.getString("email");
return new Employee(fullName, email, position);
}
}
EmployeeFragmentStateAdapter.java
package org.o7planning.viewpager2example;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.ArrayList;
import java.util.List;
public class EmployeeFragmentStateAdapter extends FragmentStateAdapter {
private List<Employee> employees;
public EmployeeFragmentStateAdapter(@NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);
this.employees = this.intDatas();
}
private List<Employee> intDatas() {
Employee emp1 = new Employee("James Smith", "jamessmith@example.com", "Web Designer");
Employee emp2 = new Employee("Elizabeth Johnson", "elizabethjohnson@example.com", "Project Manager");
Employee emp3 = new Employee("Catherine Johnson", "catherinejohnson@example.com", "President of Sales");
List<Employee> list = new ArrayList<Employee>();
list.add(emp1);
list.add(emp2);
list.add(emp3);
return list;
}
@NonNull
@Override
public Fragment createFragment(int position) {
Employee employee = this.employees.get(position);
return new EmployeePageFragment(employee);
}
@Override
public int getItemCount() {
return this.employees.size();
}
}
Employee.java
package org.o7planning.viewpager2example;
public class Employee {
private String fullName;
private String email;
private String position;
public Employee(String fullName, String email, String position) {
this.fullName = fullName;
this.email = email;
this.position = position;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
}
Voici l'interface principal de l'application:
activity_main.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager2_employee"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package org.o7planning.viewpager2example;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager2Employee;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.viewPager2Employee = findViewById(R.id.viewPager2_employee);
// Employee FragmentStateAdapter.
EmployeeFragmentStateAdapter adapter = new EmployeeFragmentStateAdapter(this);
this.viewPager2Employee.setAdapter(adapter);
}
}
3. Example: Transformation
Afin d'afficher les effets d'animation quand l'utilisateur fait défiler les pages, il est nécessaire d'écrire une classe qui installe (implements) l'interface de ViewPager2.PageTransformer et la fournit à l'objet ViewPager2.
ViewPager2 viewPager = findViewById(R.id.pager);
...
viewPager.setPageTransformer(new YourPageTransformer());
L'interface de ViewPager2.PageTransformer ne contient qu'une seule méthode transformPage(), qui est convoquée à chaque transition (transition).
/**
* Apply a property transformation to the given page.
*
* @param page Apply the transformation to this page
* @param position Position of page relative to the current front-and-center
* position of the pager. 0 is front and center. 1 is one full
* page position to the right, and -2 is two pages to the left.
* Minimum / maximum observed values depend on how many pages we keep
* attached, which depends on offscreenPageLimit.
*
* @see #setOffscreenPageLimit(int)
*/
void transformPage(@NonNull View page, float position);
Ajouter des effets d'animation dans l'exemple ci-dessous:
Zoom Out Page Transformer
ZoomOutPageTransformer.java
package org.o7planning.viewpager2example.transformer;
import android.view.View;
import androidx.viewpager2.widget.ViewPager2;
public class ZoomOutPageTransformer implements ViewPager2.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0f);
} else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA +
(scaleFactor - MIN_SCALE) /
(1 - MIN_SCALE) * (1 - MIN_ALPHA));
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0f);
}
}
}
MainActivity.java (Zoom Out Page Transformer)
package org.o7planning.viewpager2example;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import org.o7planning.viewpager2example.transformer.ZoomOutPageTransformer;
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager2Employee;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.viewPager2Employee = findViewById(R.id.viewPager2_employee);
// Employee FragmentStateAdapter.
EmployeeFragmentStateAdapter adapter = new EmployeeFragmentStateAdapter(this);
this.viewPager2Employee.setAdapter(adapter);
// PageTransformer
this.viewPager2Employee.setPageTransformer(new ZoomOutPageTransformer());
}
}
Depth Page Transformer
DepthPageTransformer.java
package org.o7planning.viewpager2example.transformer;
import android.view.View;
import androidx.annotation.RequiresApi;
import androidx.viewpager2.widget.ViewPager2;
@RequiresApi(21)
public class DepthPageTransformer implements ViewPager2.PageTransformer {
private static final float MIN_SCALE = 0.75f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0f);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1f);
view.setTranslationX(0f);
view.setTranslationZ(0f);
view.setScaleX(1f);
view.setScaleY(1f);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
// Move it behind the left page
view.setTranslationZ(-1f);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0f);
}
}
}
MainActivity.java (Depth Page Transformer)
package org.o7planning.viewpager2example;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Build;
import android.os.Bundle;
import org.o7planning.viewpager2example.transformer.DepthPageTransformer;
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager2Employee;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.viewPager2Employee = findViewById(R.id.viewPager2_employee);
// Employee FragmentStateAdapter.
EmployeeFragmentStateAdapter adapter = new EmployeeFragmentStateAdapter(this);
this.viewPager2Employee.setAdapter(adapter);
// PageTransformer
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Api 21+.
this.viewPager2Employee.setPageTransformer(new DepthPageTransformer());
}
}
}
Tutoriels de programmation Android
- Configurer Android Emulator en Android Studio
- Le Tutoriel de Android ToggleButton
- Créer un File Finder Dialog simple dans Android
- Le Tutoriel de Android TimePickerDialog
- Le Tutoriel de Android DatePickerDialog
- De quoi avez-vous besoin pour démarrer avec Android?
- Installer Android Studio sur Windows
- Installer Intel® HAXM pour Android Studio
- Le Tutoriel de Android AsyncTask
- Le Tutoriel de Android AsyncTaskLoader
- Tutoriel Android pour débutant - Exemples de base
- Comment connaître le numéro de téléphone d'Android Emulator et le changer?
- Le Tutoriel de Android TextInputLayout
- Le Tutoriel de Android CardView
- Le Tutoriel de Android ViewPager2
- Obtenir un numéro de téléphone dans Android à l'aide de TelephonyManager
- Le Tutoriel de Android Phone Call
- Le Tutoriel de Android Wifi Scanning
- Le Tutoriel de programmation de jeux Android 2D pour débutant
- Le Tutoriel de Android DialogFragment
- Le Tutoriel de Android CharacterPickerDialog
- Le Tutoriel Android pour débutant - Hello Android
- Utiliser Android Device File Explorer
- Activer USB Debugging sur un appareil Android
- Le Tutoriel de Android UI Layouts
- Le Tutoriel de Android SMS
- Le Tutoriel de Android et SQLite Database
- Le Tutoriel de Google Maps Android API
- Le Tutoriel de texte pour parler dans Android
- Le Tutoriel de Android Space
- Le Tutoriel de Android Toast
- Créer un Android Toast personnalisé
- Le Tutoriel de Android SnackBar
- Le Tutoriel de Android TextView
- Le Tutoriel de Android TextClock
- Le Tutoriel de Android EditText
- Le Tutoriel de Android TextWatcher
- Formater le numéro de carte de crédit avec Android TextWatcher
- Le Tutoriel de Android Clipboard
- Créer un File Chooser simple dans Android
- Le Tutoriel de Android AutoCompleteTextView et MultiAutoCompleteTextView
- Le Tutoriel de Android ImageView
- Le Tutoriel de Android ImageSwitcher
- Le Tutoriel de Android ScrollView et HorizontalScrollView
- Le Tutoriel de Android WebView
- Le Tutoriel de Android SeekBar
- Le Tutoriel de Android Dialog
- Le Tutoriel de Android AlertDialog
- Tutoriel Android RatingBar
- Le Tutoriel de Android ProgressBar
- Le Tutoriel de Android Spinner
- Le Tutoriel de Android Button
- Le Tutoriel de Android Switch
- Le Tutoriel de Android ImageButton
- Le Tutoriel de Android FloatingActionButton
- Le Tutoriel de Android CheckBox
- Le Tutoriel de Android RadioGroup et RadioButton
- Le Tutoriel de Android Chip et ChipGroup
- Utilisation des Image assets et des Icon assets d'Android Studio
- Configuration de la Carte SD pour Android Emulator
- Exemple ChipGroup et Chip Entry
- Comment ajouter des bibliothèques externes à Android Project dans Android Studio?
- Comment désactiver les autorisations déjà accordées à l'application Android?
- Comment supprimer des applications de Android Emulator?
- Le Tutoriel de Android LinearLayout
- Le Tutoriel de Android TableLayout
- Le Tutoriel de Android FrameLayout
- Le Tutoriel de Android QuickContactBadge
- Le Tutoriel de Android StackView
- Le Tutoriel de Android Camera
- Le Tutoriel de Android MediaPlayer
- Le Tutoriel de Android VideoView
- Jouer des effets sonores dans Android avec SoundPool
- Le Tutoriel de Android Networking
- Analyser JSON dans Android
- Le Tutoriel de Android SharedPreferences
- Le Tutorial de stockage interne Android (Internal Storage)
- Le Tutoriel de Android External Storage
- Le Tutoriel de Android Intents
- Exemple d'une Android Intent explicite, appelant une autre Intent
- Exemple de Android Intent implicite, ouvrez une URL, envoyez un email
- Le Tutoriel de Android Service
- Le Tutoriel Android Notifications
- Le Tutoriel de Android DatePicker
- Le Tutoriel de Android TimePicker
- Le Tutoriel de Android Chronometer
- Le Tutoriel de Android OptionMenu
- Le Tutoriel de Android ContextMenu
- Le Tutoriel de Android PopupMenu
- Le Tutoriel de Android Fragment
- Le Tutoriel de Android ListView
- Android ListView avec Checkbox en utilisant ArrayAdapter
- Le Tutoriel de Android GridView
Show More