ViewPager2
یک نسخه بهبود یافته از کتابخانه ViewPager
است که عملکردهای پیشرفتهتری را ارائه میدهد و مشکلات رایج در استفاده ViewPager
را برطرف میکند. اگر برنامه شما قبلاً از ViewPager
استفاده میکند، این صفحه را بخوانید تا درباره مهاجرت به ViewPager2
اطلاعات بیشتری کسب کنید.
اگر میخواهید از ViewPager2
در برنامه خود استفاده کنید و در حال حاضر از ViewPager
استفاده نمیکنید، برای اطلاعات بیشتر ، Slide بین قطعات با استفاده از ViewPager2 و Create views Swipe with Tabs با استفاده از 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 بهطور خودکار در صورت لزوم بر اساس محلی فعال میشود، اما میتوانید با تنظیم ویژگی android:layoutDirection
صفحهبندی RTL را برای عنصر ViewPager2
به صورت دستی فعال کنید:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layoutDirection="rtl" />
همچنین می توانید با استفاده از متد setLayoutDirection() این ویژگی را به صورت برنامه نویسی تنظیم کنید.
مجموعه های قطعه قابل تغییر
ViewPager2
از صفحهبندی از طریق مجموعهای از قطعات قابل تغییر پشتیبانی میکند و با فراخوانی notifyDatasetChanged()
برای بهروزرسانی رابط کاربری زمانی که مجموعه اصلی تغییر میکند.
این بدان معنی است که برنامه شما می تواند به صورت پویا مجموعه قطعه را در زمان اجرا تغییر دهد و ViewPager2
مجموعه اصلاح شده را به درستی نمایش می دهد.
DiffUtil
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
از سه کلاس انتزاعی مختلف استفاده کرد. ViewPager2
فقط از دو کلاس انتزاعی استفاده می کند.
برای هر شی ViewPager
که به یک شی ViewPager2
تبدیل می کنید، کلاس آداپتور را به روز کنید تا کلاس انتزاعی مناسب را به صورت زیر گسترش دهید:
- وقتی
ViewPager
ازPagerAdapter
برای صفحه از طریق نماها استفاده کرد، ازRecyclerView.Adapter
باViewPager2
استفاده کنید. - وقتی
ViewPager
ازFragmentPagerAdapter
برای صفحهبندی تعداد کمی از قطعات ثابت استفاده میکرد، ازFragmentStateAdapter
باViewPager2
استفاده کنید. - هنگامی که
ViewPager
ازFragmentStatePagerAdapter
برای صفحه در تعداد زیادی یا ناشناخته قطعه استفاده کرد، ازFragmentStateAdapter
باViewPager2
استفاده کنید.
پارامترهای سازنده
کلاسهای آداپتور مبتنی بر Fragment که از FragmentPagerAdapter
یا FragmentStatePagerAdapter
به ارث میبرند، همیشه یک شی FragmentManager
را به عنوان پارامتر سازنده میپذیرند. وقتی FragmentStateAdapter
برای یک کلاس آداپتور ViewPager2
گسترش می دهید، به جای آن گزینه های زیر را برای پارامترهای سازنده دارید:
- شیء
FragmentActivity
یا شیءFragment
که شیViewPager2
در آن قرار دارد. در بیشتر موارد، این گزینه بهتر است. - یک شیء
FragmentManager
و یک شیءLifecycle
.
کلاسهای آداپتور مبتنی بر View که مستقیماً از RecyclerView.Adapter
به ارث میبرند، به پارامتر سازنده نیاز ندارند.
نادیده گرفتن روش ها
کلاسهای آداپتور شما همچنین باید روشهای مختلفی را برای ViewPager2
نسبت به ViewPager
نادیده بگیرند:
- به جای
getCount()
،getItemCount()
را لغو کنید. به غیر از نام، این روش بدون تغییر است. - بهجای
getItem()
، در کلاسهای آداپتور مبتنی بر قطعه،createFragment()
را لغو کنید. مطمئن شوید که متدcreateFragment()
جدید شما همیشه هر بار که تابع فراخوانی می شود به جای استفاده مجدد از نمونه ها، یک نمونه قطعه جدید ارائه می کند.
خلاصه
به طور خلاصه، برای تبدیل یک کلاس آداپتور ViewPager
برای استفاده با ViewPager2
، باید تغییرات زیر را اعمال کنید:
- سوپرکلاس را به
RecyclerView.Adapter
برای صفحهبندی از طریق نماها یاFragmentStateAdapter
برای صفحهبندی از طریق قطعات تغییر دهید. - پارامترهای سازنده را در کلاس های آداپتور مبتنی بر قطعه تغییر دهید.
- به جای
getCount()
getItemCount()
را لغو کنید. - در کلاسهای آداپتور مبتنی بر فرگمنت، به جای
getItem()
createFragment()
لغو کنید.
کاتلین
// 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() }
جاوا
// 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; } }
رابط های Refactor TabLayout
ViewPager2
تغییراتی را در ادغام TabLayout
معرفی می کند. اگر در حال حاضر از یک ViewPager
با یک شی TabLayout
برای نمایش برگه های افقی برای پیمایش استفاده می کنید، باید شی TabLayout
را برای ادغام با ViewPager2
تغییر دهید.
TabLayout
از ViewPager2
جدا شده است و اکنون به عنوان بخشی از اجزای Material در دسترس است. این بدان معناست که برای استفاده از آن، باید وابستگی مناسب را به فایل build.gradle
خود اضافه کنید:
شیار
implementation "com.google.android.material:material:1.1.0-beta01"
کاتلین
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
استفاده می کند، برای ادغام با ViewPager2
به یک نمونه TabLayoutMediator
نیاز دارد.
شی TabLayoutMediator
همچنین وظیفه تولید عناوین صفحه برای شی TabLayout
را بر عهده دارد، به این معنی که کلاس آداپتور نیازی به لغو getPageTitle()
ندارد:
کاتلین
// 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() } ... }
جاوا
// 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 یکی از راههای حل این مشکل را با طرحبندی بستهبندی سفارشی همه کاره نشان میدهد.
منابع اضافی
برای کسب اطلاعات بیشتر در مورد ViewPager2
، به منابع اضافی زیر مراجعه کنید.
نمونه ها
- نمونه های ViewPager2 در GitHub
ویدیوها
- چرخاندن صفحه: مهاجرت به ViewPager2 (Android Dev Summit '19)