Flutter:自定义Tab切换,订单列表页tab,tab吸顶

1、自定义tab切换

在这里插入图片描述

view

<Widget>[// 好评<Widget>[TDImage(assetUrl: 'assets/img/order4.png',width: 36.w,height: 36.w,),SizedBox(width: 10.w,),TextWidget.body('好评',size: 24.sp,color: controller.tabIndex == 0 ? AppTheme.colorfff : AppTheme.color999,),].toRow(mainAxisAlignment: MainAxisAlignment.center).card(color: controller.tabIndex == 0 ? AppTheme.error : AppTheme.colorfff,shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.w))).tight(width: 160.w,height: 68.w).onTap(() {controller.onTapOrderStatus(0);}),SizedBox(width: 20.w,),// 中评<Widget>[TDImage(assetUrl: 'assets/img/order5.png',width: 36.w,height: 36.w,),SizedBox(width: 10.w,),TextWidget.body('中评',size: 24.sp,color: controller.tabIndex == 1 ? AppTheme.colorfff : AppTheme.color999,),].toRow(mainAxisAlignment: MainAxisAlignment.center).card(color: controller.tabIndex == 1 ? AppTheme.error : AppTheme.colorfff,shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.w))).tight(width: 160.w,height: 68.w).onTap(() {controller.onTapOrderStatus(1);}),SizedBox(width: 20.w,),// 差评<Widget>[TDImage(assetUrl: 'assets/img/order6.png',width: 36.w,height: 36.w,),SizedBox(width: 10.w,),TextWidget.body('差评',size: 24.sp,color: controller.tabIndex == 2 ? AppTheme.colorfff : AppTheme.color999,),].toRow(mainAxisAlignment: MainAxisAlignment.center).card(color: controller.tabIndex == 2 ? AppTheme.error : AppTheme.colorfff,shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.w))).tight(width: 160.w,height: 68.w).onTap(() {controller.onTapOrderStatus(2);}),
].toRow(),

controller

import 'package:flutter/material.dart';
import 'package:get/get.dart';
class OrderEvaluateController extends GetxController{OrderEvaluateController();// tab 索引int tabIndex = 0;// 状态改变onTapOrderStatus(int index){tabIndex = index;// print('tabIndex: $tabIndex');update(["order_evaluate"]);}@overridevoid onClose() {super.onClose();tabController.dispose();}
}

2、订单列表tab,可以指定tabIndex的初始位置

在这里插入图片描述

view

import 'package:demo/common/index.dart';
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import 'index.dart';class OrderListPage extends GetView<OrderListController> {const OrderListPage({super.key});// tab切换Widget _buildTab() {return TDTabBar(controller: controller.tabController,tabs: controller.tabNames.map((e) => TDTab(text: e)).toList(),onTap: (index) {controller.onTapOrderStatus(index);},backgroundColor: Colors.white,showIndicator: true,indicatorColor: const Color(0xffe01e1e),labelColor: const Color(0xffe01e1e),);}// list 列表Widget _buildList() {return SmartRefresher(controller: controller.refreshController,enablePullUp: true, // 启用上拉加载onRefresh: controller.onRefresh, // 下拉刷新回调onLoading: controller.onLoading, // 上拉加载回调footer: const SmartRefresherFooterWidget(), // 底部加载更多组件header: const SmartRefresherHeaderWidget(), // 顶部下拉刷新组件child: ListView.builder(itemCount: 10,itemBuilder: (context, index) {return _buildItem();},),);}// 商品itemWidget _buildItem() {return Text('item')}// 主视图Widget _buildView() {return <Widget>[_buildTab(),Expanded(child: _buildList()),].toColumn();}@overrideWidget build(BuildContext context) {return GetBuilder<OrderListController>(init: OrderListController(),id: "order_list",builder: (_) {return Scaffold(backgroundColor: const Color(0xffF5F6FA),appBar: const TDNavBar(height: 45,title: '我的订单',titleFontWeight: FontWeight.w600,backgroundColor: Colors.white,screenAdaptation: true,useDefaultBack: true,),body: SafeArea(child: _buildView(),),);},);}
}

controller

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';class OrderListController extends GetxController with GetSingleTickerProviderStateMixin{OrderListController();// 订单列表List items = [];// tab 控制器late TabController tabController;// tab 索引int tabIndex = Get.arguments["tabIndex"] ?? 0;// tab 名称List<String> tabNames = ['全部', '待付款', '待发货', '待收货', '已完成'];// 订单状态改变onTapOrderStatus(int index){tabIndex = index;// 刷新订单列表refreshController.requestRefresh();update(["order_list"]);}@overridevoid onInit() {super.onInit();// 初始化时设置当前索引tabController = TabController(length: tabNames.length,vsync: this,initialIndex: tabIndex, // 设置初始索引);// 监听 tab 切换tabController.addListener(() {if (tabController.indexIsChanging) {tabIndex = tabController.index;update(["order_list"]);}});}@overridevoid onClose() {super.onClose();refreshController.dispose();tabController.dispose();}/** 分页* refreshController:分页控制器* _page:分页* _limit:每页条数* _loadNewsSell:拉取数据(是否刷新)* onLoading:上拉加载新商品* onRefresh:下拉刷新* */final RefreshController refreshController = RefreshController(initialRefresh: true,);// int _page = 1;// int _limit = 20;Future<bool> _loadNewsSell(bool isRefresh) async {return false;// var result = await ProductApi.products(ProductsReq(//   page:isRefresh ? 1:_page,//     prePage:_limit// ));// if(isRefresh){//   _page = 1;//   items.clear();// }// if(result.isNotEmpty){//   _page++;//   items.addAll(result);// }// // 是否是空// return result.isEmpty;}// 上拉载入新商品void onLoading() async {if (items.isNotEmpty) {try {// 拉取数据是否为空 ? 设置暂无数据 : 加载完成var isEmpty = await _loadNewsSell(false);isEmpty? refreshController.loadNoData(): refreshController.loadComplete();} catch (e) {refreshController.loadFailed(); // 加载失败}} else {refreshController.loadNoData(); // 设置无数据}update(["goods_list"]);}// 下拉刷新void onRefresh() async {try {await _loadNewsSell(true);refreshController.refreshCompleted();} catch (e) {refreshController.refreshFailed();}update(["goods_list"]);}
}

3、tab吸顶,主要记录view中的实现。
下拉刷新和tab切换的方法基本与上方2、的controller一致

在这里插入图片描述
在这里插入图片描述

view

import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import 'package:xiaoshukeji/common/index.dart';
import 'index.dart';// 1. SliverPersistentHeaderDelegate:必须实现的抽象类
class _StickyTabBarDelegate extends SliverPersistentHeaderDelegate {final Widget child;_StickyTabBarDelegate({required this.child});@overrideWidget build(BuildContext context, double shrinkOffset, bool overlapsContent) {// shrinkOffset: 滚动距离// overlapsContent: 是否与其他内容重叠return Container(color: AppTheme.pageBgColor,child: child,);}@overridedouble get maxExtent => 92.w; // 最大高度,已知tab高度72+上下padding:10@overridedouble get minExtent => 92.w; // 最小高度@overridebool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => true;
}class RankingPage extends GetView<RankingController> {const RankingPage({super.key});// 头部皇冠位置Widget _buildHeader() {return <Widget>[].toRow().card(color: AppTheme.pageBgColor).tight(width: 750.w,height: 300.w,);}// tab,可吸顶Widget _buildTab() {return <Widget>[<Widget>[TextWidget.body('日榜', size: 28.sp, weight: FontWeight.w600, color: AppTheme.textColorfff),].toRow(mainAxisAlignment: MainAxisAlignment.center).card(color: AppTheme.primaryYellow).tight(width: 336.w,height: 72.w,),<Widget>[TextWidget.body('总榜', size: 28.sp, weight: FontWeight.w600, color: AppTheme.textColor6a7),].toRow(mainAxisAlignment: MainAxisAlignment.center).card(color: AppTheme.navBarBgColor).tight(width: 336.w,height: 72.w,),].toRow(mainAxisAlignment: MainAxisAlignment.spaceBetween);}// 数据列表Widget _buildDataList() {return SliverList(delegate: SliverChildBuilderDelegate((context, index) {return <Widget>[].toRow().paddingHorizontal(30.w).card(color: AppTheme.blockBgColor).tight(width: 690.w,height: 120.w,).marginOnly(bottom: 20.w);},childCount: 20,),);}// 主视图Widget _buildView() {return SmartRefresher(controller: controller.refreshController,enablePullUp: true,onRefresh: controller.onRefresh,onLoading: controller.onLoading,footer: const SmartRefresherFooterWidget(),header: const SmartRefresherHeaderWidget(),child: CustomScrollView(slivers: [// 头部_buildHeader().sliverToBoxAdapter().sliverPaddingHorizontal(30.w),// 2. SliverPersistentHeader:实现吸顶的核心组件SliverPersistentHeader(pinned: true,  // 设置为 true 实现吸顶delegate: _StickyTabBarDelegate(child: Container(padding: EdgeInsets.symmetric(horizontal: 30.w, vertical: 10.w),child: _buildTab(),),),),// 列表内容_buildDataList().sliverPaddingHorizontal(30.w),],),);}@overrideWidget build(BuildContext context) {return GetBuilder<RankingController>(init: RankingController(),id: "ranking",builder: (_) {return Scaffold(backgroundColor: AppTheme.pageBgColor, // 自定义颜色appBar: const TDNavBar(height: 0,titleColor: AppTheme.textColorfff,titleFontWeight: FontWeight.w600,backgroundColor: AppTheme.pageBgColor,screenAdaptation: true, // 是否进行屏幕适配,默认trueuseDefaultBack: false,),body: _buildView(),);},);}
}
GetTickerProviderStateMixin 和 GetSingleTickerProviderStateMixin 的主要区别在于:
1、GetSingleTickerProviderStateMixin:
用于创建单个 AnimationController
性能更好,因为只维护一个 Ticker
适用场景:只需要一个动画控制器的情况,如单个 TabController
class MyController extends GetxController with GetSingleTickerProviderStateMixin {late TabController tabController;@overridevoid onInit() {super.onInit();tabController = TabController(length: 3, vsync: this);}@overridevoid onClose() {tabController.dispose();super.onClose();}
}2、GetTickerProviderStateMixin:
可以创建多个 AnimationController
适用场景:需要多个独立动画控制器的情况class MyController extends GetxController with GetTickerProviderStateMixin {late AnimationController controller1;late AnimationController controller2;@overridevoid onInit() {super.onInit();controller1 = AnimationController(vsync: this,duration: const Duration(milliseconds: 300),);controller2 = AnimationController(vsync: this,duration: const Duration(milliseconds: 500),);}
}什么时候需要 GetSingleTickerProviderStateMixin:
当你使用 TabController 来控制 tab 切换动画
当你需要实现滑动切换 tab 功能
当你需要更复杂的 tab 切换效果如果只需要点击切换,不需要 GetSingleTickerProviderStateMixin

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习笔记——循环神经网络RNN

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍面试过程中可能遇到的循环神经网络RNN知识点。 文章目录 文本特征提取的方法1. 基础方法1.1 词袋模型&#xff08;Bag of Words, BOW&#xff09;工作原…

nvm版本安装

安装 使用切换 MySQL5.7新安装 熟人命令 8.0 mysql -P3306 -uroot -p5.7 mysql -P3307 -uroot -p 记得用完关闭

人工智能之深度学习_[4]-神经网络入门

文章目录 神经网络基础1 神经网络1.1 神经网络概念1.1.1 什么是神经网络1.1.2 如何构建神经网络1.1.3 神经网络内部状态值和激活值 1.2 激活函数1.2.1 网络非线性因素理解1.2.2 常见激活函数1.2.2.1 Sigmoid 激活函数1.2.2.2 Tanh 激活函数1.2.2.3 ReLU 激活函数1.2.2.4 SoftMa…

一文大白话讲清楚webpack基本使用——11——chunkIds和runtimeChunk

文章目录 一文大白话讲清楚webpack基本使用——11——chunkIds和runtimeChunk1. 建议按文章顺序从头看&#xff0c;一看到底&#xff0c;豁然开朗2. 啥是chunkIds3.怎么使用chunkIds4. 啥是runtimeChunk5. 怎么使用runtimeChunk 一文大白话讲清楚webpack基本使用——11——chun…

第11篇:vue3 中 props 的使用

第一步&#xff1a;App.vue 中发送数据&#xff1a; <template> <Person :list"persons"/> //注意多个的话 中间是没有 , // <Person a "哈哈中" :list persons /> </template> let persons reactive([ {id:e98219e12,n…

【Tool】沉浸式翻译 DeepLX

效果对比 对比一下四个常用的翻译工具的效果 不难看出只有Deepl算是在讲人话 如何配置 DeepLX 安装沉浸式翻译插件 获取APIKEY 从这获取: https://linux.do/t/topic/111737 配置 参考官方教程: https://linux.do/t/topic/111911

SSM开发(二) MyBatis简介

目录 一、MyBatis是什么 二、mybatis的优点 三、mybatis的缺点 四、mybatis与JDBC、jdbctemplate对比 1、JDBC 2、 MyBatis 3、 JdbcTemplate 五、mybatis工作原理 一、MyBatis是什么 mybatis是一个简化和实现了java数据持久层的开源框架&#xff0c;它抽象了大量的JDB…

LabVIEW 水电站厂内经济运行系统

基于 LabVIEW 的水电站经济运行系统&#xff0c;主要针对农村小水电站运行管理的不足进行改进&#xff0c;通过精确控制发电与用水量&#xff0c;最小化耗水量并优化负荷分配&#xff0c;提升水电站的运营效率和经济效益。 ​ LabVIEW 在系统中的功能特点 强大的图形化编程环…

重学SpringBoot3-WebClient配置与使用详解

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞??收藏评论 重学SpringBoot3-WebClient配置与使用详解 1. 简介2. 环境准备 2.1 依赖配置 3. WebClient配置 3.1 基础配置3.2 高级配置3.3 retrieve()和exchange()区别 4. 使用示例 4.1 基本请求操…

鸿蒙仓颉环境配置(仓颉SDK下载,仓颉VsCode开发环境配置,仓颉DevEco开发环境配置)

目录 ​1&#xff09;仓颉的SDK下载 1--进入仓颉的官网 2--点击图片中的下载按钮 3--在新跳转的页面点击即刻下载 4--下载 5--找到你们自己下载好的地方 6--解压软件 2&#xff09;仓颉编程环境配置 1--找到自己的根目录 2--进入命令行窗口 3--输入 envsetup.bat 4--验证是否安…

【AI编辑器】字节跳动推出AI IDE——Trae,专为中文开发者深度定制

目录 一、背景 二、核心特性 2.1 AI驱动的代码自动生成 2.2 智能问答与代码补全 2.3 多语言支持 2.4 插件与扩展 三、架构 四、下载使用 4.1 下载与安装 4.2 界面与配置 五、应用实践 5.1 快速生成代码 5.2 智能问答与调试 5.3 团队协作与代码审查 六、与Cursor…

linux网络 | 传输层TCP | 认识tcp报头字段与分离

前言&#xff1a; 本节内容继续传输层的讲解&#xff0c; 本节讲解的是tcp协议。 tcp协议是我们日常中最常用的协议。就比如我们浏览网页&#xff0c;我们知道网页时http或者https协议。 其实http或者https底层就是用的tcp协议。tcp协议&#xff0c;全名又称为传输控制协议&…

快速入门Flink

Flink是新一代实时计算平台&#xff0c;采用原生的流处理系统&#xff0c;保证了低延迟性&#xff0c;在API和容错上也是做的相当完善&#xff0c;本文将从架构、组件栈、安装、入门程序等进行基础知识的分析&#xff0c;帮助大家快速对Flink有一个了解。 一.简介 1.是什么 Ap…

最新版pycharm如何配置conda环境

首先在conda prompt里创建虚拟环境&#xff0c;比如 conda create --prefix E:/projects/myenv python3.8然后激活 conda activate E:/projects/myenv往里面安装点自己的包&#xff0c;比如 conda install pytorch1.7.1 torchvision0.8.2 -c pytorch打开pycharm 注意&#x…

循环队列(C语言版)

循环队列(C语言版&#xff09; 1.简单介绍循环队列2.使用何种结构来实现3.基本结构4.初始化5.判空判满6.向循环队列插入一个元素7.从循环队列中删除一个元素8.获取队头队尾元素9.释放空间10.完整代码 &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#…

【线性代数】列主元法求矩阵的逆

列主元方法是一种用于求解矩阵逆的数值方法&#xff0c;特别适用于在计算机上实现。其基本思想是通过高斯消元法将矩阵转换为上三角矩阵&#xff0c;然后通过回代求解矩阵的逆。以下是列主元方法求解矩阵 A A A 的逆的步骤&#xff1a; [精确算法] 列主元高斯消元法 步骤 1&am…

OGG 19C 集成模式启用DDL复制

接Oracle19C PDB 环境下 OGG 搭建&#xff08;PDB to PDB&#xff09;_cdb架构 配置ogg-CSDN博客&#xff0c;给 pdb 环境 ogg 配置 DDL 功能。 一个报错 SYShfdb1> ddl_setup.sqlOracle GoldenGate DDL Replication setup scriptVerifying that current user has privile…

基于微信小程序的健身管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

澎峰科技计算软件栈与沐曦GPU完成适配和互认证

近期&#xff0c;澎峰科技与沐曦完成了对PerfXLM&#xff08;推理引擎&#xff09;、PerfXCloud&#xff08;大模型服务平台&#xff09;与沐曦的曦云系列通用计算GPU的联合测试&#xff0c;测试结果表明PerfXLM、PerfXCloud软件与沐曦GPU产品实现了全面兼容。 PerfXLM高性能大…

Tensor 基本操作1 unsqueeze, squeeze, softmax | PyTorch 深度学习实战

本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 目录 创建 Tensor常用操作unsqueezesqueezeSoftmax代码1代码2代码3 argmaxitem 创建 Tensor 使用 Torch 接口创建 Tensor import torch参考&#xff1a;https://pytorch.org/tutorials/beginn…