Aller au contenu principal

ViewPager2 Examples

If you're an Android developer, you're probably familiar with ViewPager, a popular UI component that allows users to swipe between different fragments or views within an activity. Well, there's a new kid on the block: ViewPager2. In this article, we'll take a closer look at what ViewPager2 is, how it differs from its predecessor, and how you can use it in your own Android projects.

What is ViewPager2?

ViewPager2 is a new and improved version of the ViewPager component that was introduced in the Android Support Library. It was first released in 2019 as part of the AndroidX library, and it offers several improvements over the original ViewPager.

What are the improvements?

One of the biggest improvements in ViewPager2 is that it now supports vertical scrolling in addition to horizontal scrolling. This makes it much more flexible and allows you to create more complex layouts with less code.

Another improvement is that ViewPager2 now uses RecyclerView as its underlying implementation. This means that it inherits all of the performance benefits of RecyclerView, such as smooth scrolling and efficient memory usage.

Finally, ViewPager2 has a simplified API that makes it easier to use and more consistent with other Android components.

How do I use ViewPager2?

Using ViewPager2 in your Android project is fairly straightforward. First, you'll need to add the following dependency to your project's build.gradle file:

implementation 'androidx.viewpager2:viewpager2:1.0.0'

Next, you can add ViewPager2 to your layout file like this:

<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />

Once you've added ViewPager2 to your layout file, you can create an adapter to supply the content for each page. Here's an example adapter that uses fragments:

class MyPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
FragmentStateAdapter(fragmentManager, lifecycle) {

override fun getItemCount() = 3

override fun createFragment(position: Int) =
when (position) {
0 -> MyFragment1()
1 -> MyFragment2()
else -> MyFragment3()
}
}

In this example, the adapter creates three fragments, one for each page. You can customize this to fit your specific needs.

Finally, you can set the adapter on the ViewPager2 like this:

val viewPager = findViewById<ViewPager2>(R.id.view_pager)
viewPager.adapter = MyPagerAdapter(supportFragmentManager, lifecycle)

And that's it! You now have a fully functional ViewPager2 in your Android app.

Here are some features of ViewPager2:

Vertical orientation support

Unlike ViewPager which needs complex customization to achieve vertical paging, ViewPager2 provides this capability natively. It also of course provides horizontal paging. Enabling vertical or horizontal paging is as easy as it gets, all you need to do is provide the value for the android:orientation attribute in your xml layout:

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

You can also set this attribute programmatically using the setOrientation().

Right-to-left support

Based on the locale your app is being used in, you may want to support RTL(right-to-left) paging. Unlike ViewPager, ViewPager2 provides this capability natively and in fact automatically without any action from your part. This is done based on the users locale in the device.

However you can also set it manually in your layout as follows:

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

or programmatically using the setLayoutDirection() method.

Modifiable fragment collections

The collections assigned to ViewPager2 as the data source can be mutated. You do this by calling the notifyDatasetChanged(). This method updates the UI when that collection changes or is modified.

The advantage of this is that you can mutate or change your collection of fragments at runtime and ViewPager2 will refresh itself based on that without requiring rebinding.

DiffUtil

ViewPager2 also, unlike ViewPager supports DiffUtil. This is because it is built from RecyclerView. This not only makes the binding of fragments more efficient but also implies that ViewPager2 can natively take advantage of dataset change animations from the RecyclerView class.

Let's look at some examples.

Kotlin Android ViewPager2 Example

Step by step example on how to use ViewPager2 in Kotlin Android.

Step 1: Dependencies

Start by adding the ViewPager2 androidx dependency. We will also use a third party CircularIndicator to indicate the pages:

    // CircleIndicator
implementation 'me.relex:circleindicator:2.1.6'

// ViewPager2
implementation "androidx.viewpager2:viewpager2:1.0.0"

Step 2: Design Layout

We need two layouts. The first is a layout to represent a single page. Remember we will be swiping pages. This layout defines a single page:

item_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"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" >

<RadioButton
android:id="@+id/radioButton4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RadioButton" />

<RadioButton
android:id="@+id/radioButton3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RadioButton" />

<RadioButton
android:id="@+id/radioButton2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RadioButton" />

<RadioButton
android:id="@+id/radioButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RadioButton" />
</RadioGroup>

</androidx.constraintlayout.widget.ConstraintLayout>

Then another layout tobe inflated into the main activity. This is where you add the ViewPager2 as well as the CircleIndicator:

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">

<Button
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginBottom="16dp"
android:text="قبلی"
app:layout_constraintBottom_toTopOf="@+id/indicator"
app:layout_constraintStart_toStartOf="parent" />

<Button
android:id="@+id/btn_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:text="بعدی"
app:layout_constraintBottom_toTopOf="@+id/indicator"
app:layout_constraintEnd_toEndOf="parent" />

<me.relex.circleindicator.CircleIndicator3
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#1e88e5"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager2"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/indicator"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" >

</androidx.viewpager2.widget.ViewPager2>

</androidx.constraintlayout.widget.ConstraintLayout>

Step 3: Create ViewPager2 Adapter

Because as we had said earlier ViewPager2 is built on RecyclerView, it needs an adapter. But not a PagerAdapter like ViewPager, instead a RecyclerView.Adapter:

Here is an example of such an adapter:

ViewPagerAdapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

class ViewPagerAdapter(private val dataValue: List<String>, private val condition: ConditionViewPager) :
RecyclerView.Adapter<ViewPagerAdapter.ViewPagerViewHolder>() {

inner class ViewPagerViewHolder(view: View) : RecyclerView.ViewHolder(view) {

//val txt: TextView = view.findViewById(R.id.textView)

}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerViewHolder =
ViewPagerViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item_page, parent, false)
)

override fun onBindViewHolder(holder: ViewPagerViewHolder, position: Int) {
condition.condition(position,dataValue.size)
}

override fun getItemCount(): Int = dataValue.size

interface ConditionViewPager {

fun condition(position : Int, fullSize : Int)

}

}

Step 4: Write Activity Code

The next step is to write the main activity code. This is where you will connect the ViewPager2 with the CircleIndicator:

MainActivity.kt

package com.alirezabashi98.viewpager

import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager2.widget.ViewPager2
import me.relex.circleindicator.CircleIndicator3

class MainActivity : AppCompatActivity(), ViewPagerAdapter.ConditionViewPager {

private val data = mutableListOf<String>()
private lateinit var viewPager: ViewPager2
private lateinit var indicator: CircleIndicator3
private lateinit var btnNext: Button
private lateinit var btnBack: Button

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
castView()
addToList()

viewPager.adapter = ViewPagerAdapter(data, this)
viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL

indicator.setViewPager(viewPager)

btnNext.setOnClickListener {
viewPager.apply {
beginFakeDrag()
fakeDragBy(-10f)
endFakeDrag()
}
}

btnBack.setOnClickListener {
viewPager.apply {
beginFakeDrag()
fakeDragBy(10f)
endFakeDrag()
}
}

}

private fun castView() {

viewPager = findViewById(R.id.view_pager2)
indicator = findViewById(R.id.indicator)
btnNext = findViewById(R.id.btn_next)
btnBack = findViewById(R.id.btn_back)

}

private fun addToList() {
for (item in 1..20) {
data.add("item $item")
}
}

override fun condition(position: Int, fullSize: Int) {

if (position == fullSize) {
btnNext.text = "پایان"
}
Toast.makeText(this, "$position / $fullSize", Toast.LENGTH_SHORT).show()

}

}

Reference

Here are the reference links:

NumberLink
1.Download code
2.Follow code author
3.Read more about ViewPager2

Conclusion

ViewPager2 is a powerful and flexible UI component that offers several improvements over its predecessor. With support for vertical scrolling, improved performance, and a simplified API, it's a great choice for creating complex layouts in your Android apps. So why not give it a try in your next project?