Flutter吸顶Tabbar+流式布局
实现APP首页tabbar滚动吸顶功能
首页代码:
WillPopScope( child: Scaffold( backgroundColor: Colors.white, appBar: PreferredSize( preferredSize: Size(double.infinity, 0.w), child: AppBar( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, elevation: 0, title: const Text(""), ), ), body: NestedScrollView( controller: scrollController, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return <Widget>[ buildHeaderWidget(), // tabbar上面被隐藏的部分 SliverOverlapAbsorber( handle: NestedScrollView.sliverOverlapAbsorberHandleFor( context), sliver: SliverPersistentHeader( pinned: true, // floating: true, delegate: StickyTabBarDelegate( child: BrnTabBar( //生成tabbar controller: tabController, tabs: tabs, showMore: true, moreWindowText: "栏目总览", onTap: (state, index) { state.refreshBadgeState(index); // scrollController.animateTo( // globalKey.currentContext!.size!.height, // duration: Duration(milliseconds: 200), // curve: Curves.linear); }, onMorePop: () {}, closeController: closeWindowController, ), ), ), ), SliverToBoxAdapter( child: SizedBox( height: 60.w, ), ) ]; }, body: TabBarView( controller: tabController, children: catTabList.map<Widget>((e) { return HomeArticlesListPage(e.id, showTopContainer: showTopContainer); }).toList(), ), // ), ), onWillPop: () { if (closeWindowController!.isShow) { closeWindowController!.closeMoreWindow(); return Future.value(false); } return Future.value(true); }, );
tabbar下 各页面流式布局代码:
流式布局使用的是 MasonryGridView.count();
因为是要在tabbar下的页面 所以 要关闭滚动 且不能绑定 controller;
绑定controller会导致 首页有滚动事件滚动首页部分
流式布局组件滚动流式布局的界面 然会吸顶 就会失效。
我一开始就犯了这个错误 虽然设置了 physics: const NeverScrollableScrollPhysics(),
让流式布局不滚动 但是忘记去除绑定的 controller 就导致吸顶的动画出错了。
import 'package:communityApp/app/router/routers.dart'; import 'package:communityApp/app/utils/local_storage.dart'; import 'package:communityApp/components/cache_Image_widget.dart'; import 'package:communityApp/home_system/request/homeRequest.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; class HomeArticlesListPage extends StatefulWidget { final int activeCatId; //当前选择的栏目ID Function? showTopContainer; HomeArticlesListPage(this.activeCatId, {Key? key, this.showTopContainer}) : super(key: key); @override State<HomeArticlesListPage> createState() => _HomeArticlesListPageState(); } class _HomeArticlesListPageState extends State<HomeArticlesListPage> { late ScrollController _scrollViewController; List _buildArticleList = []; // 瀑布留 数据列表 bool _isOver = true; // 接口请求 防抖 int _page = 1; //当前的页数 bool _haveMore = true; //是否有更多的数据 @override void initState() { super.initState(); _scrollViewController = ScrollController(initialScrollOffset: 0.w) ..addListener(() { // print(_scrollViewController.position.pixels); // if (_scrollViewController.position.pixels < 10) { // widget.showTopContainer == null ? '' : widget.showTopContainer!(0.0); // } else { // widget.showTopContainer == null ? '' : widget.showTopContainer!(-1.0); // } // 当滚动到最底部的时候,加载新的数据 if (_scrollViewController.position.pixels == _scrollViewController.position.maxScrollExtent) { //当还有更多数据的时候才会进行加载新数据 if (_haveMore) { _getListViewList(); } } }); _getListViewList(); } // 加载更多 数据 void _getListViewList() async { if (!_isOver) return; _isOver = false; if (_haveMore) { var userId = await LocalStorage.get(LocalStorage.userId); var result = await HomeRequest.getArticleList({ 'userId': userId, 'articleCatId': widget.activeCatId, 'pageSize': 10, 'pageNum': _page }); _isOver = true; if (mounted) { setState(() { if (_page == 1) { _buildArticleList = result; } else { _buildArticleList.addAll(result); } if (result.length == 10) { _page++; } else if (result.length < 10) { _haveMore = false; } }); } } } @override Widget build(BuildContext context) { double width = MediaQuery.of(context).size.width; double height = MediaQuery.of(context).size.height; return Container( padding: EdgeInsets.fromLTRB(20.w, 0.w, 20.w, 60.w), child: MasonryGridView.count( // controller: _scrollViewController, // 展示几列 crossAxisCount: 2, // 元素总个数 itemCount: _buildArticleList.length, // 单个子元素 itemBuilder: (BuildContext context, int index) { var item = _buildArticleList[index]; var user = item['user']; return GestureDetector( onTap: () async { /* 跳转 */ if (item["type"] == 1) { /* 跳转到动态 */ var result = await Navigator.of(context).pushNamed( CommunityAppRouter.articelDetailPage, arguments: {"articleId": item["id"].toString()}); } else { var result = await Navigator.of(context).pushNamed( CommunityAppRouter.evaluationDetailPage, arguments: {"articleId": item["id"].toString()}); } }, child: Container( child: Column( children: [ Container( clipBehavior: Clip.hardEdge, //溢出隐藏c decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.w), ), child: CaCheImageWidget( item['frontCover'], ), ), Container( padding: EdgeInsets.all(8.w), child: Text( item['title'], overflow: TextOverflow.ellipsis, maxLines: 2, style: TextStyle( color: const Color.fromARGB(255, 0, 0, 0), fontSize: 15.sp, fontWeight: FontWeight.bold, ), ), ), Container( padding: EdgeInsets.fromLTRB(8.w, 0, 8.w, 8.w), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( width: 110.w, decoration: BoxDecoration(), clipBehavior: Clip.hardEdge, child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ClipOval( child: CaCheImageWidget( user['picture'], width: 14.w, height: 14.w, ), ), Container( width: 90.w, margin: EdgeInsets.only(left: 4.w), child: Text( user['nickName'], overflow: TextOverflow.ellipsis, maxLines: 2, style: TextStyle( color: Color(0xFFB3BBBD), fontSize: 11.sp, ), ), ) ], ), ), Container( child: Text( '${item['viewNum']}看过', style: TextStyle( color: const Color(0xFFB3BBBD), fontSize: 11.w, ), ), ) ], ), ), ], ), ), ); }, // 纵向元素间距 mainAxisSpacing: 10, // 横向元素间距 crossAxisSpacing: 10, //本身不滚动,让外面的singlescrollview来滚动 physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, //收缩,让元素宽度自适应 ), ); } @override void dispose() { _scrollViewController.dispose(); super.dispose(); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!