ย้ายข้อมูลจาก ViewPager ไปยัง ViewPager2

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 คุณต้องทำการเปลี่ยนแปลงต่อไปนี้

  1. ���ปลี่ยน Superclass เป็น RecyclerView.Adapter สำหรับการแบ่งหน้ายอดดู หรือ FragmentStateAdapter สำหรับการแบ่งหน้าส่วนย่อย
  2. เปลี่ยนพารามิเตอร์ตัวสร้างในคลาสอะแดปเตอร์ที่อิงตาม Fragment
  3. ลบล้าง getItemCount() แทน getCount()
  4. ลบล้าง 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 ได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้

ตัวอย่าง

วิดีโอ