草庐IT

ViewPager2+TabLayout

贺兰猪 2023-07-04 原文

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页。如果当前在第一页,会预加载第二页,滑倒第二页,会预加载第三页,当滑倒第三页,第一页会销毁,第四页会加载。

有关ViewPager2+TabLayout的更多相关文章

  1. android - 如何解决viewpager android中的空对象引用 - 2

    我正在使用查看寻呼机来滑动图像。我可以在日志中获取url,但是当我尝试在ImageView中设置时,出现错误。E/AndroidRuntime(1895):FATALEXCEPTION:mainE/AndroidRuntime(1895):Process:com.project.center,PID:1895E/AndroidRuntime(1895):java.lang.NullPointerException:Attempttoreadfromfieldcom.project.center.views.TouchImageViewcom.project.center.FullScr

  2. android - 在 android.support.design.widget.TabLayout 中设置选项卡的宽度? - 2

    我正在为我的Viewpager使用选项卡,这是现在的XML:它们看起来很棒,但我希望能够有更多选项卡,而不是让所有内容都挤在屏幕上。但是我不喜欢切换到可滚动的tabMode,因为那样的话一切都会变平并且看起来很乱。如何设置各个选项卡的宽度? 最佳答案 TabLayout不提供特定选项卡固定宽度的属性。但是您可以设置最小和最大宽度。tabMinWidthandtabMaxWidthhttps://developer.android.com/reference/android/support/design/widget/TabLayou

  3. java - 使用 ViewPager 在 Fragment 中创建 Listview - 2

    我正在尝试开发一个时间线,就像下面的facebook一样。你看,我有一个ViewPager可以在“fragment”(如提要、个人资料、关于等)之间导航用户。我有“main.xml”,它上面只有viewpager;我还有fragmenta.xml、fragmentb.xml、fragmentc.xml。让我们检查一下fragmenta.xml,我把它放在里面;并制作了singlerow.xml来将这些框创建成这样的时间线;我让它只使用一个静态框。但是当我尝试运行这个结构时,我在Debug模式下遇到错误“找不到来源编辑源查找路径”在我尝试像这样将我的适配器和其他关于listview的东西

  4. android - 海拔不适用于 TabLayout - 2

    我正在ViewPager内的TabLayout上设置高度,但它根本没有显示。我在stackoverflow上尝试了很多答案,但无法解决问题。在CoordinatorLayout中设置android:clipToPadding="false"也不能解决问题。任何帮助,将不胜感激。这是我正在使用但现在提升的布局的xml: 最佳答案 要使阴影可见,您必须在TabLayout上设置背景。它可以与您的窗口背景颜色相同(只要它是没有alpha的纯色)。此外,您还必须为其提供Tablayout边距以查看高度。最小margin应该是您提供的elev

  5. java - 自定义 ViewPager 的 PageTitles - 2

    以下是我的XML,我的PagerTitleStrip嵌入到ViewPager中:这是我自定义的PagerAdapter类。publicclassCustomPagerAdapterextendsPagerAdapter{privateint[]image_resources={R.drawable.1,R.drawable.2,R.drawable.3};privateContextctx;privateLayoutInflaterlayoutInflater;publicCustomPagerAdapter(Contextctx){this.ctx=ctx;}@Overridepub

  6. android - ViewPager 项目布局中的 OnclickAction - 2

    我想将setOnClickListener设置到我的ImageView,它位于ViewPagerItemXML中。在我的activityXML中,我有ViewPager和其他几个按钮。在我的ViewPagerItemXML中,我有可点击的ImageView。我想在Activity中单击ImageView后执行一些操作。不幸的是,OnClickListener根本不会触发。LayoutInflaterinflater=(LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);itemView=inflat

  7. java - 如何使 photoview 库与 viewpager 一起工作 - 2

    我是安卓开发的新手。我正在使用photoview库在我的imageviewer应用程序中启用图像缩放。但是viewpager和缩放功能不能同时工作。当我在FullImageActivity.java中包含photoView.setVisibility(View.GONE);时,viewpager开始工作,当我删除它,缩放功能开始工作。但是zooming和viewpager不能同时工作。我该如何解决?谢谢完整代码可在https://github.com/redviper00/game获得FullImageActivity.java:publicclassFullImageActivity

  8. java - 带有 Fragment 和 ViewPager 的 NullPointerException - 2

    我的代码有一些问题。我在下面的代码中有一个NullPointerException。我正在尝试在3个不同的fragment之间创建滑动。我不明白我的错误在哪里所以请帮助我:p虚拟fragment.java:packagecom.example.testslide;importandroid.os.Bundle;importandroid.support.v4.app.Fragment;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importandroid.w

  9. ios - 为什么 Ios viewPager 与 UISearchController 一起崩溃? - 2

    现在我在iOS应用程序开发过程中遇到了一个问题。我使一个viewpagercontrollerview包含几个viewcontroller。每个Viewcontroller都包含tableview。我在这个TableView中使用了UISearchController。但是,每当我单击searchcontroller并滚动标签时,就会发生错误。2016-08-0822:07:11.211ToolManager[3913:121312]***Assertionfailurein-[_UIQueuingScrollView_setWrappedViewAtIndex:withView:],

  10. android - Ionic 3 - 如何实现 viewpager? - 2

    我目前正在使用Ionic3开发一个应用程序,主屏幕包含3个选项卡(ion-tabs)我创建了一个根据用户滑动更改选项卡的功能,但是我的客户要求一个等于WhatsApp的过渡,我不知道要实现这个。我考虑过使用ion-slides但我必须将代码从3个选项卡迁移到单个View,有没有一种方法可以在不更改组件的情况下附加动画? 最佳答案 您可以使用ionic2-super-tabs.这个库可以轻松制作可滑动的选项卡。您必须检查github页面的兼容性以及您应该使用哪个版本。有了这个库,一个基本的例子如下。它与Ionic本身的选项卡几乎相同。

随机推荐