我使用SliverAppBar
,SliverPersistentHeader
,TabView
和ListView
创建了一个屏幕。
如果我在tab1中向下滚动,tab2会自动向下滚动。所以如果我切换到tab2,列表不是从第一项开始。我怎么能阻止这个?
我创建了简单的演示应用程序来演示问题,你可以看看这个gist。
这个问题背后的原因是两个选项卡都使用相同的TabController
,在你的情况下DefaultTabController
,它是impilictly定义子窗口小部件的选项卡控制器,你必须为每个选项卡明确设置一个单独的TabController
,所以它的行为是独立的另一个,但你将额外的代码来管理你的新控制器:
这是一个例子:
在你的nestedScrollView
里面
child: nestedScrollView(
controller: // add a `ScrollController` here
),
尝试将TabBarView
包裹在StatefulWidget
内的独立脚手架中。这样,您可以确保每次更改选项卡时都重建选项卡主体,以便不会保留滚动位置。
例:
return Scaffold(
body: DefaultTabController(
length: 2,
child: NestedScrollView(
headerSliverBuilder: /* Your headerSliverBuilder code */
body: MyCustomTabWidget(),
)
);
class MyCustomTabWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return MyCustomTabWidgetState();
}
}
class MyCustomTabWidgetState extends State<MyCustomTabWidget > {
@override
Widget build(BuildContext context) {
return Scaffold(
body: new TabBarView(
children: [
/*Code for both the Containers containing ListViews*/
]
)
)
}
}
我用PageStorageKey修改了你的gist。见下面的工作示例:
import 'package:flutter/material.dart';
void main() async {
runApp(new TestApp());
}
class TestApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(primarySwatch: Colors.yellow),
home: new TestAppHomePage(),
);
}
}
class TestAppHomePage extends StatefulWidget {
@override
State createState() => new TestAppHomePageState();
//FPDetailScreen({Key key, @required this.period}) : super(key: key);
}
class TestAppHomePageState extends State<TestAppHomePage>
with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return new Scaffold(
//bottomNavigationBar: bottomNavBar,
body: DefaultTabController(
length: 2,
child: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
expandedHeight: 120.0,
floating: false,
forceElevated: innerBoxIsScrolled,
backgroundColor: Colors.green,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin,
centerTitle: true,
title: Text(
"Foo Bar Baz",
style: TextStyle(color: Colors.white),
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
softWrap: true,
maxLines: 1,
),
background: Container(
alignment: Alignment.topCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Row(
children: <Widget>[
Text(
'10.00 TL',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold),
),
],
mainAxisAlignment: MainAxisAlignment.center,
),
Container(
width: 0,
height: 0,
)
],
),
),
//background: ,
),
),
SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
TabBar(
tabs: [
Tab(
child: Text(
"Tab1",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold),
),
),
Tab(
child: Text(
"Tab2",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
];
},
body:TabBarView(
//controller: _tabController,
children: [
CardList('one'),
CardList('two'),
]),
),
),
);
}
}
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate(this._tabBar);
final TabBar _tabBar;
@override
double get minExtent => _tabBar.preferredSize.height;
@override
double get maxExtent => _tabBar.preferredSize.height;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return new Container(
color: Colors.white,
child: _tabBar,
);
}
@override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return false;
}
}
class CardList extends StatelessWidget {
final String listKey;
CardList(this.listKey);
@override
Widget build(BuildContext context) {
return Container(
child: ListView.builder(
key: PageStorageKey<String>(listKey),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: 20,
//itemExtent: 1.0,
itemBuilder: (context, index){
return new ListTile(
title: new Text("Item $index"),
);
}),
);
}
}