如何创建有界可滚动 TabBarView [英] How to create a bounded scrollable TabBarView
问题描述
我需要在 Flutter 中实现以下布局.
当用户滚动时,我希望整个布局滚动(隐藏标题和标签栏).但是,我不能将 TabBarView 嵌套在 ListView 中,因为 TabBarView 没有有界高度,而 ListViews 没有为其子项提供有界高度.
我已经看到了这些问题,但对于这个用例,所有这些问题的答案都不令人满意:
class SliverWithTabBar 扩展 StatefulWidget {@覆盖_SliverWithTabBarState createState() =>_SliverWithTabBarState();}class _SliverWithTabBarState 扩展 State
与 SingleTickerProviderStateMixin {TabController 控制器;@覆盖无效的初始化状态(){super.initState();控制器 = TabController(长度:3,vsync:这个);}@覆盖小部件构建(BuildContext 上下文){返回脚手架(正文:NestedScrollView(headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {返回 [SliverAppBar(固定:假,backgroundColor: Colors.white,弹性空间:弹性空间条(collapseMode: CollapseMode.pin,背景:列(crossAxisAlignment: CrossAxisAlignment.start,孩子们:<小部件>[容器(高度:200.0,宽度:double.infinity,颜色:Colors.grey,孩子:FlutterLogo(),),填充(填充:const EdgeInsets.all(10.0),孩子:文本('商务办公室',样式:TextStyle(字体大小:25.0),textAlign: TextAlign.left,),),填充(填充:const EdgeInsets.all(10.0),孩子:文本('现在开放 街道地址,299 城市,州',样式:TextStyle(字体大小:15.0),textAlign: TextAlign.left,),),填充(填充:const EdgeInsets.only(右:10.0),孩子:行(mainAxisAlignment: MainAxisAlignment.end,孩子们:<小部件>[图标(Icons.share),填充(填充:const EdgeInsets.only(左:10.0),孩子:图标(Icons.favorite),),],),)],),),展开高度:380.0,底部:TabBar(indicatorColor: Colors.black,labelColor: Colors.black,标签: [标签(文本:'帖子'),标签(文本:'详细信息'),标签(文本:'追随者'),],控制器:控制器,),)];},正文:ListView.builder(itemCount: 100,itemBuilder:(BuildContext 上下文,int 索引){退货卡(颜色:索引 % 2 == 0 ?Colors.blue : Colors.green,孩子:容器(对齐:Alignment.center,宽度:double.infinity,高度:100.0,孩子:文本('Flutter 很棒',样式:TextStyle(字体大小:18.0),),),);},),),);}} 您应该寻找
Sliver
小部件来实现NestedScrollView
.这为您提供了一个 headerSliverBuilder 属性,您实际上可以在其中放置一些标题,当滚动正文小部件时,这些标题可能隐藏或固定在屏幕顶部,在这个特定示例中,一个
ListView
.您可能需要查看 RenderSliver 文档.
I need to implement the following layout in Flutter.
When the user scrolls, I want the entire layout to scroll (hiding the header and tab bar). However, I can't nest a TabBarView inside a ListView since the TabBarView doesn't have a bounded height and ListViews don't provide a bounded height to their children.
I've already seen these questions, but all of them have unsatisfactory answers for this use case:
- How can I have a TabView with variable height content within a Scrollable View with Flutter? : Exactly what I needed, but the only answer doesn't provide any concrete code on how to implement this, only a reference to a feature (SliverList) that I can't figure out how to implement.
- how to implement a sliverAppBar with a tabBar : The provided code doesn't work since the SliverList doesn't accept a constructor with this shape (and I tried adapting it to use a delegate without success).
- Getting 'Horizontal viewport was given unbounded height.' with TabBarView in flutter : This use case doesn't work for me since I need the entire layout to scroll, and in that answer, the header is fixed to the top.
解决方案class SliverWithTabBar extends StatefulWidget { @override _SliverWithTabBarState createState() => _SliverWithTabBarState(); } class _SliverWithTabBarState extends State<SliverWithTabBar> with SingleTickerProviderStateMixin { TabController controller; @override void initState() { super.initState(); controller = TabController(length: 3, vsync: this); } @override Widget build(BuildContext context) { return Scaffold( body: NestedScrollView( headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ SliverAppBar( pinned: false, backgroundColor: Colors.white, flexibleSpace: FlexibleSpaceBar( collapseMode: CollapseMode.pin, background: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Container( height: 200.0, width: double.infinity, color: Colors.grey, child: FlutterLogo(), ), Padding( padding: const EdgeInsets.all(10.0), child: Text( 'Business Office', style: TextStyle(fontSize: 25.0), textAlign: TextAlign.left, ), ), Padding( padding: const EdgeInsets.all(10.0), child: Text( 'Open now Street Address, 299 City, State', style: TextStyle(fontSize: 15.0), textAlign: TextAlign.left, ), ), Padding( padding: const EdgeInsets.only(right: 10.0), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ Icon(Icons.share), Padding( padding: const EdgeInsets.only(left: 10.0), child: Icon(Icons.favorite), ), ], ), ) ], ), ), expandedHeight: 380.0, bottom: TabBar( indicatorColor: Colors.black, labelColor: Colors.black, tabs: [ Tab(text: 'POSTS'), Tab(text: 'DETAILS'), Tab(text: 'FOLLOWERS'), ], controller: controller, ), ) ]; }, body: ListView.builder( itemCount: 100, itemBuilder: (BuildContext context, int index) { return Card( color: index % 2 == 0 ? Colors.blue : Colors.green, child: Container( alignment: Alignment.center, width: double.infinity, height: 100.0, child: Text( 'Flutter is awesome', style: TextStyle(fontSize: 18.0), ), ), ); }, ), ), ); } }
You should look for
Sliver
widgets to achieveNestedScrollView
.That gives you a headerSliverBuilder property where you can actually fit some headers that you might hide or pin on the top of the screen when the body widget is scrolled, in this particular example, a
ListView
.You might want to take a look to the RenderSliver documentation.
这篇关于如何创建有界可滚动 TabBarView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!