ViewPager2和TabLayout协同使用,实现多Fragment页面切换类似于QQ音乐,bilibili效果

news2024/11/24 18:53:49

一、ViewPager2的基本用法

使用前先添加依赖:

   implementation 'androidx.appcompat:appcompat:1.4.0' // AndroidX AppCompat
    implementation 'com.google.android.material:material:1.4.0' // Material Design Components

1、制作Fragment

首先制作一个Fragment的xml布局页面

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="SSSSS"
        android:textSize="19sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

然后使用Fragment类绑定这个布局

public class HomeFragment extends Fragment {
    FragmentBinding binding;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = FragmentBinding.inflate(inflater,container,false);
        return binding.getRoot();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}

2、制作Adapter

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

自定义自己的Adapter继承FragmentStateAdapter

制作一个fragmentList管理所有的fragment

public class MyPagerAdapter extends FragmentStateAdapter {

    List<Fragment> fragmentList;    //管理所有的fragment

    public MyPagerAdapter(@NonNull FragmentActivity fragmentActivity, List<Fragment> fragmentList) {
        super(fragmentActivity);
        this.fragmentList = fragmentList;
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return fragmentList.get(position);
    }


    @Override
    public int getItemCount() {
        return fragmentList != null ? fragmentList.size() : 0;
    }
}

createFragment:用于返回指定的frgment界面

getItemCount:用于加载容器大小

除此之外,FragmentStateAdapter有三个构造方法剩下两个分别是:

public FragmentStateAdapter(@NonNull Fragment fragment)

public FragmentStateAdapter(@NonNull FragmentManager fragmentManager,@NonNull Lifecycle lifecycle)

FragmentStateAdapter(Fragment fragment)

这个构造方法通常用于在 Fragment 内部创建 FragmentStateAdapter,并将其附加到该 Fragment 的生命周期。

public class MyFragment extends Fragment {
    private ViewPager2 viewPager;
    private FragmentStateAdapter adapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_layout, container, false);

        // 初始化 ViewPager2
        viewPager = rootView.findViewById(R.id.viewPager);

        // 创建适配器并将其附加到当前 Fragment 的生命周期
        adapter = new MyFragmentStateAdapter(this);
        viewPager.setAdapter(adapter);

        return rootView;
    }
}

FragmentStateAdapter(FragmentManager fragmentManager, Lifecycle lifecycle)

这个构造方法通常用于在活动中创建 FragmentStateAdapter,并通过提供 FragmentManagerLifecycle 对象来管理 Fragment 的生命周期。

public class MainActivity extends AppCompatActivity {
    private ViewPager2 viewPager;
    private FragmentStateAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化 ViewPager2
        viewPager = findViewById(R.id.viewPager);

        // 创建适配器并将其附加到活动的生命周期
        adapter = new MyFragmentStateAdapter(getSupportFragmentManager(), getLifecycle());
        viewPager.setAdapter(adapter);
    }
}

3、使用Adapter加载fragment页面

        List<Fragment> fragmentList = new ArrayList<>();

        fragmentList.add(new HomeFragment());
        fragmentList.add(new HomeFragment());
        fragmentList.add(new HomeFragment());
        fragmentList.add(new HomeFragment());
        fragmentList.add(new HomeFragment());
        fragmentList.add(new HomeFragment());
        fragmentList.add(new HomeFragment());
        fragmentList.add(new HomeFragment());

        MyPagerAdapter adapter = new MyPagerAdapter(this,fragmentList);

        //禁用预加载
        binding.viewPager.setOffscreenPageLimit(ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT);


        binding.viewPager.setAdapter(adapter);

预加载是在页面还未滑动时,提前加载页面。一般默认加载1个页面。

FragmentStateAdapter内部封装有 FragmentManagerFragmentTransaction,用于管理Fragment;

使用FragmentManager可以根据ID或TAG来查找Fragment , 动态添加、删除、替换

让Fragment 成为ViewPager的一页时,FragmentManager会一直保存管理创建好了的Fragment,即使当前不是显示的这一页,Fragment对象也不会被销毁,在后台默默等待重新显示。但如果Fragment不再可见时,它的视图层次会被销毁掉,下次显示时视图会重新创建

二、ViewPager2和TabLayout协同使用

1、制作TabLayout与ViewPager2布局文件

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tabMode"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:tabIndicatorColor="#1E90FF"
            app:tabIndicatorAnimationMode="elastic"
            app:tabSelectedTextColor="#B22222"
            app:tabUnboundedRipple="true"
            app:tabGravity="center"
            app:tabMode="auto" >
        </com.google.android.material.tabs.TabLayout>

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal"/> 
        
    <!-- ViewPager2内部通过RecyclerView 所以需要通过orientation来设置页面切换方向-->
        
    </LinearLayout>

**tabIndicatorAnimationMode ** :设置加载动画样式,elastic表示粘粘性动画,linear表示线性动画

tabIndicatorColor :指示器颜色

tabIndicatorHeight :指示器高度

tabIndicatorFullWidth :设置为false 则指示器跟文本宽度一致

tabUnboundedRipple :设置为true点击时会有一个水波纹效果

tabGravity :可设置center或fill;center指的是居中显示,fill指的是沾满全屏。

tabMode :可设置fixed和 scrollable;fixed:指的是固定tab;scrollable指的是tab可滑动。

tabTextColor :tab文字颜色

tabSelectedTextColor :选中时的tab颜色

image-20231109193100489

关于更多的TabLayou的使用可以参考:Android控件-TabLayout使用介绍

2、绑定TabLayout到ViewPager2

2.1 动态自定义Tab

这里采取了自定义TabView的方式,同样的也可以直接操作tab修改样式。

        new TabLayoutMediator(binding.tabMode, binding.viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
            @Override
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {

                //自定义TabView
                TextView tabView = new TextView(MainActivity.this);

                tabView.setText("Fragment " + position);

                //将tabbView绑定到tab
                tab.setCustomView(tabView);
            }
        }).attach();

注意一定要使用.attach()进行启动。

2.2 静态自定义Tab——tabTextAppearance

设置文字的大小和样式,在values下新建文件如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="tabDome">
        <item name="android:textSize">20sp</item>
        <item name="android:textStyle">bold</item>
    </style>
</resources>

在TabLayout中导入文件即可

image-20231109202114266

3、Viewpager2的滑动监听事件

ViewPager2.OnPageChangeCallback有三个构造方法:

        binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {

            //该方法开始滑动到滑动结束前不断调用
            // 参数一:position表示当前页面的位置(当前页面在翻页适配器中的下标,索引),因为不断调用,position也可能表示目标页面的下标
            // 参数二:positionOffset表示页面偏移的百分比,翻页时不断增大(不断趋近1),最后翻页完成时突变成0
            // 这个参数在左滑时由1趋近0,右滑由0趋近1
            // 参数三:positionOffsetPixel表示页面完成滑动的像素数,变化趋势和positionOffset一样
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                super.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }

            //该方法在页面切换成功后调用(滑动前与滑动后不是同一页面)
            //position表示当前页面在适配器中的下标,索引
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
            }

            //该方法在页面滑动状态改变时调用
            // ViewPager2.SCROLL_STATE_IDLE表示空闲状态,当前页面处于静止状态,没有要翻页的趋势 == 0
            // ViewPager2.SCROLL_STATE_DRAGGING表示拖动状态,用户正在拖动页面,准备进行翻页滚动 == 1
            // ViewPager2.SCROLL_STATE_SETTLING表示滚动状态,页面正在自动滚动到目标页面 == 2
            @Override
            public void onPageScrollStateChanged(int state) {
                super.onPageScrollStateChanged(state);
            }
        });

3.1 使用动态方法实现字体大小颜色变化

监听ViewPager2的页面滑动实现修改tab

        //viewPager 页面切换监听
        binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            
            //用于回调ViewPager2的当前页面,当页面发送变化就会调用这个方法onPageSelected
            @Override
            public void onPageSelected(int position) {
                //获取总的TabLayout的个数
                int tabCount = binding.tabMode.getTabCount();

                //遍历选择所有的Tab,如果判断是当前的Tab则进行相关操作,不是则还原操作
                for (int i = 0; i < tabCount; i++) {
                    TabLayout.Tab tab = binding.tabMode.getTabAt(i);    //取得tab
                    
                    //通过tab获取tabView
                    TextView tabView = (TextView) tab.getCustomView();

                    if (tab.getPosition() == position) {
                        tabView.setTextSize(20);
                        tabView.setTypeface(Typeface.DEFAULT_BOLD);
                        tabView.setTextColor(Color.parseColor("#B22222"));
                    } else {
                        tabView.setTextSize(15);
                        tabView.setTypeface(Typeface.MONOSPACE);
                        tabView.setTextColor(Color.parseColor("#000000"));

                    }

                }

            }
        });

3.2 使用静态的方法实现字体大小和颜色变化

首先设置静态的style选项卡,在values下新建一个xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="TabLayoutTextSelected">
        <item name="android:textSize">20sp</item>
        <item name="android:textColor">#B22222</item>
    </style>

    <style name="TabLayoutTextUnSelected">
        <item name="android:textSize">15sp</item>
        <item name="android:textColor">#000080</item>
    </style>

</resources>

然后在TabLayout的布局文件中设置初始状态的tab颜色字体

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tabMode"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:tabIndicatorColor="#1E90FF"
            app:tabUnboundedRipple="true"
            app:tabGravity="center"
            app:tabMode="auto"
            app:tabTextAppearance="@style/TabLayoutTextUnSelected">	//注意在这个地方使用tabTextAppearance设置初始状态tab的文字效果
        </com.google.android.material.tabs.TabLayout>

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal"/>

    </LinearLayout>

监听TabLayout实现修改,TabLayout监听事件有三个Override方法,当然这里也可以继续使用ViewPager2页面的监听方法实现。

        binding.tabMode.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            //选中时的变化
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                // 创建新的 TextView 实例,并设置样式和文本
                TextView selectedTextView = new TextView(MainActivity.this);
                selectedTextView.setTextAppearance(R.style.TabLayoutTextSelected);	//在这里动态使用刚刚的style文件
                selectedTextView.setText("Fragment " + tab.getPosition());	//设置文字内容,tab因为是重新加载的textView内容,所以原来的数据被覆盖掉了
                tab.setCustomView(selectedTextView);
            }

            //未选中时的变化
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                // 清除未选中标签的自定义视图
                tab.setCustomView(null);
            }

            //重复选中的变化,当用户再次点击已经选中的Tab时,这个方法就会被调用。
            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                // 处理标签重新选择,如果需要
            }
        });

注意点:

1、在onTabSelected中重新设置加载的文本内容,否则原数据会被覆盖,出现这样的情况

815d22199678c9eea892ad0d5d700517

2、在onTabUnselected中一定要清除覆盖在tab的自定义视图否则视图会不停重复的加在tab上面,出现这样的情况:

f9a347c9e0b08ec6b09f4308b9b8fc44

4、TabLayout的监听事件

        binding.tabMode.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

            TextView textView = new TextView(MainActivity.this);
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                //选中时的变化

            }

            public void onTabUnselected(TabLayout.Tab tab) {
                //未选中的变化
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                //重复选中的变化,当用户再次点击已经选中的Tab时,这个方法就会被调用。
            }
        });

5、禁止Viewpager2左右滑动翻页

        //false表示禁止,true表示允许
        binding.viewPager.setUserInputEnabled(false);

此时就只能通过点击Tab才能加载Fragment.

6、TabLayout+Viewpager2效果展示

e5da21bb-7c36-4e16-999e-b1ab7c7c173c

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1208779.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

欧拉回路和欧拉路径

目录 欧拉回路基础 欧拉回路的定义 欧拉回路的性质 判断图中是否存在欧拉回路的java代码实现 寻找欧拉回路的三个算法 Hierholzer算法 详细思路 代码实现 欧拉路径 欧拉路径的定义 欧拉路径的性质 欧拉回路基础 欧拉回路的定义 欧拉回路遍历了所有的边&#xff0c;…

spring cloud 简介

springcloud 定义 1.定义&#xff1a;springcloud为开发人员提供了在分布式系统中快速构建一些通用模式的工具&#xff08;例如配置管理、服务发现、断路器、路由、控制总线等&#xff09;2.微服务:基于单体应用&#xff0c;基于业务进行拆分&#xff0c;每个服务都是独立应用…

栈的实现---超详细

栈的实现 文章目录 栈的实现一、栈的模型二、栈的代码实现以及测试用例①栈的初始化②入栈③出栈④弹出栈顶⑤判断栈空间是否为空⑥计算栈空间长度⑦销毁栈⑧测试用例 一、栈的模型 首先栈有两个概念 1.数据结构里的栈。2.语言/操作系统中的栈(内存空间)&#xff0c;可能会在递…

xshell连接云服务器(保姆级教程)

文章目录 1. 前言2. 查看云服务器的信息3. xshell7连接云服务器 1. 前言 云服务器&#xff0c;也被称为Elastic Compute Service (ECS)&#xff0c;是一种简单高效、安全可靠、处理能力可弹性伸缩的计算服务。它源于物理服务器集群资源池&#xff0c;可以像从大海中取水一样&am…

从流程优化到经营提效,法大大电子签全面助力智慧零售升级

在新零售模式下&#xff0c;“商业综合体、百货商场、连锁商超、连锁便利店、线上电商平台”等各类商业零售企业借助数字化的手段来改造和重塑传统零售流程和逻辑&#xff0c;实现全面数字化转型&#xff0c;包括线上线下一体化、全场景覆盖、全链条联通、全渠道经营、客户服务…

大数据安全 | 【实验】RSA加密解密

文章目录 &#x1f4da;关于RSA&#x1f4da;实验目的&#x1f4da;流程梳理&#x1f407;Step1&#xff1a;求解乘法逆元&#x1f407;Step2&#xff1a;生成密钥&#x1f407;Step3&#xff1a;加密解密&#x1f407;Step4&#xff1a;最后数据导入 &#x1f4da;实验结果 &a…

github使用手册

核心代码 配置用户名/邮箱 best practice git init #在本地初始化一个仓库 git add . #将当前目录所有的文件加入&#xff08;注意这里是加入&#xff09;到缓存区 git commit -m "xxx" #将当前缓存区里的内容提交到本地仓库 git remote add <remote_rep_name&g…

开启学习新时代,电大搜题助您实现梦想!

亲爱的读者朋友们&#xff0c;当您拥有追求知识的渴望&#xff0c;秉持着对成功的执着追求时&#xff0c;浙江开放大学&#xff08;广播电视大学&#xff09;诞生了——它向您开启了一扇通向知识殿堂的大门。而今&#xff0c;我们荣幸地向您推荐一款既简便又高效的学习利器——…

Android设计模式--原型模式

一&#xff0c;定义 原型模式就是用原型实例指定创建对象的种类&#xff0c;并通过拷贝这些原型创建新的对象 也就是说用户从一个实例中复制出一个内部属性一致的对象&#xff0c;这个被复制的对象就是原型。 原型模式多用于创建复杂的或者构造耗时的实例&#xff0c;因为这…

YOLO目标检测——苹果数据集下载分享【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;监测果园中苹果的生长情况、水果品质监控、自动化分拣数据集说明&#xff1a;苹果检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富标签说明&#xff1a;使用lableimg标注软件标注&#xff0c;标注框质量高&#xff0c;含voc(…

淘宝京东优惠券信息API接口系列

获取淘宝优惠券信息接口需要使用淘宝开放平台提供的API接口。以下是获取优惠券信息的步骤&#xff1a; 进入淘宝开放平台&#xff0c;注册并登录账号。在开放平台页面中&#xff0c;找到“优惠券”或“营销工具”等相关的API接口&#xff0c;根据需要进行选择。根据接口文档&a…

计算机组成原理:大而快——层次化存储

原文链接www.xiaocr.fun/index.php/2023/11/14/计算机组成原理大而快-层次化存储/ 引言 关于两种局部性 时间局部性&#xff1a;如果某个数据被访问&#xff0c;那么在不久的将来它可能再次被访问空间局部性&#xff1a;如果某个数据项被访问&#xff0c;与它相邻的数据项可…

接口自动化测试(Python+Requests+Unittest)合集详解教程

&#xff08;1&#xff09;接口自动化测试的优缺点 优点&#xff1a; 测试复用性。维护成本相对UI自动化低一些。回归方便。可以运行更多更繁琐的测试。 自动化的一个明显的好处是可以在较少的时间内运行更多的测试。为什么UI自动化维护成本更高&#xff1f; 因为前端页面变…

工作记录-------MySql主从同步

MySql主从同步简述&#xff1a; MySQL主从同步&#xff0c;可以实现将数据从一台数据库服务器同步到多台数据库服务器。MySQL数据库自带主从同步功能&#xff0c;经过配置&#xff0c;可以实现基于库、表结构的多种方案的主从同步。 Redis是一种高性能的内存数据库&#xff1…

【Hello Go】初识Go语言

初识Go语言 Go语言介绍Go语言是什么Go语言优势Go语言能用来做什么 Go语言环境安装第一个GO语言程序运行Go语言程序 Go语言介绍 Go语言是什么 go语言是是Google开发的一种静态强类型、编译型、并发型&#xff0c;并具有垃圾回收功能的编程语言. 静态类型&#xff1a;在静态类型…

【左程云算法全讲10】打表技巧和矩阵处理技巧

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于左程云算法课程进行的&#xff0c;每个知识点的修正和深入主要参考…

算法笔记-其他高效的技巧与算法(未处理完)

算法笔记-其他高效的技巧与算法 前缀和 前缀和 #include <cstdio> #include <vector> using namespace std; const int MAXN 10000; int n, a[MAXN]; int sum[MAXN] { 0 };int main() {scanf("%d", &n);for (int i 0; i < n; i) {scanf("…

数据银行:安全保障的重要一环

随着信息技术的快速发展&#xff0c;数据银行已经成为了我们日常生活中不可或缺的一部分。它存储了我们的个人信息、财务数据、医疗记录等重要信息&#xff0c;这些信息对于我们的生活和工作至关重要。然而&#xff0c;由于数据的安全性备受关注&#xff0c;因此&#xff0c;对…

JavaWeb——HTML常用标签

目录 1. 标题标签 2. 段落标签 3. 换行/分割线标签 4. 列表标签 4.1. 有序列表 4.2. 无序列表 5. 超链接标签 6. 多媒体标签 6.1. img 图片标签 6.2. audio 音频标签 6.3. video 视频标签 7. 表格标签(重点) 8. 表单标签&#xff08;重点&#xff09; 1. 标题标签 …