想在Flutter中克隆Playstore的首页应用栏滚动功能。 Playstore Appbar我正在尝试制作一个屏幕,其中包含SliverAppBar bottom属性下的静态Tabs。每当我单击任何父静态选项卡时,都需要创建动态选项卡和TabBarViews。我成功完成了,但是遇到了一些问题。
这是我的屏幕代码。
class DynamicTabContent {
IconData icon;
String tooTip;
DynamicTabContent.name(this.icon, this.tooTip);
}
int currentTabBlue = 0;
class TestAppHomePage extends StatefulWidget {
@override
TestAppHomePageState createState() => new TestAppHomePageState();
}
class TestAppHomePageState extends State<TestAppHomePage>
with TickerProviderStateMixin {
List<DynamicTabContent> myList = new List();
ScrollController _scrollController = new ScrollController();
TabController _tabControllerBlue;
TabController _tabController;
handleTabChange() {
currentTabBlue = _tabControllerBlue.index;
print("CurrentTab = " + currentTabBlue.toString());
if (_tabControllerBlue.index == 0) {
setState(() {
myList.clear();
myList.add(new DynamicTabContent.name(Icons.favorite, "Favorited"));
myList
.add(new DynamicTabContent.name(Icons.local_pizza, "local pizza"));
this._tabController = new TabController(initialIndex: 0, length: 15, vsync: this);
});
} else if (_tabControllerBlue.index == 1) {
setState(() {
myList.clear();
myList.add(new DynamicTabContent.name(Icons.favorite, "Favorited"));
myList
.add(new DynamicTabContent.name(Icons.local_pizza, "local pizza"));
myList
.add(new DynamicTabContent.name(Icons.local_pizza, "local pizza"));
this._tabController = new TabController(initialIndex: 0, length: 15, vsync: this);
});
} else if (_tabControllerBlue.index == 2) {
setState(() {
myList.clear();
myList.add(new DynamicTabContent.name(Icons.favorite, "Favorited"));
myList.add(new DynamicTabContent.name(Icons.favorite, "Favorited"));
myList
.add(new DynamicTabContent.name(Icons.local_pizza, "local pizza"));
myList
.add(new DynamicTabContent.name(Icons.local_pizza, "local pizza"));
myList
.add(new DynamicTabContent.name(Icons.local_pizza, "local pizza"));
this._tabController = new TabController(initialIndex: 0, length: 15, vsync: this);
});
}
}
@override
void initState() {
print("initState = TestAppHomePage");
myList.add(new DynamicTabContent.name(Icons.favorite, "Favorited"));
myList.add(new DynamicTabContent.name(Icons.local_pizza, "local pizza"));
_tabControllerBlue =
new TabController(initialIndex: 0, length: 3, vsync: this);
_tabControllerBlue.addListener(handleTabChange);
_tabController =
new TabController(initialIndex: 0, length: myList.length, vsync: this);
}
@override
void dispose() {
print("dispose");
// _tabController.removeListener(handleTabChange);
// _tabController.dispose();
super.dispose();
}
Future<void> executeAfterBuild() async {
print("Build: Called Back");
}
@override
Widget build(BuildContext context) {
executeAfterBuild();
return new Scaffold(
body: new NestedScrollView(
controller: _scrollController,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: null,
),
title: Text('Kitchen'),
floating: true,
pinned: true,
bottom: TabBar(
controller: _tabControllerBlue,
tabs: [
Tab(icon: Icon(Icons.lightbulb_outline), text: "Tab 1"),
Tab(icon: Icon(Icons.lightbulb_outline), text: "Tab 2"),
Tab(icon: Icon(Icons.lightbulb_outline), text: "Tab 3"),
],
),
),
new SliverPersistentHeader(
pinned: true,
delegate: TestTabBarDelegate(controller: _tabController),
),
];
},
body: new TestHomePageBody(
tabController: _tabController,
scrollController: _scrollController,
myList: myList,
),
),
);
}
}
class TestHomePageBody extends StatefulWidget {
TestHomePageBody({this.tabController, this.scrollController, this.myList});
final TabController tabController;
final ScrollController scrollController;
final List<DynamicTabContent> myList;
State<StatefulWidget> createState() {
return TestHomePageBodyState();
}
}
class TestHomePageBodyState extends State<TestHomePageBody> {
Key _key = new PageStorageKey({});
bool _innerListIsScrolled = false;
void _updateScrollPosition() {
if (!_innerListIsScrolled &&
widget.scrollController.position.extentAfter == 0.0) {
setState(() {
_innerListIsScrolled = true;
print("_innerListIsScrolled = true");
});
} else if (_innerListIsScrolled &&
widget.scrollController.position.extentAfter > 0.0) {
setState(() {
_innerListIsScrolled = false;
print("_innerListIsScrolled = false");
// Reset scroll positions of the TabBarView pages
_key = new PageStorageKey({});
});
}
}
@override
void initState() {
widget.scrollController.addListener(_updateScrollPosition);
print("initState = TestHomePageBodyState");
super.initState();
}
@override
void dispose() {
widget.scrollController.removeListener(_updateScrollPosition);
super.dispose();
}
@override
Widget build(BuildContext context) {
return new TabBarView(
controller: widget.tabController,
key: _key,
children: widget.myList.isEmpty
? <Widget>[]
: widget.myList.map(
(dynamicContent) {
return new Card(
child: new Column(
children: <Widget>[
new Container(
height: 450.0,
width: 300.0,
child: new IconButton(
icon: new Icon(dynamicContent.icon, size: 100.0),
tooltip: dynamicContent.tooTip,
onPressed: null,
),
),
Text(dynamicContent.tooTip),
],
),
);
},
).toList(),
);
}
}
class TestTabBarDelegate extends SliverPersistentHeaderDelegate {
TestTabBarDelegate({this.controller});
final TabController controller;
@override
double get minExtent => kToolbarHeight;
@override
double get maxExtent => kToolbarHeight;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return new Container(
color: Theme.of(context).cardColor,
height: kToolbarHeight,
child: new TabBar(
controller: controller,
isScrollable: true,
labelColor: Theme.of(context).accentColor,
indicatorSize: TabBarIndicatorSize.label,
key: new PageStorageKey<Type>(TabBar),
indicatorColor: Theme.of(context).accentColor,
tabs: List<Widget>.generate(controller.length, (int index) {
print(controller.length);
return new Tab(text: "Excluded Discounted Deals");
}),
),
);
}
@override
bool shouldRebuild(covariant TestTabBarDelegate oldDelegate) {
return oldDelegate.controller != controller;
}
}
答案 0 :(得分:0)
一种解决方法是使用 PageStorage 。例如。
在onTap
方法中,您需要编写状态,而在构建窗口小部件时,您需要读取状态,如下所示:
// Reading state:
var tabInternalIndex = PageStorage.of(context).readState(context, identifier: ValueKey('tab3'));
_currentTab = tabInternalIndex == null ? _currentTab : tabInternalIndex;
// Writing State
onTap: (int index) {
setState(() {
_currentTab = index;
PageStorage.of(context).writeState(context, index,
identifier: ValueKey('tab3'));
});
}
请注意,每个主标签的标识符必须不同。
完整示例:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
initialIndex: 1,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.mail)),
Tab(icon: Icon(Icons.contacts)),
Tab(icon: Icon(Icons.info)),
],
),
title: Text('Sample tabs'),
),
body: TabBarView(children: <Widget>[
SubTabs1(),
SubTabs2(),
SubTabs3()
]),
),
);
}
}
class SubTabs1 extends StatefulWidget {
@override
_SubTabs1State createState() => _SubTabs1State();
}
class _SubTabs1State extends State<SubTabs1> {
int _currentTab = 0;
@override
Widget build(BuildContext context) {
var tabInternalIndex = PageStorage.of(context)
.readState(context, identifier: ValueKey('tab1'));
_currentTab = tabInternalIndex == null ? _currentTab : tabInternalIndex;
return DefaultTabController(
initialIndex: _currentTab,
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
onTap: (int index) {
setState(() {
_currentTab = index;
PageStorage.of(context).writeState(context, index,
identifier: ValueKey('tab1'));
});
},
tabs: [
Tab(icon: Icon(Icons.delete)),
Tab(icon: Icon(Icons.delete_forever)),
Tab(icon: Icon(Icons.delete_outline)),
],
),
),
body: TabBarView(
children: <Widget>[
Container(
color: Colors.green[100],
child: Text('Child 5'),
),
Container(
color: Colors.green[300],
child: Text('Child 6'),
),
Container(
color: Colors.green[600],
child: Text('Child 7'),
)
],
)));
}
}
class SubTabs2 extends StatefulWidget {
@override
_SubTabs2State createState() => _SubTabs2State();
}
class _SubTabs2State extends State<SubTabs2> {
int _currentTab = 0;
@override
Widget build(BuildContext context) {
var tabInternalIndex = PageStorage.of(context)
.readState(context, identifier: ValueKey('tab2'));
_currentTab = tabInternalIndex == null ? _currentTab : tabInternalIndex;
return DefaultTabController(
initialIndex: _currentTab,
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
onTap: (int index) {
setState(() {
_currentTab = index;
PageStorage.of(context).writeState(context, index,
identifier: ValueKey('tab2'));
});
},
tabs: [
Tab(icon: Icon(Icons.alarm_add)),
Tab(icon: Icon(Icons.alarm_off)),
Tab(icon: Icon(Icons.alarm_on)),
],
),
),
body: TabBarView(
children: <Widget>[
Container(
color: Colors.yellow[100],
child: Text('Child 5'),
),
Container(
color: Colors.yellow[300],
child: Text('Child 6'),
),
Container(
color: Colors.yellow[600],
child: Text('Child 7'),
)
],
)));
}
}
class SubTabs3 extends StatefulWidget {
@override
_SubTabs3State createState() => _SubTabs3State();
}
class _SubTabs3State extends State<SubTabs3> {
int _currentTab = 0;
@override
Widget build(BuildContext context) {
// Reading state:
var tabInternalIndex = PageStorage.of(context).readState(context, identifier: ValueKey('tab3'));
_currentTab = tabInternalIndex == null ? _currentTab : tabInternalIndex;
return DefaultTabController(
initialIndex: _currentTab,
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
onTap: (int index) {
setState(() {
_currentTab = index;
PageStorage.of(context).writeState(context, index,
identifier: ValueKey('tab3'));
});
},
tabs: [
Tab(icon: Icon(Icons.ac_unit)),
Tab(icon: Icon(Icons.accessible)),
Tab(icon: Icon(Icons.airport_shuttle)),
],
),
),
body: TabBarView(
children: <Widget>[
Container(
color: Colors.pink[100],
child: Text('Child 1'),
),
Container(
color: Colors.pink[300],
child: Text('Child 2'),
),
Container(
color: Colors.pink[600],
child: Text('Child 3'),
)
],
)));
}
}
希望获得帮助。