ViewPager2简介
距离ViewPager2正式版的发布已经一年多了,目前ViewPager早已停止更新,官方鼓励使用ViewPager2替代。ViewPager2底层基于RecyclerView实现,因此可以获得RecyclerView带来的诸多收益:
-
抛弃传统的PagerAdapter,统一了Adapter的API。 -
通过LinearLayoutManager可以实现类似抖音的纵向滑动。 -
支持DiffUtil,可以实现局部刷新。 -
支持RTL(right-to-left),对于一些有出海需求的APP非常有用。 -
支持ItemDecorator。 -
与ViewPager对比:
ViewPager | ViewPager2 |
---|
PagerAdapter | RecyclerView.Adapter | FragmentStatePagerAdapter | FragmentStateAdapter | addPageChangeListener | registerOnPageChangeCallback | 不支持 | 支持RTL | 不支持 | 支持垂直滑动 | 不支持 | 支持停止用户操作 |
1、基本使用
1.1 添加依赖
dependencies {
implementation "androidx.viewpager2:viewpager2:1.0.0"
}
2.2 布局文件中使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_page2"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
2.3 设置Adapter
因为内部RecycleRiew实现的,所以ViewPager2的Adapter就需要设置为RecyclerView的Adapter
public class VpAdapter extends RecyclerView.Adapter<VpAdapter.PagerViewHolder> {
private List<Integer> mList = new ArrayList<>();
private int resourceId;
private Context mContext;
public VpAdapter(Context context, int resourceId, List<Integer> data) {
this.mContext = context;
this.resourceId = resourceId;
this.mList = data;
}
@NonNull
@Override
public PagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(resourceId, parent, false);
PagerViewHolder viewHolder= new PagerViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull PagerViewHolder holder, int position) {
holder.textView.setText(String.valueOf(mList.get(position)));
}
@Override
public int getItemCount() {
return mList.size();
}
class PagerViewHolder extends RecyclerView.ViewHolder{
TextView textView;
public PagerViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv_text);
}
}
}
item_page.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:id="@+id/tv_text"
android:background="#24adf3"
android:layout_width="match_parent"
android:layout_height="280dp"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="22sp" />
</LinearLayout>
2.4 在MainActivity中使用
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
viewPager2 = findViewById(R.id.view_page2);
VpAdapter adapter = new VpAdapter(this, R.layout.item_page, list);
viewPager2.setAdapter(adapter);
viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
}
}
2、进阶
2.1 页面切换监听
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
Log.d("OnPageScrolled", "position: " + position + " positionOffset: " + positionOffset + " positionOffsetPixels: " + positionOffsetPixels);
}
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
Log.d("OnPageSelected", "position: " + position);
}
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
Log.d("OnPageScrollStateChanged", "state: "+ state);
}
});
2.2 一屏多页
ViewPager2如果要实现一屏多页的效果,需要借助于 offscreenPageLimit 以及 setPadding
viewPager.setOffscreenPageLimit(1);
RecyclerView rv = (RecyclerView) viewPager.getChildAt(0);
rv.setPadding(60, 0, 60, 0);
rv.setClipToPadding(false);
这里获取第0个child:
RecyclerView rv = (RecyclerView) viewPager.getChildAt(0);
是因为源码中:ViewPager2内部是默认将 mRecyclerView添加到ViewGroup中的,索引值固定是0!
attachViewToParent(mRecyclerView, 0, mRecyclerView.getLayoutParams());
2.3、 offscreenPageLimit 预加载
在ViewPager中,会默认加载前后各一个页面,所以处理懒加载就比较麻烦,那么在ViewPager2中,默认去掉了这限制,也就是默认只会加载一个页面
源码中的setOffscreenPageLimit 设置需要处理一个参数,可以看到有个注解OffscreenPageLimit 表明默认值是需要从1开始的。
源码:
public void setOffscreenPageLimit(@OffscreenPageLimit int limit) {
if (limit < 1 && limit != OFFSCREEN_PAGE_LIMIT_DEFAULT) {
throw new IllegalArgumentException(
"Offscreen page limit must be OFFSCREEN_PAGE_LIMIT_DEFAULT or a number > 0");
}
mOffscreenPageLimit = limit;
mRecyclerView.requestLayout();
}
3、与Fragment、TabLayout一起使用
3.1 导入依赖
implementation 'com.google.android.material:material:1.3.0'
3.2 直接上代码
activity_main.xml
<?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/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>
MainActivity.java
public class MainActivity extends AppCompatActivity {
ViewPager2 viewPager;
TabLayout tabLayout;
List<String> titles = new ArrayList<>();
List<Fragment> fragments = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.pager);
tabLayout = findViewById(R.id.tab_layout);
titles.add("1");
titles.add("2");
fragments.add(new MyFragment());
fragments.add(new YouFragment());
PageAdapter adapter = new PageAdapter(getSupportFragmentManager(), getLifecycle(), fragments);
viewPager.setAdapter(adapter);
new TabLayoutMediator(tabLayout, viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
tab.setText(titles.get(position));
}
}).attach();
}
}
适配器代码:
public class PageAdapter extends FragmentStateAdapter {
List<Fragment> fragments;
public PageAdapter(@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();
}
}
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, false);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#FF9800"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
效果图:
参考:
|