• ViewPager2+TabLayout


    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

    1. public class MainActivity extends AppCompatActivity {
    2. private TabLayout tabLayout;
    3. private ViewPager2 viewPager2;
    4. private int activeColor = Color.parseColor("#ff678f");
    5. private int normalColor = Color.parseColor("#666666");
    6. private int activeSize = 20;
    7. private int normalSize = 14;
    8. private ArrayList fragments;
    9. private TabLayoutMediator mediator;
    10. @Override
    11. protected void onCreate(Bundle savedInstanceState) {
    12. super.onCreate(savedInstanceState);
    13. setContentView(R.layout.activity_main);
    14. tabLayout = findViewById(R.id.tab_layout);
    15. viewPager2 = findViewById(R.id.view_pager);
    16. final String[] tabs = new String[]{"关注", "推荐", "最新0", "最新1", "最新2", "最新3", "最新4", "最新5", "最新6"};
    17. //禁用预加载
    18. viewPager2.setOffscreenPageLimit(ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT);
    19. //Adapter
    20. viewPager2.setAdapter(new FragmentStateAdapter(getSupportFragmentManager(), getLifecycle()) {
    21. @NonNull
    22. @Override
    23. public Fragment createFragment(int position) {
    24. //FragmentStateAdapter内部自己会管理已实例化的fragment对象。
    25. // 所以不需要考虑复用的问题
    26. return TestFragment.newInstance(tabs[position]);
    27. }
    28. @Override
    29. public int getItemCount() {
    30. return tabs.length;
    31. }
    32. });
    33. //viewPager 页面切换监听监听
    34. viewPager2.registerOnPageChangeCallback(changeCallback);
    35. mediator = new TabLayoutMediator(tabLayout, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
    36. @Override
    37. public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
    38. //这里可以自定义TabView
    39. TextView tabView = new TextView(MainActivity.this);
    40. int[][] states = new int[2][];
    41. states[0] = new int[]{android.R.attr.state_selected};
    42. states[1] = new int[]{};
    43. int[] colors = new int[]{activeColor, normalColor};
    44. ColorStateList colorStateList = new ColorStateList(states, colors);
    45. tabView.setText(tabs[position]);
    46. tabView.setTextSize(normalSize);
    47. tabView.setTextColor(colorStateList);
    48. tab.setCustomView(tabView);
    49. }
    50. });
    51. //要执行这一句才是真正将两者绑定起来
    52. mediator.attach();
    53. }
    54. private ViewPager2.OnPageChangeCallback changeCallback = new ViewPager2.OnPageChangeCallback() {
    55. @Override
    56. public void onPageSelected(int position) {
    57. //可以来设置选中时tab的大小
    58. int tabCount = tabLayout.getTabCount();
    59. for (int i = 0; i < tabCount; i++) {
    60. TabLayout.Tab tab = tabLayout.getTabAt(i);
    61. TextView tabView = (TextView) tab.getCustomView();
    62. if (tab.getPosition() == position) {
    63. tabView.setTextSize(activeSize);
    64. tabView.setTypeface(Typeface.DEFAULT_BOLD);
    65. } else {
    66. tabView.setTextSize(normalSize);
    67. tabView.setTypeface(Typeface.DEFAULT);
    68. }
    69. }
    70. }
    71. };
    72. @Override
    73. protected void onDestroy() {
    74. mediator.detach();
    75. viewPager2.unregisterOnPageChangeCallback(changeCallback);
    76. super.onDestroy();
    77. }
    78. }

    activity_main关键代码

    1. <com.google.android.material.tabs.TabLayout
    2. android:id="@+id/tab_layout"
    3. android:layout_width="match_parent"
    4. android:layout_height="40dp"
    5. app:tabGravity="center"
    6. app:tabIndicatorColor="#ff678f"
    7. app:tabIndicatorFullWidth="false"
    8. app:tabIndicatorHeight="2dp"
    9. app:tabMode="scrollable"
    10. app:tabSelectedTextColor="#ff678f"
    11. app:tabTextColor="#333333"
    12. app:tabUnboundedRipple="true" />
    13. <androidx.viewpager2.widget.ViewPager2
    14. android:id="@+id/view_pager"
    15. android:layout_width="match_parent"
    16. android:layout_height="0dp"
    17. android:layout_weight="1"
    18. 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中进行实现。

    1. public class TestFragment extends Fragment {
    2. private View rootView;
    3. public static TestFragment newInstance(String text) {
    4. Bundle args = new Bundle();
    5. args.putString("text", text);
    6. TestFragment fragment = new TestFragment();
    7. fragment.setArguments(args);
    8. return fragment;
    9. }
    10. @Nullable
    11. @Override
    12. public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    13. rootView = inflater.inflate(R.layout.fragment_test, container, false);
    14. return rootView;
    15. }
    16. @Override
    17. public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    18. super.onActivityCreated(savedInstanceState);
    19. TextView textView = rootView.findViewById(R.id.text_view);
    20. String text = getArguments() != null ? getArguments().getString("text") : null;
    21. textView.setText(text);
    22. }
    23. }

    几个注意的点!!

    • ViewPager2获取当前fragment,通过mFragmentManager.findFragmentByTag(XXX); tag前面需要拼接“f”

    看下源码tag怎么设置的,调用链如下:

    FragmentStateAdapter-》onBindViewHolder-》placeFragmentInViewHolder方法
    1. mFragmentManager.beginTransaction()
    2. .add(fragment, "f" + holder.getItemId())
    3. .setMaxLifecycle(fragment, STARTED)
    4. .commitNow();
    • ViewPager.setOffscreenPageLimit()设置预加载与缓存

    (1)ViewPager 会预加载几页
    (2)ViewPager 会缓存 2*n+1 页(n为设置的值)

    如设置为n=1,预加载页数1页,缓存页数3页。如果当前在第一页,会预加载第二页,滑倒第二页,会预加载第三页,当滑倒第三页,第一页会销毁,第四页会加载。

  • 相关阅读:
    [学习记录] 设计模式 1. 单例模式实现
    使用腾讯云服务器安装宝塔Linux面板教程_图文全流程
    LLM 新缺陷曝光,自我纠正成功率仅 1%;苹果超 95% 产品仍在中国制造丨 RTE 开发者日报 Vol.72
    你是如何使用React高阶组件的?
    程序员副业接单做私活避坑指南
    nodejs+Vue+python电子商务电商后台管理系统java
    蓝牙资讯|Q2中国蓝牙耳机市场发布,搭载苹果Find My的蓝牙耳机正逐步推出
    计算机组成原理——总线の选择题整理
    第十五章 汇编语言与逆向编程
    AndroidStudio Loading Devices不可点击
  • 原文地址:https://blog.csdn.net/u013773608/article/details/127997374