ViewPager2和TabLayout协同使用

news2024/11/15 17:23:40

一、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);
            }

            //该方法在页面滑动状态改变时调用
            // ViewPager.SCROLL_STATE_IDLE表示空闲状态,当前页面处于静止状态,没有要翻页的趋势
            // ViewPager.SCROLL_STATE_DRAGGING表示拖动状态,用户正在拖动页面,准备进行翻页滚动
            // ViewPager.SCROLL_STATE_SETTLING表示滚动状态,页面正在自动滚动到目标页面
            @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/1201404.html

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

相关文章

Mysql数据库管理---MySQL数据库连接、权限认证

1 mysql系统连接权限认证。 1 mysql数据库权限表在数据库启动时就载入内存&#xff0c;当用户通过身份验证后&#xff0c;就在内存中进行相应权限的存取。系统会用到mysql数据库中3个核心表&#xff1a;user&#xff0c;host&#xff0c;db。 主要包括&#xff1a; 用户列&a…

【Opencv】图像融合addWeighted()函数示例和详解

本文通过原理和示例对addWeighted&#xff08;&#xff09;函数进行详解&#xff0c;&#xff0c;并通过改变融合系数展示多个结果&#xff0c;帮助大家理解和使用。 目录 函数原理示例权重&#xff08;0.5,0.5&#xff09;权重&#xff08;0.8,0.2&#xff09;权重&#xff08…

如何解决Windows电脑 Create folder error,Access is denied.

如何解决 Create folder error, Error: mkdir C:\Program Files\nodejs\21.1.0/: Access is denied. Waring: Name : http://npm.taobao.org/mirrors/node/v21.1.0/win-x64/node.exe Code : -2 Error : Create folder error, Error: mkdir C:\Program Files\nodejs\\21.1.0/…

【Linux】虚拟机连不上外网 (ping www.baidu.com不通)

进入linux系统&#xff0c;打开终端&#xff0c;ping www.baidu.com 发现ping不通 首先我连接的是nat模式 查看是否连接上自己本机的网 切换root用户 使用 ifconfig 命令查看是eth0 还是 ens33 vi /etc/sysconfig/network-scripts/ifcfg-ens33 BOOTPROTOstatic ONBOOTyes …

cocosCreator 之 Bundle使用

版本&#xff1a; v3.4.0 语言&#xff1a; TypeScript 环境&#xff1a; Mac Bundle简介 全名 Asset Bundle(简称AB包)&#xff0c;自cocosCreator v2.4开始支持&#xff0c;用于作为资源模块化工具。 允许开发者根据项目需求将贴图、脚本、场景等资源划分在 Bundle 中&am…

LeetCode 189.轮转数组(三种方法解决)

文章目录 题目暴力求解空间换时间三段逆置总结 题目 LeetCode 189.轮转数组 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5…

Redis的特性以及使用场景

分布式发展历程参考 陈佬 http://t.csdnimg.cn/yYtWK 介绍redis Redis&#xff08;Remote Dictionary Server&#xff09;是一个基于客户端-服务器架构的在内存中存储数据的中间件&#xff0c;属于NoSQL的一种。它可以用作数据库、缓存/会话存储以及消息队列。 作为一种内存数…

基于Amazon EC2和Amazon Systems Manager Session Manager的堡垒机设计和自动化实现

01 背景 在很多企业的实际应用场景中&#xff0c;特别是金融类的客户&#xff0c;大部分的应用都是部署在私有子网中。为了能够让客户的开发人员和运维人员从本地的数据中心中安全的访问云上资源&#xff0c;堡垒机是一个很好的选择。传统堡垒机的核心实现原理是基于 SSH 协议的…

模板——“C++”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是C中的模板初阶的内容&#xff0c;下面&#xff0c;让我们进入C模板的世界吧&#xff01;&#xff01;&#xff01; 1. 泛型编程 2. 函数模板 3. 类模板 泛型编程 如何实现一个通用的交换函数呢&#xff1f;…

汽车ECU的虚拟化技术初探(二)

目录 1.概述 2.U2A虚拟化方案概述 3.U2A的虚拟化功能概述 4.虚拟化辅助功能的使能 5.留坑 1.概述 在汽车ECU的虚拟化技术初探(一)-CSDN博客里&#xff0c;我们聊到虚拟化技术比较关键的就是vECU的虚拟地址翻译问题&#xff0c;例如Cortex-A77就使用MMU来进行虚实地址的转换…

阿里云ACK(Serverless)安装APISIX网关及APISIX Ingress Controller

在k8s上安装apisix全家&#xff0c;通过helm安装很简单&#xff0c;但是会遇到一些问题。 安装 首先登录阿里云控制台&#xff0c;在ACK集群详情页&#xff0c;进入CloudShell&#xff0c;执行下面helm命令安装apisix、apisix-ectd、apisix-dashboard和apisix-ingress-contro…

【Linux】Kali(WSL)基本操作与网络安全入门

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍WSL安装Kali及基本操作。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷路…

从0到0.01入门React | 004.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

upload-labs关卡7(基于黑名单的空格绕过)通关思路

文章目录 前言一、回顾上一关知识点二、靶场第七关通关思路1、看源代码2、空格绕过3、检查文件是否成功上传 总结 前言 此文章只用于学习和反思巩固文件上传漏洞知识&#xff0c;禁止用于做非法攻击。注意靶场是可以练习的平台&#xff0c;不能随意去尚未授权的网站做渗透测试…

【GEE】10、使用 Google 地球引擎创建图形用户界面【GUI开发】

1简介 在本模块中&#xff0c;我们将讨论以下概念&#xff1a; 用于生成图形用户界面的 GEE 对象。如何开发具有交互元素的面板。如何将地理处理元素连接到交互式元素。 2背景 在过去的十个单元中&#xff0c;我们展示了 Google Earth Engine 可以成为一种重要且高效的资源&a…

数字双向码、密勒码、传号反转(CMI)码、AMI、HDB3的编码规则和功率谱解析+眼图

数字双向码、密勒码、传号反转&#xff08;CMI&#xff09;码、AMI、HDB3的编码规则和功率谱解析眼图 本文主要涉及数字双向码、密勒码、传号反转&#xff08;CMI&#xff09;码、AMI、HDB3的编码规则,优缺点和功率谱解析以及眼图的分析。关于简单二元码大家可以参考简单二元码…

Python---元组的相关操作方法

由于元组中的数据不允许直接修改&#xff0c;所以其操作方法大部分为查询方法。 编号函数作用1元组[索引]根据索引下标查找元素2index()查找某个数据&#xff0c;如果数据存在返回对应的下标&#xff0c;否则报错&#xff0c;语法和列表、字符串的index方法相同3count()统计某…

第十七章jQuery中的事件与动画

一。常用事件&#xff1a; 1.鼠标事件&#xff1a; mouseover()&#xff1a;在鼠标进入内容后一直显示事件 mouseout()&#xff1a;在鼠标离开内容后一直显示事件 mouseenter()&#xff1a;在进入刹那间显示事件 mouseleave()&#xff1a;在退出刹那间显示事件 案例&#xf…

v-bind和v-model

目录 前言 v-bind 作用 语法格式 编译原理 简写 v-model 作用 使用方法 v-bind和v-model的区别和联系 前言 本文我们来了解一下模板语法之指令语法中的v-bind和v-model v-bind 作用 v-bind可以让html标签的某个属性的值产生动态的效果 语法格式 <html标签 v-bin…

终端安全/SOC安全/汽车信息安全大课来袭-共计204节课

在近两年的时间里&#xff0c;我投入了大量的心血和精力&#xff0c;不仅创作了数千篇精美的图片&#xff0c;还编写了超过1000篇文章&#xff0c;以及数百篇内容丰富的PPT。经过这番努力我终于成功地构建出两套系统化的学习课程&#xff0c;它们分别是“Trustzone/TEE/安全从入…