codestory

Die Anleitung zu Android ViewPager2

  1. Android ViewPager2 vs ViewPager
  2. Example: ViewPager2
  3. Example: Transformation

1. Android ViewPager2 vs ViewPager

Android ViewPager ist eine Interface-Komponente, die in der Unterstützungsbibliothek von Android eingeführt wurde. Der Benutzer kann nach links oder rechts wischen, um eine völlig neue Seite (Bildschirm) anzuzeigen.
ViewPager/ViewPager2
Ein ViewPager/ViewPager2, bei dem jede Seite den Bildschirm ausfüllt. Der Benutzer wischt nacht links, um zur nächsten Seite zu gelangen, oder nach rechts, um eine Seite zurück zu kehren.
Ein ViewPager/ViewPager2, der in der Sprachlern-Anwendung Duolingo angezeigt wird.
ViewPager2 vs ViewPager
Wie wir alle wissen, veröffentlicht das Team Android ständig neue Updates und Verbesserung für das Android Framework. Eine der Komponenten, die wichtige Updates erhalten haben, ist ViewPager2. ViewPager2 ist der Ersatz für ViewPager und hat nur wenige Leistungsverbesserungen und zusätzliche Funktionen erhalten.
So what's new in ViewPager2?
  • ViewPager2 ist eine improvisierte Version von ViewPager, die zusätzliche Funktionen bietet und häufig auftretende Probleme in ViewPager behebt.
  • ViewPager2 basiert auf RecyclerView. Deshalb haben Sie die größen Vorteile, die RecyclerView bietet. Z.B: Sie können DiffUtils benutzen, um die Differenz zwischen Datensätzen effizient zu berechnen und den ViewPager mit Animation zu aktualisieren.
  • ViewPager2 unterstützt die vertikale Ausrichtung. Wenn Sie ViewPager verwenden, müssen Sie die zusätzlichen Anpassungen für ViewPager schreiben um dieselben Ergebnisse zu erhalten.
  • ViewPager2 unterstütz Right-to-Left (RTL) und das wird automatisch basierend auf App Locale aktiviert.
  • Bei der Arbeit mit einer Reihe von Fragment. Wenn eines der Fragment seine Interface ändert, sollten Sie die Methode notifyDatasetChanged() aufrufen um die Interface der Anwendung ordnungsgemäß zu aktualisieren.
  • ViewPager2 unterstützt die Seitentransformation, d.h Sie können bei der Seitentransformation die Animation bereitstellen. Sie können auch Ihren eigenen benutzerdefinierten PageTransformer schreiben.
  • PagerAdapter wird durch RecyclerView ersetzt.
  • FragmentStatePagerAdapter wird durch FragmentStateAdapter ersetzt.
Library
ViewPager2 ist eine Komponente, die in der Standardbibliothek von Android nicht verfügbar ist. Wenn Sie sie benutzen möchten, sollten Sie sie in Ihrem Projekt installieren.
Sie können ViewPager2 aus Palette vom Design-Fenster installieren.
Nach der vollständigen Installation wird die Bibliothek ViewPager2 in build.gradle (Module: app) deklariert.
implementation 'androidx.viewpager2:viewpager2:1.0.0'

2. Example: ViewPager2

Jetzt üben wir ein Beispiel für ViewPager2 und verwenden Fragment als ein Design für jede Seite. Hier ist das Vorschaubild des Beispiel:
  • Die Datei fragment_employee_page.xml ist die Interface-Design einer Seite (Page).
  • Die Klasse EmployeePageFragment enthältet die Daten eines Objekt Employee und zeigt sie in einer Seite (Page).
Auf Android Studio erstellen Sie ein neues Projekt:
  • File > New > New Project > Empty Activity
    • Name: ViewPager2Example
    • Package name: org.o7planning.viewpager2example
    • Language: Java
Wie oben erwähnt ist ViewPager2 eine Komponente, die in der Standardbibliothek von Android nicht verfügbar ist. Daher müssen Sie es im nächsten Schritt über Palette vom das Designfenster in Ihr Projekt installieren.
Und dann erstellen Sie ein Fragment (EmployeePageFragment), das einer Seite (Page) von ViewPager2 entspricht:
  • File > New > Fragment > Fragment (Blank)
  • Fragment Name: EmployeePageFragment
  • Fragment Layout Name: fragment_page_employee
  • Source Language: Java
Jetzt können Sie sehen, dass zwei Datei erstellt werden:
Zum nächsten öffnen Sie die Datei fragment_employee_page.xml um die Interface zu entwerfen.
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;
    }

}
Die Hauptinterface der Anwendung:
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

Um den Animationseffekt bei der Seitentransformation anzuzeigen, müssen Sie eine Klasse schreiben, die die Interface ViewPager2.PageTransformer implementiert und für das Objekt ViewPager2 bereitstellt.
ViewPager2 viewPager = findViewById(R.id.pager);
...
viewPager.setPageTransformer(new YourPageTransformer());
Die Interface ViewPager2.PageTransformer hat nur die einzige Methode transformPage(),. Diese Methode wird bei jeder Transittion einmal aufgeruft.
/**
 * 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);
Weiter mit dem obigen Beispiel werden wir die Animationseffekt hinzufügen.
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());
        }
    }

}

Anleitungen Android

Show More