إنشاء طرق عرض التمرير السريع باستخدام علامات التبويب باستخدام ViewPager2

تتيح لك طرق عرض التمرير السريع التنقل بين الشاشات التابعة، مثل علامات التبويب، باستخدام إيماءة إصبع أفقية أو التمرير السريع. ويُشار إلى نمط التنقّل هذا أيضًا باسم التقسيم الأفقي إلى صفحات.

يعلمك هذا الموضوع كيفية إنشاء تنسيق علامات التبويب باستخدام طرق عرض التمرير للتبديل بين علامات التبويب وكيفية إظهار شريط عناوين بدلاً من علامات التبويب.

تطبيق عروض التمرير السريع

يمكنك إنشاء طرق عرض التمرير السريع باستخدام التطبيق المصغّر ViewPager2 في AndroidX. لاستخدام ViewPager2 وعلامات التبويب، عليك إضافة تبعية إلى ViewPager2 ومكوّنات المواد إلى مشروعك.

لإعداد التنسيق باستخدام ViewPager2، أضِف العنصر <ViewPager2> إلى تنسيق XML. على سبيل المثال، إذا كانت كل صفحة في عرض التمرير تستهلك التنسيق بالكامل، فإن التخطيط الخاص بك سيبدو كما يلي:

<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" />

لإدراج طرق عرض فرعية تمثّل كل صفحة، أدرِج هذا التنسيق في شكل FragmentStateAdapter. وإليك كيفية استخدامها للتمرير سريعًا عبر مجموعة من عناصر Fragment:

Kotlin

class CollectionDemoFragment : Fragment() {
    // When requested, this adapter returns a DemoObjectFragment,
    // representing an object in the collection.
    private lateinit var demoCollectionAdapter: DemoCollectionAdapter
    private lateinit var viewPager: ViewPager2

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.collection_demo, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        demoCollectionAdapter = DemoCollectionAdapter(this)
        viewPager = view.findViewById(R.id.pager)
        viewPager.adapter = demoCollectionAdapter
    }
}

class DemoCollectionAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {

    override fun getItemCount(): Int = 100

    override fun createFragment(position: Int): Fragment {
        // Return a NEW fragment instance in createFragment(int).
        val fragment = DemoObjectFragment()
        fragment.arguments = Bundle().apply {
            // The object is just an integer.
            putInt(ARG_OBJECT, position + 1)
        }
        return fragment
    }
}

private const val ARG_OBJECT = "object"

// Instances of this class are fragments representing a single
// object in the collection.
class DemoObjectFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.fragment_collection_object, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        arguments?.takeIf { it.containsKey(ARG_OBJECT) }?.apply {
            val textView: TextView = view.findViewById(android.R.id.text1)
            textView.text = getInt(ARG_OBJECT).toString()
        }
    }
}

Java

public class CollectionDemoFragment extends Fragment {
    // When requested, this adapter returns a DemoObjectFragment,
    // representing an object in the collection.
    DemoCollectionAdapter demoCollectionAdapter;
    ViewPager2 viewPager;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.collection_demo, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        demoCollectionAdapter = new DemoCollectionAdapter(this);
        viewPager = view.findViewById(R.id.pager);
        viewPager.setAdapter(demoCollectionAdapter);
    }
}

public class DemoCollectionAdapter extends FragmentStateAdapter {
    public DemoCollectionAdapter(Fragment fragment) {
        super(fragment);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        // Return a NEW fragment instance in createFragment(int).
        Fragment fragment = new DemoObjectFragment();
        Bundle args = new Bundle();
        // The object is just an integer.
        args.putInt(DemoObjectFragment.ARG_OBJECT, position + 1);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public int getItemCount() {
        return 100;
    }
}

// Instances of this class are fragments representing a single
// object in the collection.
public class DemoObjectFragment extends Fragment {
    public static final String ARG_OBJECT = "object";

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_collection_object, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        Bundle args = getArguments();
        ((TextView) view.findViewById(android.R.id.text1))
                .setText(Integer.toString(args.getInt(ARG_OBJECT)));
    }
}

توضّح الأقسام التالية كيفية إضافة علامات تبويب للمساعدة في تسهيل التنقل بين الصفحات.

إضافة علامات التبويب باستخدام TabLayout

توفّر علامة TabLayout طريقة لعرض علامات التبويب أفقيًا. وعند استخدام TabLayout مع ViewPager2، يمكن أن يوفّر واجهة مألوفة للتنقل بين الصفحات من خلال التمرير السريع.

صورة تعرض TabLayout يحتوي على أربع علامات تبويب، والثالثة تم اختيارها.
الشكل 1. TabLayout مع أربع علامات تبويب

لتضمين TabLayout في ViewPager2، يمكنك إضافة عنصر <TabLayout> أعلى العنصر <ViewPager2>:

<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>

بعد ذلك، أنشئ TabLayoutMediator لربط TabLayout بالViewPager2 وأرفقها، كما يلي:

Kotlin

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

public class CollectionDemoFragment extends 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، اطّلِع على المراجع الإضافية التالية.

عيّنات

الفيديوهات الطويلة