ViewPager2 系列-- 初探ViewPager2

ViewPager2是什么

ViewPager2是Android Jetpack庫中的一個組件,是用于在應用程序中實現頁面切換和滑動效果的容器。

ViewPager2的作用和用途

ViewPager2是一個功能強大的滑動容器,可以應用于多種場景中,提供了靈活的頁面切換和布局定制功能,使得應用程序界面更加豐富和交互性強,可以用于以下場景:

  1. 實現引導頁或歡迎頁:ViewPager2可以用于創建引導頁或歡迎頁,讓用戶通過滑動瀏覽介紹應用程序功能或展示歡迎內容。

  2. 創建圖片瀏覽器:ViewPager2可以用于創建圖片瀏覽器,允許用戶通過滑動來切換不同的圖片,并支持縮放和手勢交互。

  3. 構建輪播圖:ViewPager2非常適合構建輪播圖功能,可以通過適配器動態加載不同的輪播項,并提供自動循環滾動的功能。

  4. 實現選項卡式布局:結合TabLayout,ViewPager2可以用于創建選項卡式布局,讓用戶通過滑動選項卡來切換不同的內容頁面。

  5. 創建垂直滑動頁面:與ViewPager不同,ViewPager2支持垂直方向的滑動,因此可以用于創建垂直滑動的頁面布局,例如垂直滑動的導航菜單或垂直的新聞列表。

  6. 實現分頁數據展示:ViewPager2可以用于展示分頁數據,例如將大量數據按頁加載并在每一頁中展示一部分內容。

  7. 嵌套滑動布局:ViewPager2可以與其他滑動組件(如RecyclerView)嵌套使用,實現復雜的滑動布局結構。

  8. 實現自定義的滑動效果:通過使用自定義的轉換器(Transformer),可以實現各種炫酷的頁面切換效果,例如漸變、縮放、旋轉等。

ViewPager2相較于ViewPager的改進和優勢

ViewPager2是對ViewPager的改進版本,提供了更好的性能、更靈活的適配器和更豐富的功能。它是構建滑動頁面布局的首選組件,可以在應用程序中實現各種滑動頁面的需求,并提供更好的用戶體驗,大致有以下幾點改進和優勢:

  1. 支持垂直滑動:ViewPager2是在ViewPager的基礎上進行改進的,最顯著的改進之一是支持垂直滑動。而在ViewPager中,只支持水平滑動。這使得ViewPager2在創建垂直布局或特定場景下的垂直滑動功能更加方便和靈活。

  2. 更好的性能和穩定性:ViewPager2內部實現使用了RecyclerView作為容器,而不再依賴于ViewPager的實現方式。這使得ViewPager2具有RecyclerView的優勢,例如更好的性能和內存管理、更流暢的滑動體驗以及更好的布局回收和復用機制。同時,ViewPager2還解決了ViewPager一些已知的問題和不穩定性,如條目位置錯亂、刷新數據的不及時等。

  3. 支持使用Fragment作為頁面:與ViewPager不同,ViewPager2直接支持使用Fragment作為頁面,而無需通過FragmentPagerAdapter或FragmentStatePagerAdapter進行適配。這簡化了頁面管理和生命周期處理,并提供了更直觀和一致的使用體驗。

  4. 更靈活的適配器:ViewPager2引入了新的適配器接口,即RecyclerView.Adapter的子類RecyclerView.Adapter。這使得適配器的創建和管理更加靈活,同時提供了更多的功能和擴展性。

  5. 更豐富的功能和接口:ViewPager2提供了許多新的功能和接口,例如支持頁面預加載、更強大的頁面切換動畫支持、更豐富的回調接口等。這些功能和接口使得開發者能夠更好地控制和定制ViewPager2的行為和外觀。

環境配置和依賴

  1. 在你的項目模塊的build.gradle文件中,添加以下依賴項:
dependencies {
    // ...
    implementation 'androidx.viewpager2:viewpager2:1.0.0'
}

  1. 確保你的項目使用了AndroidX,可以在gradle.properties文件中添加以下配置:
arduinoCopy code
android.useAndroidX=true
android.enableJetifier=true

ViewPager2基本用法

  • 創建一個包含ViewPager2的布局文件

  • 在Activity或Fragment中查找和實例化ViewPager2

  • 創建和設置適配器(Adapter)來管理ViewPager2的內容

  • 設置適配器到ViewPager2實例

與View結合使用

以下是使用Kotlin的ViewPager2基本用法示例:

  1. 在XML布局文件中定義ViewPager2:
<androidx.viewpager2.widget.ViewPager2
    android:id="@+id/viewPager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

  1. 在Activity或Fragment中,獲取ViewPager2實例并設置適配器:
val viewPager: ViewPager2 = findViewById(R.id.viewPager)
val adapter = MyAdapter() // 自定義適配器,需要繼承RecyclerView.Adapter<ViewHolder>
viewPager.adapter = adapter

  1. 創建自定義適配器MyAdapter,繼承自RecyclerView.Adapter<ViewHolder>
class MyAdapter : RecyclerView.Adapter<MyViewHolder>() {

    // 在這里定義你的數據源
    private val dataList: MutableList<String> = mutableListOf()

    // 添加數據到數據源
    fun setData(data: List<String>) {
        dataList.clear()
        dataList.addAll(data)
        notifyDataSetChanged()
    }

    // 創建ViewHolder
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_view, parent, false)
        return MyViewHolder(view)
    }

    // 綁定數據到ViewHolder
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val data = dataList[position]
        holder.bindData(data)
    }

    // 返回數據源的大小
    override fun getItemCount(): Int {
        return dataList.size
    }
}

  1. 創建ViewHolder類MyViewHolder,繼承自RecyclerView.ViewHolder
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    private val textView: TextView = itemView.findViewById(R.id.textView)

    fun bindData(data: String) {
        textView.text = data
    }
}

  1. item_view.xml布局文件中定義每個頁面的布局,例如一個簡單的TextView:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/itemLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="16sp"
    android:padding="16dp" />

</LinearLayout>

注意:布局文件的根視圖的寬度和高度設置為match_parent ,否則會報錯:

java.lang.IllegalStateException: Pages must fill the whole ViewPager2 (use match_parent)

通過上述步驟,就可以在ViewPager2中顯示自定義的頁面,并通過適配器來管理數據源和頁面布局。

與Fragment結合使用

ViewPager2除了配合View使用,更多會和Fragment結合使用,此時我們只需要借助FragmentStateAdapter,簡單實現如下:


class MyFragmentStateAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {

    private val fragmentList = listOf(
        FirstFragment(),
        SecondFragment(),
        ThirdFragment()
    )

    override fun getItemCount(): Int {
        return fragmentList.size
    }

    override fun createFragment(position: Int): Fragment {
        return fragmentList[position]
    }
}

然后,在MainActivity中使用ViewPager2和適配器:


class MainActivity : AppCompatActivity() {

    private lateinit var viewPager: ViewPager2

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

        viewPager = findViewById(R.id.viewPager)
        val adapter = MyFragmentStateAdapter(this)
        viewPager.adapter = adapter
    }
}

如何監聽頁面切換事件

要監聽頁面切換事件,你可以在 ViewPager2 上設置一個 OnPageChangeCallback 對象來監聽頁面的變化。OnPageChangeCallback 提供了幾個方法,可以在頁面被選中、滾動和滾動狀態改變時觸發相應的回調。

下面是一個示例,展示了如何監聽頁面切換事件:

import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback

class MainActivity : AppCompatActivity() {

    private lateinit var viewPager: ViewPager2

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

        viewPager = findViewById(R.id.viewPager)

        // 設置頁面切換監聽
        viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                // 當頁面選中時觸發回調
                // 在這里可以根據需要執行相應的操作
            }

            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {
                // 當頁面滾動時觸發回調
                // 在這里可以根據需要執行相應的操作
            }

            override fun onPageScrollStateChanged(state: Int) {
                // 當頁面滾動狀態改變時觸發回調
                // 在這里可以根據需要執行相應的操作
            }
        })
    }
}

頁面滾動狀態都有哪些

ViewPager2 的頁面滾動狀態有三種,分別對應不同的整數值:

  1. ViewPager2.SCROLL_STATE_IDLE(值為 0):空閑狀態。表示當前頁面處于靜止狀態,沒有正在進行的滾動操作。

  2. ViewPager2.SCROLL_STATE_DRAGGING(值為 1):拖動狀態。表示用戶正在拖動頁面,準備進行滾動操作。

  3. ViewPager2.SCROLL_STATE_SETTLING(值為 2):滾動狀態。表示頁面正在自動滾動到最終的位置。

可以通過 ViewPager2.OnPageChangeCallbackonPageScrollStateChanged() 方法中的 state 參數獲取當前的頁面滾動狀態。根據不同的狀態值,可以執行相應的操作,例如顯示加載指示器、更新界面等。

自定義動畫切換動畫和過渡效果

要自定義頁面切換動畫和過渡效果,我們可以使用 ViewPager2.PageTransformer 接口來實現。PageTransformer 允許在頁面切換時對頁面應用自定義的動畫和過渡效果。

下面是一個示例,展示了如何自定義頁面切換動畫和過渡效果:

import android.view.View
import androidx.viewpager2.widget.ViewPager2

class CustomPageTransformer : ViewPager2.PageTransformer {

    override fun transformPage(page: View, position: Float) {
        val absPosition = Math.abs(position)

        // 在這里根據需要對頁面進行自定義動畫和過渡效果的操作

        // 例如,可以對頁面進行縮放和透明度變化
        page.scaleY = 0.85f + (1f - 0.85f) * (1f - absPosition)
        page.alpha = 0.5f + (1f - 0.5f) * (1f - absPosition)
    }
}

在上述示例中,我們創建了一個名為 CustomPageTransformer 的類,并實現了 ViewPager2.PageTransformer 接口。在 transformPage() 方法中,我們可以根據需要對每個頁面進行自定義的動畫和過渡效果。

在這個示例中,我們對頁面進行了簡單的縮放和透明度變化。根據頁面的位置(position),我們設置了不同的縮放和透明度值。

接下來,將 CustomPageTransformer 應用到 ViewPager2 上:

val viewPager: ViewPager2 = findViewById(R.id.viewPager)
val adapter = MyAdapter()
viewPager.adapter = adapter

val pageTransformer = CustomPageTransformer()
viewPager.setPageTransformer(pageTransformer)

在這個示例中,我們首先實例化了 ViewPager2 和適配器 MyAdapter。然后,我們創建了 CustomPageTransformer 的實例,并通過 setPageTransformer() 方法將其應用到 ViewPager2 上。

如何禁用或限制頁面切換

要禁用或限制頁面切換,可以使用 ViewPager2.OnPageChangeCallback 監聽器來控制頁面切換的行為。通過在回調方法中處理邏輯,你可以決定是否允許頁面切換。

下面是一個示例,展示了如何禁用或限制頁面切換:

import androidx.viewpager2.widget.ViewPager2

class CustomOnPageChangeCallback : ViewPager2.OnPageChangeCallback() {

    private var isPageChangeEnabled = true

    fun setPageChangeEnabled(enabled: Boolean) {
        isPageChangeEnabled = enabled
    }

    override fun onPageSelected(position: Int) {
        if (!isPageChangeEnabled) {
            // 如果頁面切換被禁用,則強制將選中的頁面切換回原始位置
            // 這樣可以避免用戶手動滑動頁面
            val viewPager = /* 獲取 ViewPager2 實例 */
            viewPager.setCurrentItem(/* 原始位置 */, false)
        }
    }

    override fun onPageScrollStateChanged(state: Int) {
        if (!isPageChangeEnabled && state == ViewPager2.SCROLL_STATE_DRAGGING) {
            // 如果頁面切換被禁用,并且用戶嘗試拖動頁面,
            // 則強制將滾動狀態設置為 SCROLL_STATE_IDLE,防止頁面滾動
            val viewPager = /* 獲取 ViewPager2 實例 */
            viewPager.scrollToPosition(/* 原始位置 */)
        }
    }
}

在上述示例中,我們創建了一個名為 CustomOnPageChangeCallback 的類,繼承自 ViewPager2.OnPageChangeCallback。我們添加了一個 setPageChangeEnabled() 方法,用于啟用或禁用頁面切換。

onPageSelected() 方法中,我們檢查 isPageChangeEnabled 的狀態。如果頁面切換被禁用,我們使用 ViewPager2 實例將選中的頁面切換回原始位置,這樣可以防止用戶手動滑動頁面。

onPageScrollStateChanged() 方法中,我們檢查 isPageChangeEnabled 的狀態以及滾動狀態。如果頁面切換被禁用,并且用戶嘗試拖動頁面,我們強制將滾動狀態設置為 SCROLL_STATE_IDLE,這樣可以防止頁面滾動。

然后,將 CustomOnPageChangeCallback 應用到 ViewPager2 上:

val viewPager: ViewPager2 = findViewById(R.id.viewPager)
val adapter = MyAdapter()
viewPager.adapter = adapter

val onPageChangeCallback = CustomOnPageChangeCallback()
viewPager.registerOnPageChangeCallback(onPageChangeCallback)

在這個示例中,我們首先實例化了 ViewPager2 和適配器 MyAdapter。然后,我們創建了 CustomOnPageChangeCallback 的實例,并通過 registerOnPageChangeCallback() 方法將其注冊到 ViewPager2 上。

要禁用或啟用頁面切換,只需調用 setPageChangeEnabled() 方法并傳遞相應的參數即可:

onPageChangeCallback.setPageChangeEnabled(false) // 禁用頁面切換
onPageChangeCallback.setPageChangeEnabled(true)

滑動方向設置

要設置 ViewPager2 的滑動方向,你可以通過設置 Orientation 屬性來實現。ViewPager2 支持兩種滑動方向:水平滑動和垂直滑動。

在布局文件中,將 ViewPager2android:orientation 屬性設置為 horizontal(水平滑動)或 vertical(垂直滑動)即可。

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

在上述示例中,我們將 ViewPager2android:orientation 屬性設置為 "horizontal",以實現水平滑動。如果你想實現垂直滑動,只需將屬性值設置為 "vertical"

頁面預加載

要設置 ViewPager2 的頁面預加載數量,你可以使用 setOffscreenPageLimit() 方法。setOffscreenPageLimit() 方法用于設置 ViewPager2 在當前頁面附近預加載的頁面數量。

默認情況下,ViewPager2 的頁面預加載數量為 1,即當前頁面的左右各一個頁面會被預加載。你可以根據需要增加或減少預加載的頁面數量。

以下是示例代碼,展示了如何設置 ViewPager2 的頁面預加載數量為 2:

val viewPager: ViewPager2 = findViewById(R.id.viewPager)
viewPager.offscreenPageLimit = 2

在上述示例中,我們通過 viewPager.offscreenPageLimit 屬性將頁面預加載數量設置為 2。這意味著在當前頁面的左右各兩個頁面會被預加載。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容