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

Flutter TabBar与TabBarView联动及获取当前点击栏目索引

     TabBar还有TabBarView都是谷歌flutter官方组件库——Material组件库提供的组件,其中TabBar用于导航切换,TabBarView则是配合其切换显示的对应的视图,官网参考地址:TabBarView class - material library - Dart API。

        实现一体联动有两种实现方式:使用默认控制器(DefaultTabController)和自定义控制器。使用自定义控制器灵活性更高,但是需要指定TabController的length属性,但有些情况下栏目的实际数据是从网络上异步加载读取的,这个TabController的length无法动态更新或后面重新指定,非常扯淡,具体实现参考:flutter 之 TabBar、TabBarView的使用 - 简书。

      本文主要介绍在使用DefaultTabController下,实现获取点击当前栏目的索引,包括点击TabBar和滑动TabBarView以及视图状态保持,示例如下:

  late int _selectIndex = 0;late final ScrollController _scrollController;late final NewsPageViewModel _vm = NewsPageViewModel();late final _scaffoldKey = GlobalKey<_NewsPageViewState>();@overridevoid initState() {// TODO: implement initStatesuper.initState();//栏目滑动索引改变_scrollController = ScrollController(onDetach: (ScrollPosition position) {if (_scaffoldKey.currentContext != null) {final controller =DefaultTabController.of(_scaffoldKey.currentContext!);controller.addListener(() {if (controller.index.toDouble() == controller.animation?.value) {//loadListDataFor(controller.index);debugPrint(controller.index);}});}});}@overrideWidget build(BuildContext context) {// TODO: implement buildreturn BaseView<NewsPageViewModel>(viewModel: _vm,build: (context, viewModel, child) {if (viewModel.state == ViewState.Busy) {return BaseView.loadingWidget();} else {return DefaultTabController(initialIndex: _selectIndex,length: viewModel.arrCategory.length,child: NestedScrollView(controller: _scrollController,headerSliverBuilder:(BuildContext context, bool innerBoxIsScrolled) {return <Widget>[SliverOverlapAbsorber(handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),sliver: SliverAppBar(title: Utils.shareInstance.customPageTitle('资讯'),//标题横向间距titleSpacing: 15,//左侧的图标或文字,多为返回箭头leading: null,//左边按钮的宽度leadingWidth: 15,//居中centerTitle: false,//标题栏是否固定pinned: true,//滑动时是否悬浮floating: false,//配合floating使用snap: false,//是否显示在状态栏的下面,false就会占领状态栏的高度primary: true,//设置分栏区域上面的高度// expandedHeight: 0,elevation: 0,//是否显示阴影,直接取值innerBoxIsScrolled,展开不显示阴影,合并后会显示forceElevated: innerBoxIsScrolled,//自定义导航和中间内容的展示flexibleSpace: null,//导航栏背景色backgroundColor: K_APP_NAVIGATION_BACKGROUND_COLOR,//TabBar 分栏标题bottom: _setCategoryTabBar(viewModel),),)];},//分栏展示的页面信息body: _setCategoryTabBarView(context, viewModel),));}},onModelReady: (viewModel) {//加载栏目viewModel.categoryLoad(context, isLoading: false);});}@overridevoid dispose() {_scrollController.dispose();// TODO: implement disposesuper.dispose();}//MARK: - 扩展
extension on _NewsPageViewState {//分栏菜单TabBar _setCategoryTabBar(NewsPageViewModel viewModel) {return TabBar(key: _scaffoldKey,//设置对齐方式(否则左边有空白)tabAlignment: TabAlignment.start,//是否允许滚动isScrollable: true,//未选中的颜色unselectedLabelColor: Utils.shareInstance.hexToInt(0x505050),//未选中的样式unselectedLabelStyle: const TextStyle(fontSize: 15),//选中的颜色labelColor: K_APP_TINT_COLOR,//选中的样式labelStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),//底部滑动条样式indicatorSize: TabBarIndicatorSize.label,//底部滑动条颜色indicatorColor: K_APP_TINT_COLOR,//菜单项目tabs: viewModel.arrCategory.map((item) {return Tab(text: item.name);}).toList(),//点击事件onTap: (index) {debugPrint(index);//loadListDataFor(index);setState(() {_selectIndex = index;});},);}// tabBar 分栏菜单各个页面Widget _setCategoryTabBarView(BuildContext context, NewsPageViewModel viewModel) {return TabBarView(children: viewModel.arrCategory.map((item) {//设置UIreturn SafeArea(top: false,bottom: false,child: Builder(builder: (BuildContext context) {return CustomScrollView(slivers: [SliverOverlapInjector(handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),),SliverPadding(padding: EdgeInsets.zero,sliver: SliverFixedExtentList(delegate: SliverChildBuilderDelegate((BuildContext context, int index) {final m = viewModel.arrList[index];if (m.className == '快讯') {//7x24快讯return NewsPageViewInformationCell(index, m, context, viewModel);}return NewsPageViewCell(index, m, context, viewModel);}, childCount: viewModel.arrList.length),itemExtent: 50.0 //item高度或宽度,取决于滑动方向),)],);},));}).toList());}}

上面方法进过实际测试,可以实现点击和滑动时获取当前栏目的索引,以便根据索引执行加载当前页面的栏目数据的业务逻辑。随之会产生新的问题就是栏目来回切换没有保持页面的状态,会重复加载数据,解决思路是借助 AutomaticKeepAliveClientMixin 并设置 wantKeepAlive 为true,在PageView和PageController组合中同样适用,效果如下:

86_1720350605

参考Demo,日拱一卒,持续更新

http://www.lryc.cn/news/396792.html

相关文章:

  • 【区块链+跨境服务】跨境出口电商溯源 | FISCO BCOS应用案例
  • 记录一次mysql死锁问题的分析排查
  • 【UE5.1 角色练习】16-枪械射击——瞄准
  • 04OLED简介和调试方法
  • “LNMP环境搭建实战指南:从零开始配置CentOS 7下的Nginx、MySQL与PHP“
  • 院内导航:如何用科技破解就医找路难题
  • C++基础篇(1)
  • 云视频监控中的高效视频转码策略:视频汇聚EasyCVR平台H.265自动转码H.264能力解析
  • xcode配置swift使用自定义主题颜色或者使用RGB或者HEX颜色
  • 相同含义但不同类型字段作为join条件时注意事项
  • 数据结构(3.8)——栈的应用
  • 前端面试题35(在iOS和Android平台上,实现WebSocket协议有哪些常见的库或框架?)
  • Mysql如何高效ALTER TABL
  • vue3+vite搭建第一个cesium项目详细步骤及环境配置(附源码)
  • LiteOS增加执行自定义源码
  • 《Nature》文章:ChatGPT帮助我学术写作的三种方式
  • 防火墙安全策略与用户认证综合实验
  • vue学习day05-watch侦听器(监视器)、Vue生命周期和生命周期的四个阶段、、工程化开发和脚手架Vue cli
  • 数字人+展厅互动体验方案:多元化互动方式,拓宽文化文娱新体验
  • 在Spring Boot项目中集成监控与报警
  • opencv实现目标检测功能----20240704
  • 音视频解封装demo:使用libmp4v2解封装(demux)出mp4文件中的h264视频数据和aac语音数据
  • 手撸俄罗斯方块(一)——简单介绍
  • 构建LangChain应用程序的示例代码:61、如何使用 LangChain 和 LangSmith 优化链
  • Android系统通过属性设置来控制log输出的方案
  • JavaDoc的最佳实践
  • 数字力量助西部职教全面提升——唯众品牌大数据、人工智能系列产品中标甘肃庆阳职院数字经济人才培养基地!
  • Swagger的原理及应用详解(四)
  • Elasticsearch7.10集群搭建
  • SMU Summer 2024 Contest Round 3