Android ViewPager、ViewPager2的基本使用详解及区别

1,917 阅读3分钟

本篇 Blog 记录 ViewPager 和 ViewPager2

嵌套 Fragment 的效果图

ViewPager 的使用

关于 ViewPager 的使用已经很常见了,这里在复习一下吧。配合 TabLayout

  1. 布局文件

    在 ViewPager 的布局中允许存在子 view,我们可以把 TabLayout 作为 ViewPager 的子 View 写在 ViewPager 内部,也可以并列。

		<androidx.viewpager.widget.ViewPager
            android:id="@+id/vp_merchant_main"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintVertical_weight="1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/banner_merchant_main"
            app:layout_constraintBottom_toBottomOf="parent">

            <com.google.android.material.tabs.TabLayout
                android:id="@+id/tab_layout_merchant_main"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                app:tabGravity="center"
                app:tabIndicatorColor="@color/tabLayoutIndicatorStartColor"
                app:tabSelectedTextColor="@color/textColor"
                app:tabTextAppearance="@android:style/TextAppearance.Holo"
                app:tabTextColor="@color/defaultTextColor" />
        </androidx.viewpager.widget.ViewPager>

  1. Java 代码

    代码中我们只需要把 Fragment 和 Titles 传入 Adapter,然后再设置到 ViewPager 上就可以了。

    我们也可以调用 Tablayout 的 setupWithViewPager() 方法使 TabLayout 和 ViewPager 进行绑定

		// ViewPager处理
        ArrayList<Fragment> fragmentList = new ArrayList<>();
        fragmentList.add(new AllProductFragment(this));
        fragmentList.add(new EvaluationFragment(this));
        String[] fragmentTitles = {"商品", "评价"};
        ViewPagerScrollAdapter scrollAdapter = new ViewPagerScrollAdapter(getSupportFragmentManager());
        scrollAdapter.setFragmentTitles(fragmentTitles);
        scrollAdapter.setMenuFragmentList(fragmentList);
        merchantMainBinding.vpMerchantMain.setAdapter(scrollAdapter);

  1. Adapter

    注意:ViewPager 的 Adapter 需要继承 FragmentStatePagerAdapter

public class ViewPagerScrollAdapter extends FragmentStatePagerAdapter {
    private ArrayList<Fragment> menuFragmentList;
    private String [] fragmentTitles;

    public ViewPagerScrollAdapter(@NonNull FragmentManager fm) {
        super(fm);
    }

    public ViewPagerScrollAdapter(@NonNull FragmentManager fm, int behavior) {
        super(fm, behavior);
    }

    public void setFragmentTitles(String[] fragmentTitles) {
        this.fragmentTitles = fragmentTitles;
    }

    public void setMenuFragmentList(ArrayList<Fragment> menuFragmentList) {
        this.menuFragmentList = menuFragmentList;
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return menuFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return menuFragmentList.size();
    }

    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        return fragmentTitles[position];
    }
}

到这儿关于 ViewPager 的基本使用就完成了。下面是 ViewPager2 的使用

ViewPager2 的使用

关于 ViewPager2 嵌套 Fragment 的使用很简单。

  1. 布局文件

    在布局中 ViewPager2 的使用是不允许有自 View 的,我们这里仍然配合 TabLayout 使用。

		<com.google.android.material.tabs.TabLayout
            android:id="@+id/tab_layout_group"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:orientation="horizontal"
            app:layout_constraintBottom_toTopOf="@id/vp_group_page"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tv_home_group_list_title"
            app:tabIndicatorColor="@color/white"
            app:tabIndicatorFullWidth="false"
            app:tabSelectedTextColor="@color/bottomTextColor"
            app:tabTextAppearance="@android:style/TextAppearance.Holo"
            app:tabTextColor="@color/defaultTextViewColor" />

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/vp_group_page"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:orientation="horizontal"
            android:paddingTop="6dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tab_layout_group"
            app:layout_constraintVertical_weight="1" />

  1. 创建 Adapter

    Adapter 需要继承 FragmentStateAdapter

public class LiveViewPagerAdapter extends FragmentStateAdapter {
    private ArrayList<Fragment> fragmentList;

    public LiveViewPagerAdapter(@NonNull Fragment fragment) {
        super(fragment);
    }

    public LiveViewPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }

    public LiveViewPagerAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }

    public void setFragmentList(ArrayList<Fragment> fragmentList) {
        this.fragmentList = fragmentList;
    }

    ......
}

  1. 重写 createFragment 和 getItemCount 方法

    需要在 Adapter 中重写这两个方法

	@NonNull
    @Override
    public Fragment createFragment(int position) {
    	// 返回Fragment
        return fragmentList.get(position);
    }

    @Override
    public int getItemCount() {
    	// 获取Fragment数量
        return fragmentList.size();
    }

  1. Activity / Fragment 中的使用

    这里以 Fragment 为例,在父 Fragment 中使用,在 initData 方法中设置 Fragment List,在 initView 中 setAdapter。

    和我们在 RecyclerView 中设置 Adapter 和数据没有区别,只是这里的数据是 Fragment。

    值得注意的是:设置页面切换时 TabLayout 样式有两种方式。请注意看代码注释

    第一种主要是使用 ViewPager2 的 registerOnPageChangeCallback 方法来控制
    第二种则是通过 new TabLayoutMediator 来关联 TabLayout 和 ViewPager2 进行控制,该方式和 ViewPager 的 setupWithViewPager 基本一致,可以算得上是升级到 ViewPager2 后的替代方法。

public class LiveFragment extends Fragment {
    private FragmentLiveBinding binding;
    private ArrayList<Fragment> fragmentArrayList;
    private final int LIVE_RECOMMEND = 0;
    private final int LIVE_FOLLOW = 1;

    ......

    @Override
    public void onStart() {
        super.onStart();
        initData();
        initView();
    }

    private void initData(){
        fragmentArrayList = new ArrayList<>();
        fragmentArrayList.add(LIVE_RECOMMEND, new LiveRecommendFragment());
        fragmentArrayList.add(LIVE_FOLLOW, new LiveFollowFragment());
    }
	
	// 以下是第一种方式
    private void initView(){
        LiveViewPagerAdapter liveViewPagerAdapter = new LiveViewPagerAdapter(this);
        liveViewPagerAdapter.setFragmentList(fragmentArrayList);
        binding.vpLiveContainer.setAdapter(liveViewPagerAdapter);
        binding.vpLiveContainer.setCurrentItem(lastPage, false);
    }
    
	private void initEvent() {
		binding.vpLiveContainer.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
                if (position == LIVE_FOLLOW) {
                    binding.tvLiveFollow.setTextColor(mContext.getColor(R.color.white));
                    binding.tvLiveRecommend.setTextColor(mContext.getColor(R.color.defaultTextColor));
                } else {
                    binding.tvLiveFollow.setTextColor(mContext.getColor(R.color.defaultTextColor));
                    binding.tvLiveRecommend.setTextColor(mContext.getColor(R.color.white));
                }
                lastPage = position;
            }
        });
	}

	// 这里是第二种方式
	private void initView() {
        GroupTypeViewPagerAdapter groupTypeAdapter = new GroupTypeViewPagerAdapter(this);
        groupTypeAdapter.setFragments(fragments);
        groupListBinding.vpGroupPage.setAdapter(groupTypeAdapter);
        new TabLayoutMediator(groupListBinding.tabLayoutGroup, groupListBinding.vpGroupPage, (tab, position) -> {
            // 可以根据positions设置Tab样式
            if (position == 0) {
                tab.setText(R.string.homeGroupMine);
            } else if (position == 1) {
                tab.setText(R.string.homeGroupInvited);
            }
        }).attach();
    }

}

这样关于 ViewPager2 的使用就 OK 了。两者都清楚了,下面说明以下两者区别

ViewPager 和 ViewPager2 的区别

  1. 在布局方面:

    ViewPager 允许有子 View

    而 ViewPager2 不允许有子 View 存在

  2. 在继承方面:

    ViewPager 的 Adapter 继承 FragmentStatePagerAdapter

    而 ViewPager2 的 Adapter 继承 FragmentStateAdapter

  3. 在设置 Fragment 方面:

    ViewPager 可以直接分别设置 FragmentList 和 FragmentTitleList

    而 ViewPager2 则是只能设置 FragmentList(也可能是我没发现,如果有类似 FragmentStatePagerAdapter 和 getPageTitle() 方法的烦请告知,谢谢)

  4. 在关联及监听方面:

    ViewPager 只需要简单的设置 Adapter 或者通过 TabLayout 的 setupWithViewPager(ViewPager) 方法进行关联。

    而 ViewPager2 则是需要 new TabLayoutMediator() 方法或者通过 ViewPager2 的监听回调 registerOnPageChangeCallback() 来实现

本篇关于 ViewPager 和 ViewPager2 的 Blog 到此结束,如果有错误,请斧正。