ViewPager2最显著的特点是基于RecyclerView实现,RecyclerView是目前Android端最成熟的AdapterView解决方案,这带来诸多好处:
1、抛弃传统的PagerAdapter,统一了Adapter的API/
2、通过LinearLayoutManager可以实现类似抖音的纵向滑动
3、支持DiffUitl,可以通过diff实现局部刷新
4、支持RTL(right-to-left)布局,对于一些有出海需求的APP非常有用
5、支持ItemDecorator
一、ViewPager2和ViewPager的对比:
1、ViewPager2内部实现是RecyclerView,所以ViewPager2的性能更高。
2、ViewPager2可以实现竖向滑动,ViewPager只能横向滑动。
3、ViewPager2只有一个adapter,FragmentStateAdapter继承自RecyclerView.Adapter。
而ViewPager有两个adapter,FragmentStatePagerAdapter和FragmentPagerAdapter,均是继承PagerAdapter。FragmentStatePagerAdapter和FragmentPagerAdapter两者的区别是FragmentStatePagerAdapter不可以缓存,FragmentPagerAdapter可以缓存。
4、ViewPager2模式实现了懒加载,默认不进行预加载。内部是通过Lifecycle 对 Fragment 的生命周期进行管理。ViewPager会进行预加载,懒加载需要我们自己去实现。
效果图:
MainActivity
public class MainActivity extends AppCompatActivity {
private TabLayout tabLayout;
private ViewPager2 viewPager2;
private int activeColor = Color.parseColor("#ff678f");
private int normalColor = Color.parseColor("#666666");
private int activeSize = 20;
private int normalSize = 14;
private ArrayList<Fragment> fragments;
private TabLayoutMediator mediator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabLayout = findViewById(R.id.tab_layout);
viewPager2 = findViewById(R.id.view_pager);
final String[] tabs = new String[]{"关注", "推荐", "最新0", "最新1", "最新2", "最新3", "最新4", "最新5", "最新6"};
//禁用预加载
viewPager2.setOffscreenPageLimit(ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT);
//Adapter
viewPager2.setAdapter(new FragmentStateAdapter(getSupportFragmentManager(), getLifecycle()) {
@NonNull
@Override
public Fragment createFragment(int position) {
//FragmentStateAdapter内部自己会管理已实例化的fragment对象。
// 所以不需要考虑复用的问题
return TestFragment.newInstance(tabs[position]);
}
@Override
public int getItemCount() {
return tabs.length;
}
});
//viewPager 页面切换监听监听
viewPager2.registerOnPageChangeCallback(changeCallback);
mediator = new TabLayoutMediator(tabLayout, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
//这里可以自定义TabView
TextView tabView = new TextView(MainActivity.this);
int[][] states = new int[2][];
states[0] = new int[]{android.R.attr.state_selected};
states[1] = new int[]{};
int[] colors = new int[]{activeColor, normalColor};
ColorStateList colorStateList = new ColorStateList(states, colors);
tabView.setText(tabs[position]);
tabView.setTextSize(normalSize);
tabView.setTextColor(colorStateList);
tab.setCustomView(tabView);
}
});
//要执行这一句才是真正将两者绑定起来
mediator.attach();
}
private ViewPager2.OnPageChangeCallback changeCallback = new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
//可以来设置选中时tab的大小
int tabCount = tabLayout.getTabCount();
for (int i = 0; i < tabCount; i++) {
TabLayout.Tab tab = tabLayout.getTabAt(i);
TextView tabView = (TextView) tab.getCustomView();
if (tab.getPosition() == position) {
tabView.setTextSize(activeSize);
tabView.setTypeface(Typeface.DEFAULT_BOLD);
} else {
tabView.setTextSize(normalSize);
tabView.setTypeface(Typeface.DEFAULT);
}
}
}
};
@Override
protected void onDestroy() {
mediator.detach();
viewPager2.unregisterOnPageChangeCallback(changeCallback);
super.onDestroy();
}
}
activity_main关键代码
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="40dp"
app:tabGravity="center"
app:tabIndicatorColor="#ff678f"
app:tabIndicatorFullWidth="false"
app:tabIndicatorHeight="2dp"
app:tabMode="scrollable"
app:tabSelectedTextColor="#ff678f"
app:tabTextColor="#333333"
app:tabUnboundedRipple="true" />
<!-- ViewPager2内置了RecyclerView
所以需要通过orientation来设置页面切换方向-->
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" />
- tabIndicatorColor 指示器颜色
- tabIndicatorHeight 指示器高度
- tabIndicatorFullWidth 设置为false 则指示器跟文本宽度一致
- tabUnboundedRipple 设置为true点击时会有一个水波纹效果
- tabGravity 可设置center或fill;center指的是居中显示,fill指的是沾满全屏。
- tabMode 可设置fixed和 scrollable;fixed:指的是固定tab;scrollable指的是tab可滑动。
- tabTextColor tab文字颜色
- tabSelectedTextColor 选中时的tab颜色
viewPager2可以通过设置android:orientation属性来设置切换方向,支持上下、左右切换。
TestFragment
对应tab页面的实现效果在Fragment中进行实现。
public class TestFragment extends Fragment {
private View rootView;
public static TestFragment newInstance(String text) {
Bundle args = new Bundle();
args.putString("text", text);
TestFragment fragment = new TestFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_test, container, false);
return rootView;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TextView textView = rootView.findViewById(R.id.text_view);
String text = getArguments() != null ? getArguments().getString("text") : null;
textView.setText(text);
}
}
几个注意的点!!
- ViewPager2获取当前fragment,通过mFragmentManager.findFragmentByTag(XXX); tag前面需要拼接“f”
看下源码tag怎么设置的,调用链如下:
FragmentStateAdapter-》onBindViewHolder-》placeFragmentInViewHolder方法
mFragmentManager.beginTransaction()
.add(fragment, "f" + holder.getItemId())
.setMaxLifecycle(fragment, STARTED)
.commitNow();
- ViewPager.
setOffscreenPageLimit
()设置预加载与缓存
(1)ViewPager 会预加载几页
(2)ViewPager 会缓存 2*n+1 页(n为设置的值)
如设置为n=1,预加载页数1页,缓存页数3页。如果当前在第一页,会预加载第二页,滑倒第二页,会预加载第三页,当滑倒第三页,第一页会销毁,第四页会加载。