我在Flutter应用程式中遇到的情况比较复杂。我有一个可滑动的PageView主屏幕,其中显示3个子Widget:日历,消息,个人资料。
目前,我的问题是日历小部件。它是从initState()方法中动态填充的。
initState()
我设法解决了第一个问题,该问题是从一页滑动到另一页导致每次重新构建Calendar Widget的原因。
现在的问题是,当我点击“日历”列表中的某个项目时,我会打开详细视图。然后,当我关闭它时…一切仍然正常。但是,当我再次滑动时,将再次调用initState()方法,并重新构建List视图。我想防止这种情况并保留它的状态。有什么建议 ?
这是本地代码。
class HomeStack extends StatefulWidget { final pages = <HomePages> [ CalendarScreen(), MessagesScreen(), ProfileScreen(), ]; @override _HomeStackState createState() => _HomeStackState(); } class _HomeStackState extends State<HomeStack> with AutomaticKeepAliveClientMixin<HomeStack> { User user; @override bool get wantKeepAlive{ return true; } @override void initState() { print("Init home"); _getUser(); super.initState(); } void _getUser() async { User _user = await HomeBloc.getUserProfile(); setState(() { user = _user; }); } final PageController _pageController = PageController(); int _selectedIndex = 0; void _onPageChanged(int index) { _selectedIndex = index; } void _navigationTapped(int index) { _pageController.animateToPage( index, duration: const Duration(milliseconds: 300), curve: Curves.ease ); } GestureDetector _navBarItem({int pageIndex, IconData iconName, String title}) { return GestureDetector( child: HomeAppBarTitleItem( index: pageIndex, icon: iconName, title: title, controller: _pageController ), onTap: () => _navigationTapped(pageIndex), ); } Widget _buildWidget() { if (user == null) { return Center( child: ProgressHud(imageSize: 70.0, progressSize: 70.0, strokeWidth: 5.0), ); } else { return Scaffold( appBar: AppBar( title: Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ _navBarItem( pageIndex: 0, iconName: Icons.calendar_today, title: AppLocalizations.of(context).calendarViewTitle, ), _navBarItem( pageIndex: 1, iconName: Icons.message, title: AppLocalizations.of(context).messagesViewTitle, ), _navBarItem( pageIndex: 2, iconName: Icons.face, title: AppLocalizations.of(context).profileViewTitle, ), ], ), backgroundColor: Colors.transparent, elevation: 0.0, ), backgroundColor: Colors.transparent, body: PageView( onPageChanged: (index) => _onPageChanged(index), controller: _pageController, children: widget.pages, ), floatingActionButton: widget.pages.elementAt(_selectedIndex).fabButton, ); } } @override Widget build(BuildContext context) { return WillPopScope( child: Stack( children: <Widget>[ BackgroundGradient(), _buildWidget(), ], ), onWillPop: () async { return true; }, ); } }
和日历代码。
class CalendarScreen extends StatelessWidget implements HomePages { /// TODO: Prevent reloading /// when : /// 1) push detail view /// 2) swipe pageView /// 3) come back to calendar it reloads static const String routeName = "/calendar"; static Color borderColor(EventPresence status) { switch (status) { case EventPresence.present: return CompanyColors.grass; case EventPresence.absent: return CompanyColors.asher; case EventPresence.pending: return CompanyColors.asher; default: return CompanyColors.asher; } } final FloatingActionButton fabButton = FloatingActionButton( onPressed: () {}, /// TODO: Add action to action button backgroundColor: CompanyColors.sky, foregroundColor: CompanyColors.snow, child: Icon(Icons.add), ); @override Widget build(BuildContext context) { return CalendarProvider( child: CalendarList(), ); } } class CalendarList extends StatefulWidget { @override _CalendarListState createState() => _CalendarListState(); } class _CalendarListState extends State<CalendarList> with AutomaticKeepAliveClientMixin<CalendarList> { Events events; void _getEvents() async { Events _events = await CalendarBloc.getAllEvents(); setState(() { events = _events; }); } @override void initState() { _getEvents(); super.initState(); } @override bool get wantKeepAlive{ return true; } Widget _displayBody() { if (events == null) { return ProgressHud(imageSize: 30.0, progressSize: 40.0, strokeWidth: 3.0); } else if(events.future.length == 0 && events.past.length == 0) return _emptyStateView(); return EventsListView(events: events); } @override Widget build(BuildContext context) { return _displayBody(); } Widget _emptyStateView() { return Center( child: Text("No data"), ); } } class EventsListView extends StatefulWidget { final Events events; EventsListView({this.events}); @override _EventsListViewState createState() => _EventsListViewState(); } class _EventsListViewState extends State<EventsListView> { GlobalKey _pastEventsScrollViewKey = GlobalKey(); GlobalKey _scrollViewKey = GlobalKey(); double _opacity = 0.0; void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { RenderSliverList renderSliver = _pastEventsScrollViewKey.currentContext.findRenderObject(); setState(() { CustomScrollView scrollView = _scrollViewKey.currentContext.widget; scrollView.controller.jumpTo(renderSliver.geometry.scrollExtent); _opacity = 1.0; }); }); } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(top: 8.0), child: AnimatedOpacity( opacity: _opacity, duration: Duration(milliseconds: 300), child: CustomScrollView( key: _scrollViewKey, controller: ScrollController( //initialScrollOffset: initialScrollOffset, keepScrollOffset: true, ), slivers: <Widget>[ SliverList( key: _pastEventsScrollViewKey, delegate: SliverChildBuilderDelegate( (context, index) { Event event = widget.events.past[index]; switch (event.type) { case EventType.competition: return CompetitionListItem(event: event); case EventType.training: return TrainingListItem(event: event); case EventType.event: return EventListItem(event: event); } }, childCount: widget.events.past.length, ), ), SliverList( delegate: SliverChildBuilderDelegate( (context, index) { return Padding( padding: EdgeInsets.only(top: 32.0, left: 16.0, right: 16.0, bottom: 16.0), child: Text( DateFormat.MMMMEEEEd().format(DateTime.now()), style: Theme.of(context).textTheme.body2.copyWith( color: CompanyColors.snow, ), ), ); }, childCount: 1, ), ), SliverList( delegate: SliverChildBuilderDelegate( (context, index) { Event event = widget.events.future[index]; switch (event.type) { case EventType.competition: return CompetitionListItem(event: event); case EventType.training: return TrainingListItem(event: event); case EventType.event: return EventListItem(event: event); } }, childCount: widget.events.future.length, ), ), ], ), ), ); } }
从AutomaticKeepAliveClientMixin的文档中:
///为[AutomaticKeepAlive]的客户提供了具有便捷方法的混合。与[State]子类一起使用。 ///子类必须实现[wantKeepAlive],并且必须调用其[build]方法super.build(返回值将始终返回null,应将其忽略)。
///为[AutomaticKeepAlive]的客户提供了具有便捷方法的混合。与[State]子类一起使用。
///子类必须实现[wantKeepAlive],并且必须调用其[build]方法super.build(返回值将始终返回null,应将其忽略)。
super.build
因此,在您的代码中,在返回脚手架之前,只需调用super.build:
Widget build(BuildContext context) { super.build(context); return Scaffold(...); }