Flutter:吸顶结果

打印 上一主题 下一主题

主题 1036|帖子 1036|积分 3108

在分页中,实现tab吸顶。
TDNavBar的screenAdaptation: true, 开启屏幕适配。
该属性已自动对不同手机状态栏高度进行适配。我们只需关注怎样实现吸顶。


   view
  1. import 'package:ducafe_ui_core/ducafe_ui_core.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:get/get.dart';
  4. import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
  5. import 'package:tdesign_flutter/tdesign_flutter.dart';
  6. import 'package:xiaoshukeji/common/index.dart';
  7. import 'index.dart';
  8. // 1. SliverPersistentHeaderDelegate:必须实现的抽象类
  9. class _StickyTabBarDelegate extends SliverPersistentHeaderDelegate {
  10.   final Widget child;
  11.   _StickyTabBarDelegate({required this.child});
  12.   @override
  13.   Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
  14.     // shrinkOffset: 滚动距离
  15.     // overlapsContent: 是否与其他内容重叠
  16.     return Container(
  17.       color: AppTheme.pageBgColor,
  18.       child: child,
  19.     );
  20.   }
  21.   @override
  22.   double get maxExtent => 92.w; // 最大高度,已知tab高度72+上下padding:10
  23.   @override
  24.   double get minExtent => 92.w; // 最小高度
  25.   @override
  26.   bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => true;
  27. }
  28. class RankingPage extends GetView<RankingController> {
  29.   const RankingPage({super.key});
  30.   // 头部皇冠位置
  31.   Widget _buildHeader() {
  32.     return <Widget>[
  33.     ].toRow()
  34.     .card(color: AppTheme.pageBgColor)
  35.     .tight(width: 750.w,height: 300.w,);
  36.   }
  37.   // tab,可吸顶
  38.   Widget _buildTab() {
  39.     return <Widget>[
  40.       <Widget>[
  41.         TextWidget.body('日榜', size: 28.sp, weight: FontWeight.w600, color: AppTheme.textColorfff),
  42.       ].toRow(mainAxisAlignment: MainAxisAlignment.center)
  43.       .card(color: AppTheme.primaryYellow)
  44.       .tight(width: 336.w,height: 72.w,),
  45.       <Widget>[
  46.         TextWidget.body('总榜', size: 28.sp, weight: FontWeight.w600, color: AppTheme.textColor6a7),
  47.       ].toRow(mainAxisAlignment: MainAxisAlignment.center)
  48.       .card(color: AppTheme.navBarBgColor)
  49.       .tight(width: 336.w,height: 72.w,),
  50.     ].toRow(mainAxisAlignment: MainAxisAlignment.spaceBetween);
  51.   }
  52.   // 数据列表
  53.   Widget _buildDataList() {
  54.     return SliverList(
  55.       delegate: SliverChildBuilderDelegate(
  56.         (context, index) {
  57.           return <Widget>[]
  58.               .toRow()
  59.               .paddingHorizontal(30.w)
  60.               .card(color: AppTheme.blockBgColor)
  61.               .tight(
  62.                 width: 690.w,
  63.                 height: 120.w,
  64.               )
  65.               .marginOnly(bottom: 20.w);
  66.         },
  67.         childCount: 20,
  68.       ),
  69.     );
  70.   }
  71.   // 主视图
  72.   Widget _buildView() {
  73.     return SmartRefresher(
  74.       controller: controller.refreshController,
  75.       enablePullUp: true,
  76.       onRefresh: controller.onRefresh,
  77.       onLoading: controller.onLoading,
  78.       footer: const SmartRefresherFooterWidget(),
  79.       header: const SmartRefresherHeaderWidget(),
  80.       child: CustomScrollView(
  81.         slivers: [
  82.           // 头部
  83.           _buildHeader().sliverToBoxAdapter().sliverPaddingHorizontal(30.w),
  84.          
  85.           // 2. SliverPersistentHeader:实现吸顶的核心组件
  86.           SliverPersistentHeader(
  87.             pinned: true,  // 设置为 true 实现吸顶
  88.             delegate: _StickyTabBarDelegate(
  89.               child: Container(
  90.                 padding: EdgeInsets.symmetric(horizontal: 30.w, vertical: 10.w),
  91.                 child: _buildTab(),
  92.               ),
  93.             ),
  94.           ),
  95.          
  96.           // 列表内容
  97.           _buildDataList().sliverPaddingHorizontal(30.w),
  98.         ],
  99.       ),
  100.     );
  101.   }
  102.   @override
  103.   Widget build(BuildContext context) {
  104.     return GetBuilder<RankingController>(
  105.       init: RankingController(),
  106.       id: "ranking",
  107.       builder: (_) {
  108.         return Scaffold(
  109.           backgroundColor: AppTheme.pageBgColor, // 自定义颜色
  110.           appBar: const TDNavBar(
  111.             height: 0,
  112.             titleColor: AppTheme.textColorfff,
  113.             titleFontWeight: FontWeight.w600,
  114.             backgroundColor: AppTheme.pageBgColor,
  115.             screenAdaptation: true, // 是否进行屏幕适配,默认true
  116.             useDefaultBack: false,
  117.           ),
  118.           body: _buildView(),
  119.         );
  120.       },
  121.     );
  122.   }
  123. }
复制代码
  controller
  1. import 'package:get/get.dart';
  2. import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
  3. class RankingController extends GetxController {
  4.   RankingController();
  5.   List items = [];
  6.   /*
  7.   * 分页
  8.   * refreshController:分页控制器
  9.   * _page:分页
  10.   * _limit:每页条数
  11.   * _loadNewsSell:拉取数据(是否刷新)
  12.   * onLoading:上拉加载新商品
  13.   * onRefresh:下拉刷新
  14.   * */
  15.   final RefreshController refreshController = RefreshController(
  16.     initialRefresh: true,
  17.   );
  18.   // int _page = 1;
  19.   // int _limit = 20;
  20.   Future<bool> _loadNewsSell(bool isRefresh) async {
  21.     return false;
  22.     // var result = await ProductApi.products(ProductsReq(
  23.     //   page:isRefresh ? 1:_page,
  24.     //     prePage:_limit
  25.     // ));
  26.     // if(isRefresh){
  27.     //   _page = 1;
  28.     //   items.clear();
  29.     // }
  30.     // if(result.isNotEmpty){
  31.     //   _page++;
  32.     //   items.addAll(result);
  33.     // }
  34.     // // 是否是空
  35.     // return result.isEmpty;
  36.   }
  37.   // 上拉载入新商品
  38.   void onLoading() async {
  39.     if (items.isNotEmpty) {
  40.       try {
  41.         // 拉取数据是否为空 ? 设置暂无数据 : 加载完成
  42.         var isEmpty = await _loadNewsSell(false);
  43.         isEmpty
  44.             ? refreshController.loadNoData()
  45.             : refreshController.loadComplete();
  46.       } catch (e) {
  47.         refreshController.loadFailed(); // 加载失败
  48.       }
  49.     } else {
  50.       refreshController.loadNoData(); // 设置无数据
  51.     }
  52.     update(["ranking"]);
  53.   }
  54.   // 下拉刷新
  55.   void onRefresh() async {
  56.     try {
  57.       await _loadNewsSell(true);
  58.       refreshController.refreshCompleted();
  59.     } catch (e) {
  60.       refreshController.refreshFailed();
  61.     }
  62.     update(["ranking"]);
  63.   }
  64.   _initData() {
  65.     update(["ranking"]);
  66.   }
  67.   void onTap() {}
  68.   // @override
  69.   // void onInit() {
  70.   //   super.onInit();
  71.   // }
  72.   @override
  73.   void onReady() {
  74.     super.onReady();
  75.     _initData();
  76.   }
  77.   // @override
  78.   // void onClose() {
  79.   //   super.onClose();
  80.   // }
  81. }
复制代码
  纪录tab切换
  1. int currentTab = 0; // 当前选中的tab索引
  2. // tab切换方法
  3. void switchTab(int index) {
  4.   if (currentTab == index) return;
  5.   currentTab = index;
  6.   items.clear();// 切换tab时重置列表数据
  7.   refreshController.requestRefresh();
  8.   update(["ranking"]);
  9. }
  10.   // tab切换
  11. Widget _buildTab() {
  12.   return <Widget>[
  13.     <Widget>[
  14.       TextWidget.body('日榜', size: 28.sp, weight: FontWeight.w600, color: controller.currentTab == 0 ?  AppTheme.textColorfff : AppTheme.textColor646),
  15.     ].toRow(mainAxisAlignment: MainAxisAlignment.center)
  16.     .card(color: controller.currentTab == 0 ? AppTheme.primaryYellow : AppTheme.navBarBgColor)
  17.     .tight(width: 336.w,height: 72.w,).onTap(() {
  18.       controller.switchTab(0);
  19.     }),
  20.     <Widget>[
  21.       TextWidget.body('总榜', size: 28.sp, weight: FontWeight.w600, color: controller.currentTab == 1 ?  AppTheme.textColorfff : AppTheme.textColor646),
  22.     ].toRow(mainAxisAlignment: MainAxisAlignment.center)
  23.     .card(color: controller.currentTab == 1 ? AppTheme.primaryYellow : AppTheme.navBarBgColor )
  24.     .tight(width: 336.w,height: 72.w,).onTap(() {
  25.       controller.switchTab(1);
  26.     }),
  27.   ].toRow(mainAxisAlignment: MainAxisAlignment.spaceBetween);
  28. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

河曲智叟

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表