一、什么是ViewPager?
布局管理器允许左右翻转带数据的页面,你想要显示的视图可以通过实现PagerAdapter来显示。这个类其实是在早期设计和开发的,它的API在后面的更新之中可能会被改变,当它们在新版本之中编译的时候可能还会改变源码。
 ViewPager经常用来连接Fragment,它很方便管理每个页面的生命周期,使用ViewPager管理Fragment是标准的适配器实现。最常用的实现一般有FragmentPagerAdapter和FragmentStatePagerAdapter。
ViewPager是android扩展包v4包中的类,这个类可以让我们左右切换当前的view。我们先来聊聊ViewPager的几个相关知识点:
- 1、ViewPager类直接继承了ViewGroup类,因此它一个容器类,可以添加其他的view类
 - 2、ViewPager类需要一个PagerAdapter适配器类给它提供数据(这点跟ListView一样需要数据适配器Adater)
 - 3、ViewPager经常和Fragment一起使用,并且官方还提供了专门的FragmentPagerAdapterFragmentStatePagerAdapter类供Fragment中的ViewPager使用
 
二、什么是ViewPager2
原理: viewpager2 内部实现原理是使用recycleview加LinearLayoutManager实现竖直滚动,其实可以理解为对recyclerview的二次封装
private void initialize(Context context, AttributeSet attrs) {
    mAccessibilityProvider = sFeatureEnhancedA11yEnabled
    ? new PageAwareAccessibilityProvider()
    : new BasicAccessibilityProvider();
    // 实例化recycleview对象
    mRecyclerView = new RecyclerViewImpl(context);
    mRecyclerView.setId(ViewCompat.generateViewId());
    mRecyclerView.setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
    // 实例化LinearLayoutManager对象
    mLayoutManager = new LinearLayoutManagerImpl(context);
    mRecyclerView.setLayoutManager(mLayoutManager);
    mRecyclerView.setScrollingTouchSlop(RecyclerView.TOUCH_SLOP_PAGING);
    setOrientation(context, attrs);
    mRecyclerView.setLayoutParams(
        new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    mRecyclerView.addOnChildAttachStateChangeListener(enforceChildFillListener());
    // Create ScrollEventAdapter before attaching PagerSnapHelper to RecyclerView, because the
    // attach process calls PagerSnapHelperImpl.findSnapView, which uses the mScrollEventAdapter
    mScrollEventAdapter = new ScrollEventAdapter(this);
    // Create FakeDrag before attaching PagerSnapHelper, same reason as above
    mFakeDragger = new FakeDrag(this, mScrollEventAdapter, mRecyclerView);
    mPagerSnapHelper = new PagerSnapHelperImpl();
    mPagerSnapHelper.attachToRecyclerView(mRecyclerView);
    // Add mScrollEventAdapter after attaching mPagerSnapHelper to mRecyclerView, because we
    // don't want to respond on the events sent out during the attach process
    mRecyclerView.addOnScrollListener(mScrollEventAdapter);
    mPageChangeEventDispatcher = new CompositeOnPageChangeCallback(3);
    mScrollEventAdapter.setOnPageChangeCallback(mPageChangeEventDispatcher);
    // Callback that updates mCurrentItem after swipes. Also triggered in other cases, but in
    // all those cases mCurrentItem will only be overwritten with the same value.
    final OnPageChangeCallback currentItemUpdater = new OnPageChangeCallback() {
        @Override
        public void onPageSelected(int position) {
            if (mCurrentItem != position) {
                mCurrentItem = position;
                mAccessibilityProvider.onSetNewCurrentItem();
            }
        }
        @Override
        public void onPageScrollStateChanged(int newState) {
            if (newState == SCROLL_STATE_IDLE) {
                updateCurrentItem();
            }
        }
    };
    // Prevents focus from remaining on a no-longer visible page
    final OnPageChangeCallback focusClearer = new OnPageChangeCallback() {
        @Override
        public void onPageSelected(int position) {
            clearFocus();
            if (hasFocus()) { // if clear focus did not succeed
                mRecyclerView.requestFocus(View.FOCUS_FORWARD);
            }
        }
    };
    // Add currentItemUpdater before mExternalPageChangeCallbacks, because we need to update
    // internal state first
    mPageChangeEventDispatcher.addOnPageChangeCallback(currentItemUpdater);
    mPageChangeEventDispatcher.addOnPageChangeCallback(focusClearer);
    // Allow a11y to register its listeners after currentItemUpdater (so it has the
    // right data). TODO: replace ordering comments with a test.
    mAccessibilityProvider.onInitialize(mPageChangeEventDispatcher, mRecyclerView);
    mPageChangeEventDispatcher.addOnPageChangeCallback(mExternalPageChangeCallbacks);
    // Add mPageTransformerAdapter after mExternalPageChangeCallbacks, because page transform
    // events must be fired after scroll events
    mPageTransformerAdapter = new PageTransformerAdapter(mLayoutManager);
    mPageChangeEventDispatcher.addOnPageChangeCallback(mPageTransformerAdapter);
    attachViewToParent(mRecyclerView, 0, mRecyclerView.getLayoutParams());
} 
 
ViewPager2的出现是为了替代ViewPager,它有以下几个优势:
- 支持RTL布局,
 - 支持竖向滚动
 - 支持notifyDataSetChanged
 
RTL布局是Right To Left布局也就是从右往左的布局,大家知道我们平常写的布局都是从左往右,但是如果你适配阿拉伯语等环境的UI布局,他们的写法是从右往左的,具体这里不做研究。
API的变动:
FragmentStateAdapter替换了原来的 FragmentStatePagerAdapter
RecyclerView.Adapter替换了原来的 PagerAdapter
registerOnPageChangeCallback替换了原来的 addPageChangeListener
FragmentStateAdapter和FragmentStatePagerAdapter作用相同, 可以用viewpager来管理fragment, 区别在于viewpager2的FragmentStateAdapter与recycleview的生命周期绑定
另外viewpager2的Adapter是继承自recyclerview的adapter, 支持除了notifyDataSetChanged()以外的notifyItemChanged(int position)等方式, 使用上更加的便捷
三、ViewPager2 结合 Fragment实际demo
在app模块的build.gradle里要加上这两个依赖
implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' 
 
myfragment.xml
一个显示在屏幕正中央的文字mode1
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF9800"
    android:orientation="vertical"
    android:gravity="center">
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="mode1"
        android:textSize="30sp"/>
</LinearLayout> 
myfragment2.xml
一个显示在屏幕正中央的文字mode2
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF0000"
    android:orientation="vertical"
    android:gravity="center">
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="mode2"
        android:textSize="30sp"/>
</LinearLayout> 
activity_main.xml
一个TabLayout和一个ViewPager2组件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/my_tab"
        android:layout_width="match_parent"
        android:layout_height="60dp"/>
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/my_pager2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout> 
 
MyAdapter.java
重写MyAdapter、createFragment、getItemCount三个方法
package com.example.viewpager2;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.lifecycle.Lifecycle;
import java.util.List;
public class MyAdapter extends FragmentStateAdapter {
    List<Fragment> fragments;
    public MyAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragments) {
        super(fragmentManager, lifecycle);
        this.fragments = fragments;
    }
    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return fragments.get(position);
    }
    @Override
    public int getItemCount() {
        return fragments.size();
    }
} 
 
MyFragment.java
实现第一个fragment页面
package com.example.viewpager2;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class MyFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.myfragment, null);
    }
} 
MySecondFragment.java
实现第二个fragment页面
package com.example.viewpager2;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class MySecondFragment extends Fragment {
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.myfragment2, null);
    }
} 
MainActivity.java
进来的activity
package com.example.viewpager2;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
    private TabLayout myTab;
    private ViewPager2 myPager2;
    List<String> titles=new ArrayList<>();
    List<Fragment> fragments=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myTab = findViewById(R.id.my_tab);
        myPager2 = findViewById(R.id.my_pager2);
        //添加标题
        titles.add("1");
        titles.add("2");
        //添加Fragment进去
        fragments.add(new MyFragment());
        fragments.add(new MySecondFragment());
        //实例化适配器
        MyAdapter myAdapter=new MyAdapter(getSupportFragmentManager(),getLifecycle(),fragments);
        //设置适配器
        myPager2.setAdapter(myAdapter);
        //TabLayout和Viewpager2进行关联
        new TabLayoutMediator(myTab, myPager2, new TabLayoutMediator.TabConfigurationStrategy() {
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                tab.setText(titles.get(position));
            }
        }).attach();
    }
} 
 
ViewPager + Fragment 实现tab页切换不同页面内容的效果

参考:【精选】Android:ViewPager \ViewPager2 简单介绍 & 使用方法解析_viewpager2与viewpager-CSDN博客


















