我一直在研究SliverAppBar,CustomScrollView,NestedScrollView,SliverPersistentHeader等。我找不到一种方法来构建类似Instagram用户个人资料屏幕标题的内容,其中仅固定了选项卡栏。屏幕的主体是TabBarView,每个窗格都有一个可滚动的列表。
使用SliverAppBar,可以很容易地在底部参数中添加TabBar。但我想在TabBar上方增加一个未知高度/可变高度的小部件。滚动页面时,多余的窗口小部件应该滚动开,然后TabBar固定在屏幕顶部。
我所能管理的只是标签栏和固定标签栏之前的固定内容。我无法使标题向上滚动并将粘贴TabBar在的正下方AppBar。
TabBar
AppBar
import 'package:flutter/material.dart'; void main() { runApp(MaterialApp(home: MyApp())); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return DefaultTabController( length: 2, child: Scaffold( appBar: AppBar( title: Text("pabloaleko"), ), body: CustomScrollView( physics: const BouncingScrollPhysics(), slivers: <Widget>[ SliverToBoxAdapter( child: SafeArea( child: Text("an unknown\namount of content\n goes here in the header"), ), ), SliverToBoxAdapter( child: TabBar( tabs: [ Tab(child: Text('Days', style: TextStyle(color: Colors.black))), Tab(child: Text('Months', style: TextStyle(color: Colors.black))), ], ), ), SliverFillRemaining( child: TabBarView( children: [ ListView( children: <Widget>[ ListTile(title: Text('Sunday 1')), ListTile(title: Text('Monday 2')), ListTile(title: Text('Tuesday 3')), ListTile(title: Text('Wednesday 4')), ListTile(title: Text('Thursday 5')), ListTile(title: Text('Friday 6')), ListTile(title: Text('Saturday 7')), ListTile(title: Text('Sunday 8')), ListTile(title: Text('Monday 9')), ListTile(title: Text('Tuesday 10')), ListTile(title: Text('Wednesday 11')), ListTile(title: Text('Thursday 12')), ListTile(title: Text('Friday 13')), ListTile(title: Text('Saturday 14')), ], ), ListView( children: <Widget>[ ListTile(title: Text('January')), ListTile(title: Text('February')), ListTile(title: Text('March')), ListTile(title: Text('April')), ListTile(title: Text('May')), ListTile(title: Text('June')), ListTile(title: Text('July')), ListTile(title: Text('August')), ListTile(title: Text('September')), ListTile(title: Text('October')), ListTile(title: Text('November')), ListTile(title: Text('December')), ], ), ], ), ), ], ), ), ); } }
您可以使用NestedScrollViewwith 实现此行为Scaffold。
NestedScrollView
Scaffold
由于我们需要在AppBar和之间的小部件TabBar进行动态构建并滚动直到TabBar到达AppBar,因此请使用的appBar属性Scaffold来构建您的文档,AppBar并用于headerSliverBuilder构建其他高度未知的小部件。使用bodyof 的属性NestedScrollView来构建选项卡视图。
appBar
headerSliverBuilder
body
这样,的元素headerSliverBuilder就会滚动直到body到达底部AppBar。
仅凭文字可能会使您感到有些困惑,这是给您的一个例子。
码:
// InstaProfilePage class InstaProfilePage extends StatefulWidget { @override _InstaProfilePageState createState() => _InstaProfilePageState(); } class _InstaProfilePageState extends State<InstaProfilePage> { double get randHeight => Random().nextInt(100).toDouble(); List<Widget> _randomChildren; // Children with random heights - You can build your widgets of unknown heights here // I'm just passing the context in case if any widgets built here needs access to context based data like Theme or MediaQuery List<Widget> _randomHeightWidgets(BuildContext context) { _randomChildren ??= List.generate(3, (index) { final height = randHeight.clamp( 50.0, MediaQuery.of(context).size.width, // simply using MediaQuery to demonstrate usage of context ); return Container( color: Colors.primaries[index], height: height, child: Text('Random Height Child ${index + 1}'), ); }); return _randomChildren; } @override Widget build(BuildContext context) { return Scaffold( // Persistent AppBar that never scrolls appBar: AppBar( title: Text('AppBar'), elevation: 0.0, ), body: DefaultTabController( length: 2, child: NestedScrollView( // allows you to build a list of elements that would be scrolled away till the body reached the top headerSliverBuilder: (context, _) { return [ SliverList( delegate: SliverChildListDelegate( _randomHeightWidgets(context), ), ), ]; }, // You tab view goes here body: Column( children: <Widget>[ TabBar( tabs: [ Tab(text: 'A'), Tab(text: 'B'), ], ), Expanded( child: TabBarView( children: [ GridView.count( padding: EdgeInsets.zero, crossAxisCount: 3, children: Colors.primaries.map((color) { return Container(color: color, height: 150.0); }).toList(), ), ListView( padding: EdgeInsets.zero, children: Colors.primaries.map((color) { return Container(color: color, height: 150.0); }).toList(), ) ], ), ), ], ), ), ), ); } }
输出:
希望这可以帮助!