ViewPager2
คือไลบรารี ViewPager
เวอร์ชันปรับปรุงซึ่งนำเสนอ
ฟังก์ชันการทำงานที่ได้รับการปรับปรุงและจัดการกับปัญหาทั่วไปในการใช้งาน ViewPager
หากแอปใช้ ViewPager
อยู่แล้ว โปรดอ่านหน้านี้เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับ
กำลังย้ายข้อมูลไปยัง ViewPager2
หากคุณต้องการใช้ ViewPager2
ในแอปและไม่ได้ใช้งานอยู่ในปัจจุบัน
ViewPager
โปรดอ่านสไลด์ระหว่างส่วนย่อยโดยใช้
ViewPager2 และสร้างมุมมองการปัดด้วย
แท็บต่างๆ ที่ใช้ ViewPager2 เพื่อดูเนื้อหาเพิ่มเติม
ประโยชน์ของการย้ายข้อมูลไปยัง ViewPager2
เหตุผลหลักในการย้ายข้อมูลคือ ViewPager2
ได้รับการใช้งานอยู่
การสนับสนุนการพัฒนาซอฟต์แวร์ และ ViewPager
ไม่ได้ อย่างไรก็ตาม ViewPager2
ยังนำเสนอ
ข้อได้เปรียบเฉพาะอื่นๆ อีกหลายประการ
รองรับการวางในแนวตั้ง
ViewPager2
รองรับการแบ่งหน้าแนวตั้งนอกเหนือจากแนวนอนแบบดั้งเดิม
การแบ่งหน้า คุณเปิดใช้การแบ่งหน้าแนวตั้งสำหรับองค์ประกอบ ViewPager2
ได้โดยการตั้งค่า
แอตทริบิวต์ android:orientation
:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:orientation="vertical" />
คุณยังตั้งค่าแอตทริบิวต์นี้แบบเป็นโปรแกรมได้โดยใช้ setOrientation()
การสนับสนุนการเขียนจากขวาไปซ้าย
ViewPager2
รองรับการแบ่งหน้าจากขวาไปซ้าย (RTL) เปิดใช้การแบ่งหน้า RTL แล้ว
โดยอัตโนมัติตามความเหมาะสม โดยอิงตามภาษา แต่คุณสามารถ
เปิดใช้การแบ่งหน้า RTL สำหรับองค์ประกอบ ViewPager2
โดยการตั้งค่า
แอตทริบิวต์ android:layoutDirection
:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layoutDirection="rtl" />
คุณยังตั้งค่าแอตทริบิวต์นี้แบบเป็นโปรแกรมได้โดยใช้ setLayoutDirection()
คอลเล็กชันส่วนย่อยที่แก้ไขได้
ViewPager2
รองรับการแบ่งหน้าผ่านคอลเล็กชัน Fragment ที่แก้ไขได้
การโทร
notifyDatasetChanged()
เพื่ออัปเดต UI เมื่อคอลเล็กชันที่สำคัญมีการเปลี่ยนแปลง
ซึ่งหมายความว่าแอปสามารถแก้ไขคอลเล็กชัน Fragment แบบไดนามิกได้ที่
และ ViewPager2
จะแสดงคอลเล็กชันที่แก้ไขแล้วได้อย่างถูกต้อง
ดิฟยูทิล
ViewPager2
สร้างเมื่อวันที่ RecyclerView
ซึ่งหมายความว่าแอปสามารถเข้าถึง
ยูทิลิตี DiffUtil
ทำให้คุณได้รับประโยชน์หลายอย่าง แต่ที่เห็นได้ชัดที่สุดคือ
ออบเจ็กต์ ViewPager2
รายการจะใช้ประโยชน์จากภาพเคลื่อนไหวสำหรับการเปลี่ยนแปลงชุดข้อมูลโดยค่าเริ่มต้น
จากชั้นเรียน RecyclerView
ย้ายข้อมูลแอปไปยัง ViewPager2
ทำตามขั้นตอนต่อไปนี้เพื่ออัปเดตออบเจ็กต์ ViewPager
รายการในแอปเป็น ViewPager2
อัปเดตไฟล์เลย์เอาต์ XML
ก่อนอื่นให้แทนที่องค์ประกอบ ViewPager
ในไฟล์เลย์เอาต์ XML ด้วย
ViewPager2
องค์ประกอบ:
<!-- A ViewPager element -->
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- A ViewPager2 element -->
<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" />
อัปเดตคลาสอะแดปเตอร์
เมื่อใช้ ViewPager
คุณต้องขยายคลาสอะแดปเตอร์ที่
ระบุหน้าใหม่ให้กับออบเจ็กต์ ViewPager
ใช้ไปแล้ว ทั้งนี้ขึ้นอยู่กับกรณีการใช้งาน
คลาสนามธรรมที่แตกต่างกัน 3 คลาส ViewPager2
ใช้คลาสนามธรรมเพียง 2 คลาส
สำหรับออบเจ็กต์ ViewPager
แต่ละรายการที่คุณกำลังแปลงเป็นออบเจ็กต์ ViewPager2
อัปเดตคลาสอะแดปเตอร์เพื่อขยายคลาส Abstract ที่เหมาะสมดังนี้
- เมื่อ
ViewPager
ใช้PagerAdapter
เพื่อเลื่อนดูหน้าเว็บ ให้ใช้RecyclerView.Adapter
กับViewPager2
- เมื่อ
ViewPager
ใช้FragmentPagerAdapter
เพื่อเลื่อนดู จำนวนคงที่ของส่วนย่อย ให้ใช้FragmentStateAdapter
กับViewPager2
- เมื่อ
ViewPager
ใช้FragmentStatePagerAdapter
เพื่อแบ่งหน้า ส่วนย่อยจำนวนมากหรือไม่ทราบจำนวน ให้ใช้FragmentStateAdapter
กับViewPager2
พารามิเตอร์ตัวสร้าง
คลาสอะแดปเตอร์ที่อิงตาม Fragment ที่รับช่วงมาจาก FragmentPagerAdapter
หรือ
FragmentStatePagerAdapter
ยอมรับออบเจ็กต์ FragmentManager
รายการเดียวเสมอ
เป็นพารามิเตอร์ตัวสร้าง เมื่อคุณขยายเวลา FragmentStateAdapter
เป็นเวลา
ประเภทอะแดปเตอร์ ViewPager2
คุณมีตัวเลือกต่อไปนี้สำหรับตัวสร้าง
แทน:
- ออบเจ็กต์
FragmentActivity
หรือออบเจ็กต์Fragment
ที่ มีออบเจ็กต์ViewPager2
รายการ ในกรณีส่วนใหญ่ ตัวเลือกนี้เหมาะสมกว่า - ออบเจ็กต์
FragmentManager
และออบเจ็กต์Lifecycle
คลาสอะแดปเตอร์ที่อิงตามการดูที่รับช่วงมาจาก RecyclerView.Adapter
โดยตรง
ไม่จำเป็นต้องใช้พารามิเตอร์ตัวสร้าง
วิธีการลบล้าง
คลาสอะแดปเตอร์ยังต้องลบล้างเมธอดต่างๆ สำหรับ ViewPager2
ด้วย
เมื่อเทียบกับ ViewPager
- ลบล้าง
getItemCount()
แทนgetCount()
นอกเหนือจากชื่อ วิธีการนี้จะไม่มีการเปลี่ยนแปลง - แทนที่
getItem()
ให้ลบล้างcreateFragment()
ในส่วนย่อย คลาสอะแดปเตอร์ใหม่ ตรวจสอบว่าใช้เมธอดcreateFragment()
ใหม่เสมอ จะใส่อินสแตนซ์ส่วนย่อยใหม่ทุกครั้งที่มีการเรียกฟังก์ชัน การนำอินสแตนซ์มาใช้ซ้ำ
สรุป
กล่าวโดยสรุปคือ หากต้องการแปลงคลาสอะแดปเตอร์ ViewPager
เพื่อใช้กับ ViewPager2
คุณต้องทำการเปลี่ยนแปลงต่อไปนี้
- เปลี่ยน Superclass เป็น
RecyclerView.Adapter
สำหรับการแบ่งหน้ายอดดู หรือFragmentStateAdapter
สำหรับการแบ่งหน้าส่วนย่อย - เปลี่ยนพารามิเตอร์ตัวสร้างในคลาสอะแดปเตอร์ที่อิงตาม Fragment
- ลบล้าง
getItemCount()
แทนgetCount()
- ลบล้าง
createFragment()
แทนgetItem()
ในอะแดปเตอร์ที่อิงตาม Fragment ใหม่
Kotlin
// A simple ViewPager adapter class for paging through fragments class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { override fun getCount(): Int = NUM_PAGES override fun getItem(position: Int): Fragment = ScreenSlidePageFragment() } // An equivalent ViewPager2 adapter class class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) { override fun getItemCount(): Int = NUM_PAGES override fun createFragment(position: Int): Fragment = ScreenSlidePageFragment() }
Java
// A simple ViewPager adapter class for paging through fragments public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter { public ScreenSlidePagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return new ScreenSlidePageFragment(); } @Override public int getCount() { return NUM_PAGES; } } // An equivalent ViewPager2 adapter class private class ScreenSlidePagerAdapter extends FragmentStateAdapter { public ScreenSlidePagerAdapter(FragmentActivity fa) { super(fa); } @Override public Fragment createFragment(int position) { return new ScreenSlidePageFragment(); } @Override public int getItemCount() { return NUM_PAGES; } }
เปลี่ยนโครงสร้างภายในอินเทอร์เฟซ TabLayout
ViewPager2
มีการเปลี่ยนแปลงในการผสานรวม TabLayout
หากคุณ
กำลังใช้ ViewPager
กับออบเจ็กต์ TabLayout
เพื่อแสดงแนวนอน
สำหรับการไปยังส่วนต่างๆ คุณต้องเปลี่ยนโครงสร้างภายในโค้ดของออบเจ็กต์ TabLayout
การผสานรวมกับ ViewPager2
TabLayout
ถูกแยกออกจาก ViewPager2
แล้ว และขณะนี้พร้อมให้บริการโดยเป็นส่วนหนึ่งของ
ส่วนประกอบของวัสดุ ซึ่งหมายความว่าคุณจะต้องเพิ่ม
ทรัพยากร Dependency ที่เหมาะสมสำหรับไฟล์ build.gradle
:
ดึงดูด
implementation "com.google.android.material:material:1.1.0-beta01"
Kotlin
implementation("com.google.android.material:material:1.1.0-beta01")
คุณต้องเปลี่ยนตำแหน่งขององค์ประกอบ TabLayout
ในลำดับชั้นของ
ไฟล์เลย์เอาต์ XML ของคุณ เมื่อใช้ ViewPager
ระบบจะประกาศองค์ประกอบ TabLayout
เป็น
ย่อยขององค์ประกอบ ViewPager
แต่เมื่อมี ViewPager2
องค์ประกอบ TabLayout
มีการประกาศโดยตรงเหนือองค์ประกอบ ViewPager2
ในระดับเดียวกัน
<!-- A ViewPager element with a TabLayout -->
<androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.viewpager.widget.ViewPager>
<!-- A ViewPager2 element with a TabLayout -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
สุดท้าย คุณต้องอัปเดตโค้ดที่แนบออบเจ็กต์ TabLayout
เข้ากับ
ViewPager
ออบเจ็กต์ ขณะที่ TabLayout
ใช้ setupWithViewPager()
ของตนเอง
ในการผสานรวมกับ ViewPager
ก็ต้องใช้ TabLayoutMediator
อินสแตนซ์ที่จะผสานรวมกับ ViewPager2
ออบเจ็กต์ TabLayoutMediator
จัดการงานสร้างชื่อหน้าเว็บด้วย
สำหรับออบเจ็กต์ TabLayout
ซึ่งหมายความว่าคลาสอะแดปเตอร์ไม่จำเป็นต้อง
ลบล้าง getPageTitle()
:
Kotlin
// Integrating TabLayout with ViewPager class CollectionDemoFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tabLayout = view.findViewById(R.id.tab_layout) tabLayout.setupWithViewPager(viewPager) } ... } class DemoCollectionPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { override fun getCount(): Int = 4 override fun getPageTitle(position: Int): CharSequence { return "OBJECT ${(position + 1)}" } ... } // Integrating TabLayout with ViewPager2 class CollectionDemoFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tabLayout = view.findViewById(R.id.tab_layout) TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = "OBJECT ${(position + 1)}" }.attach() } ... }
Java
// Integrating TabLayout with ViewPager public class CollectionDemoFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TabLayout tabLayout = view.findViewById(R.id.tab_layout); tabLayout.setupWithViewPager(viewPager); } ... } public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter { ... @Override public int getCount() { return 4; } @Override public CharSequence getPageTitle(int position) { return "OBJECT " + (position + 1); } ... } // Integrating TabLayout with ViewPager2 public class CollectionDemoFragment : Fragment() { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TabLayout tabLayout = view.findViewById(R.id.tab_layout); new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText("OBJECT " + (position + 1)) ).attach(); } ... }
รองรับองค์ประกอบที่เลื่อนได้ที่ซ้อนกัน
ViewPager2
ไม่รองรับมุมมองการเลื่อนที่ฝังไว้ในกรณีที่
มุมมองการเลื่อนมีการวางแนวเดียวกันกับวัตถุ ViewPager2
ที่มี
ได้ ตัวอย่างเช่น การเลื่อนจะไม่ทำงานสำหรับมุมมองการเลื่อนแนวตั้งภายใน
ออบเจ็กต์ ViewPager2
แนวตั้ง
หากต้องการรองรับมุมมองการเลื่อนภายในวัตถุ ViewPager2
ที่มีการวางแนวเดียวกัน ให้ทำดังนี้
คุณต้องโทร
requestDisallowInterceptTouchEvent()
ในออบเจ็กต์ ViewPager2
เมื่อคุณ
คาดว่าจะเลื่อนองค์ประกอบที่ฝังแทน การเลื่อนที่ซ้อนกันใน ViewPager2
ตัวอย่างแสดงวิธีการแก้ปัญหานี้ที่ครอบคลุมรอบด้าน
เลย์เอาต์ Wrapper ที่กำหนดเอง
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับ ViewPager2
ได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้
ตัวอย่าง
- ViewPager2 ตัวอย่างใน GitHub
วิดีโอ
- การเปลี่ยนหน้า: การย้ายข้อมูลไปยัง ViewPager2 (Android Dev Summit ปี 2019)