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)