当前位置: 首页 > news >正文

在新闻资讯 APP 中添加不同新闻分类页面,通过 ViewPager2 实现滑动切换

在新闻资讯 APP 中添加不同新闻分类页面,通过 ViewPager2 实现滑动切换

核心组件的作用

  • ViewPager2:是 ViewPager 的升级版,基于RecyclerView实现,支持水平 / 垂直滑动、RTL(从右到左)布局,且修复了 ViewPager 的诸多缺陷(如 notifyDataSetChanged 不生效、滑动冲突等)。
  • Fragment:可复用的 UI 组件,作为 ViewPager2 的 “页面” 内容,每个滑动页面对应一个 Fragment 实例。
  • FragmentStateAdapter:ViewPager2 的适配器,专门用于管理 Fragment 与 ViewPager2 的绑定,负责创建、销毁 Fragment,类似 RecyclerView 的 Adapter。
  • TabLayout(可选):通常与 ViewPager2 配合使用,显示标签标题,实现 “标签点击切换 + 滑动切换” 的联动效果。

开发步骤

1.引入依赖

ViewPager2 属于 AndroidX 库,需在build.gradle(Module 级别)中添加依赖(确保版本兼容):

dependencies {// ViewPager2核心依赖implementation "androidx.viewpager2:viewpager2:1.0.0"// Fragment依赖(若已引入AndroidX Fragment可忽略)implementation "androidx.fragment:fragment-ktx:1.5.6"// (可选)TabLayout联动依赖(与ViewPager2配合)implementation "com.google.android.material:material:1.9.0"
}
2.创建Fragment页面

每个滑动页面对应一个 Fragment,需创建多个 Fragment(如首页、推荐、我的等)。
以 "首页"页面为例:

 @NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = LayoutInflater.from(context).inflate(R.layout.item_recommend_user, parent, false);return new ViewHolder(view);}

每个 Fragment 对应一个布局文件(如fragment_home.xml),仅需简单的 UI 内容即可。

3.自定义一个ViewPage2布局

在 Activity 的布局文件中添加 ViewPager2,若需要标签页,可搭配 TabLayout:

我这里把之前写的recyclerView给改成了ViewPage2,用来实现页面的切换

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayoutxmlns: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"><!-- 顶部区域:搜索框 + 分类栏 --><LinearLayoutandroid:id="@+id/top_container"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:elevation="4dp"app:layout_behavior=".util.ScrollAwareFABBehavior"><!-- 搜索栏 --><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:background="#D3D3D3"android:padding="8dp"android:elevation="2dp"><EditTextandroid:id="@+id/search_edit_frame"android:layout_width="0dp"android:layout_height="40dp"android:layout_weight="3"android:background="@drawable/search_bg"android:paddingHorizontal="12dp"android:singleLine="true" /><Buttonandroid:id="@+id/button"android:layout_width="0dp"android:layout_height="40dp"android:layout_weight="1"android:text="搜索"android:backgroundTint="#4CAF50"android:textColor="@android:color/white" /></LinearLayout><!-- 分类栏 --><LinearLayoutandroid:id="@+id/category_bar"android:layout_width="match_parent"android:layout_height="50dp"android:orientation="horizontal"android:background="@android:color/white"android:elevation="1dp"><TextViewandroid:id="@+id/tab_hot"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="热榜"android:textSize="16sp"android:textColor="#333333"android:gravity="center"android:clickable="true"android:background="?attr/selectableItemBackground" /><TextViewandroid:id="@+id/tab_follow"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="关注"android:textSize="16sp"android:textColor="#333333"android:gravity="center"android:clickable="true"android:background="?attr/selectableItemBackground" /><TextViewandroid:id="@+id/tab_recommend"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="推荐"android:textSize="16sp"android:textColor="#333333"android:gravity="center"android:clickable="true"android:background="?attr/selectableItemBackground" /><TextViewandroid:id="@+id/tab_city"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="同城"android:textSize="16sp"android:textColor="#333333"android:gravity="center"android:clickable="true"android:background="?attr/selectableItemBackground" /></LinearLayout></LinearLayout><!-- ViewPager2容器 --><androidx.viewpager2.widget.ViewPager2android:id="@+id/view_pager"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginTop="?attr/actionBarSize" /><!-- 底部导航栏(保持原设计) --><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:padding="8dp"android:background="#FFFFFF"android:layout_gravity="bottom" ><!-- 首页 --><LinearLayoutandroid:id="@+id/home_tab"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:orientation="vertical"android:gravity="center"><ImageViewandroid:layout_width="25dp"android:layout_height="25dp"android:layout_gravity="center_horizontal"android:src="@drawable/main"android:contentDescription="首页图标"/><TextViewandroid:id="@+id/home_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="16dp"android:text="首页"android:gravity="center_horizontal"/></LinearLayout><!-- 菜单 --><LinearLayoutandroid:id="@+id/menu_tab"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:orientation="vertical"android:gravity="center"><ImageViewandroid:layout_width="25dp"android:layout_height="25dp"android:layout_gravity="center_horizontal"android:src="@drawable/menu"android:contentDescription="菜单图标"/><TextViewandroid:id="@+id/menu_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="16dp"android:text="菜单"android:gravity="center_horizontal"/></LinearLayout><!-- 我的 --><LinearLayoutandroid:id="@+id/mine_tab"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:orientation="vertical"android:gravity="center"><ImageViewandroid:layout_width="25dp"android:layout_height="25dp"android:layout_gravity="center_horizontal"android:src="@drawable/mine"android:contentDescription="我的图标"/><TextViewandroid:id="@+id/mine_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="16dp"android:text="我的"android:gravity="center_horizontal"/></LinearLayout></LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
4.实现FragmentStateAdapter

ViewPager2 需要实现FragmentStateAdapter管理 Fragment(类似 RecyclerView 的 Adapter)。FragmentStateAdapter会根据页面切换动态创建 / 销毁 Fragment,优化内存占用。

package com.example.news.adapter;import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.example.news.fragment.*;public class CategoryPagerAdapter extends FragmentStateAdapter {public CategoryPagerAdapter(@NonNull FragmentActivity fragmentActivity) {super(fragmentActivity);}@NonNull@Overridepublic Fragment createFragment(int position) {switch (position) {case 0:return new HotFragment();case 1:return new FollowFragment();case 2:return new RecommendFragment();case 3:return new CityFragment();default:throw new IllegalArgumentException("Invalid position: " + position);}}@Overridepublic int getItemCount() {return 4; // 四个分类页面}
}
5.初始化 ViewPager2 并绑定适配器
public class MainActivity extends AppCompatActivity {private ViewPager2 viewPager2;private TabLayout tabLayout;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);viewPager2 = findViewById(R.id.view_pager2);tabLayout = findViewById(R.id.tab_layout);// 1. 创建Fragment集合List<Fragment> fragments = new ArrayList<>();fragments.add(new HomeFragment());fragments.add(new RecommendFragment());fragments.add(new MineFragment());// 2. 创建适配器并绑定ViewPager2MyViewPager2Adapter adapter = new MyViewPager2Adapter(this, fragments);viewPager2.setAdapter(adapter);// 3. (可选)关联TabLayout与ViewPager2(实现标签与页面同步)new TabLayoutMediator(tabLayout, viewPager2, (tab, position) -> {// 设置标签文本(根据position动态设置)switch (position) {case 0:tab.setText("首页");break;case 1:tab.setText("推荐");break;case 2:tab.setText("我的");break;}}).attach(); // 必须调用attach()才会生效}
}
(可选)配置 ViewPager2 高级属性

根据需求设置 ViewPager2 的滑动方向、预加载、滑动禁用等属性:

// 1. 设置滑动方向(默认水平,可改为垂直)
viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);// 2. 设置预加载页面数量(默认预加载相邻1页,不能设置为0)
viewPager2.setOffscreenPageLimit(1); // 预加载1页(左右各1页)// 3. 禁用滑动(保留编程式切换,如仅通过Tab点击切换)
viewPager2.setUserInputEnabled(false);// 4. 页面切换监听(监听滑动状态、位置变化)
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {// 页面滚动时回调}@Overridepublic void onPageSelected(int position) {// 页面选中时回调(常用:更新标题栏、加载数据等)Log.d("ViewPager2", "选中第" + position + "页");}@Overridepublic void onPageScrollStateChanged(int state) {// 滑动状态变化:SCROLL_STATE_IDLE(静止)、SCROLL_STATE_DRAGGING(拖动)、SCROLL_STATE_SETTLING(惯性滑动)}
});
FragmentStateAdapter 的工作原理
  • FragmentStateAdapter通过createFragment(int position)为每个位置创建 Fragment,且会缓存当前页及相邻页的 Fragment(数量由offscreenPageLimit控制)。
  • 当 Fragment 不可见且超出缓存范围时,会被销毁(调用onDestroy()),但状态会被保存(通过onSaveInstanceState()),下次显示时重建并恢复状态。
  • 构造方法必须传入FragmentActivityFragment,因为适配器需要通过它们的getSupportFragmentManager()Lifecycle管理 Fragment 生命周期。

在这里插入图片描述


文章转载自:
http://boniness.wanhuigw.com
http://cespitose.wanhuigw.com
http://buckeye.wanhuigw.com
http://accurst.wanhuigw.com
http://bichromate.wanhuigw.com
http://acuteness.wanhuigw.com
http://atresic.wanhuigw.com
http://baroscope.wanhuigw.com
http://andes.wanhuigw.com
http://autopista.wanhuigw.com
http://capot.wanhuigw.com
http://cheer.wanhuigw.com
http://banian.wanhuigw.com
http://automorphism.wanhuigw.com
http://acrodont.wanhuigw.com
http://abattoir.wanhuigw.com
http://choreatic.wanhuigw.com
http://beefalo.wanhuigw.com
http://allier.wanhuigw.com
http://abundant.wanhuigw.com
http://aeromechanics.wanhuigw.com
http://aaui.wanhuigw.com
http://alap.wanhuigw.com
http://approachability.wanhuigw.com
http://bedraggled.wanhuigw.com
http://banshie.wanhuigw.com
http://araneology.wanhuigw.com
http://chihuahua.wanhuigw.com
http://awake.wanhuigw.com
http://brickearth.wanhuigw.com
http://www.dtcms.com/a/281010.html

相关文章:

  • 【LeetCode 热题 100】226. 翻转二叉树——DFS
  • Halcon双相机单标定板标定实现拼图
  • 野卡恢复运营?关服已成趋势
  • 路由器的核心原理以及作用
  • 某东 jdgs参数unidbg环境检测patch分析
  • 健康监测的微泰医疗的公司创始人背景、股权构成、产品类型及技术能力的全方位解读
  • 腾讯元器开发流程解析
  • Enhancing Input-Label Mapping in In-Context Learning withContrastive Decoding
  • 每日钉钉API探索:chooseUserFromList灵活选取自定义联系人
  • 基于 p5.js 实现的未来感神经网络可视化特效
  • Jupyer 魔法方法
  • 专题 函数闭包
  • 海狸IM - 一个功能完整的开源即时通讯系统
  • 数据库中索引到底对哪些sql操作具有提速作用?
  • Python 模块导入常见错误及解决方法
  • 公网ip到服务器流程
  • 智慧水务平台,智慧水务,惠及民生,提升水务管理效率与服务质量
  • 开发者工具在爬虫开发中的应用与面板功能详解
  • kiro, 新款 AI 编辑器, 简单了解一下
  • 图机器学习(5)——无监督图学习与浅层嵌入方法
  • AI Agent概念是什么?全文探讨智能体概念、技术原理及未来趋势
  • 心理学IP的长效增长逻辑:专业壁垒与信任生态的共生之道
  • Python并发模型:多线程与多进程的优劣对比与实战应用
  • linux-线程互斥
  • SMTPman,smtp发送邮件服务器助力邮件通信
  • 对于MSPM0G3系列的使用
  • 【make工具】在Windows环境安装
  • Qt .pro中的.pri详解(四)
  • 15-STM32F103RCT6的FLASH写入
  • 学习C++、QT---26(QT中实现记事本项目实现文件路径的提示、现在我们来学习一下C++类模板、记事本的行高亮的操作的讲解)