我在 Flutter 应用程序中遇到了相当复杂的情况。我有一个主屏幕,它是一个可滑动的 PageView,显示 3 个子小部件:日历、消息、配置文件。
我目前的问题是日历小部件。它是从initState()方法动态填充的。
我设法解决了从一个页面滑动到另一个页面导致每次重建日历小部件的第一个问题。
我现在的问题是当我点击日历列表中的一个项目时,我打开了详细信息视图。然后,当我关闭它时……一切都还好。但是,当我再次滑动时,再次调用 initState() 方法并重建列表视图。我想防止这种情况并保持它的状态。有什么建议 ?
这是家庭代码。
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;
},
);
}
}
Run Code Online (Sandbox Code Playgroud)
和日历代码。
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,
),
),
],
),
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
anm*_*ail 11
从关于AutomaticKeepAliveClientMixin的文档:
/// [AutomaticKeepAlive] 客户端的带有便利方法的 mixin。与 [State] 子类一起使用。
/// 子类必须实现[wantKeepAlive],并且它们的[build]方法必须调用
super.build(返回值总是返回null,应该被忽略)。
所以在你的代码中,在你返回 Scaffold 之前调用 super.build:
Widget build(BuildContext context) {
super.build(context);
return Scaffold(...);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5095 次 |
| 最近记录: |