[英]How to avoid Flutter FutureBuilder with UniqueKey flickering when SetState() is called?
I have a PageView
(parent PageView) and each of its pages is a StatefulWidget
that returns FutureBuilder
.我有一个
PageView
(父 PageView),它的每个页面都是一个返回FutureBuilder
的StatefulWidget
。 The FutureBuilder
itself will return a PageView
(child PageView), too. FutureBuilder
本身也会返回一个PageView
(子 PageView)。 Because I want both parent and child PageView
to keep page, so both parent and child widget are implemented with AutomaticKeepAliveClientMixin
.因为我希望父级和子
PageView
都保留页面,所以父级和子级小部件都使用AutomaticKeepAliveClientMixin
实现。
Each page is assigned a UniqueKey
because the pages are dynamic, meaning users can delete some pages or add pages.每个页面都分配了一个
UniqueKey
,因为页面是动态的,这意味着用户可以删除某些页面或添加页面。 However when SetState()
is called, there're two problems: 1 the whole page flickers;但是在调用
SetState()
时,有两个问题: 1 整个页面闪烁; 2 the child PageView
jumps back to page at index 0. 2 子
PageView
跳回到索引 0 处的页面。
If I don't use UniqueKey
, these two issues disappear.如果我不使用
UniqueKey
,这两个问题就会消失。 But then after adding or deleting pages, you can't refresh the pages.但是添加或删除页面后,您无法刷新页面。
Any advice are appreciated, thanks!任何建议表示赞赏,谢谢!
Codes that shows the Flickering:显示闪烁的代码:
void main() async {
runApp(
MaterialApp(
title: 'Test',
home: Scaffold(
body: Bar(),
),
),
);
}
class Bar extends StatefulWidget {
@override
State<StatefulWidget> createState() => _BarState();
}
class _BarState extends State<Bar> {
List<Widget> pages;
final controller = PageController(initialPage: 0, keepPage: true);
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
pages = [
Center(child: PageWithFutureBuilder(key: UniqueKey())),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
PageWithFutureBuilder(key: UniqueKey()),
RaisedButton(
onPressed: () {
refresh();
},
child: new Icon(
Icons.refresh,
color: Colors.blue,
size: 30.0,
),
)
],
),
];
return PageView(
controller: controller,
children: pages,
);
}
void refresh() async {
setState(() {});
}
}
class PageWithFutureBuilder extends StatefulWidget {
PageWithFutureBuilder({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => _PageWithFutureBuilderState();
}
Future test() async {
return;
}
class _PageWithFutureBuilderState extends State<PageWithFutureBuilder> {
Future future;
@override
void initState() {
future = test();
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: future,
builder: (ocntext, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Container(
color: Colors.black,
child: Center(child: CircularProgressIndicator()),
);
else if (snapshot.connectionState == ConnectionState.done) {
return Center(child: Text('test text'));
} else
return Container();
},
);
}
}
Swipe to the 2nd page, then click on the button, you'll see the flickering.滑动到第二页,然后单击按钮,您会看到闪烁。 As to the codes of
jumping back to page at index 0
, they're too complex to put here, and it's probably the same reason with the flickering.至于
jumping back to page at index 0
的代码,太复杂了,就不放了,估计和闪烁的原因是一样的。
I think I've found the right solution.我想我找到了正确的解决方案。 Basically it's caused by using a wrong
Key
.基本上是用错了
Key
造成的。 Using a UniqueKey
makes Flutter regarding the child widget as different so it re-initialized new child widget every time it rebuilds.使用
UniqueKey
使 Flutter 将子小部件视为不同,因此每次重建时它都会重新初始化新的子小部件。 Hence the flickering and jumping back to page at index 0.因此闪烁并跳回索引 0 处的页面。
Instead of using a UniqueKey
, use a value key.不要使用
UniqueKey
,而是使用值键。 In my case each of my child parent has a unique object ID
, so I use Key(objectID)
as the key.在我的例子中,我的每个孩子父母都有一个唯一的
object ID
,所以我使用Key(objectID)
作为键。 So when SetState()
get called, flutter will know some widgets can be reused since they have the same key, so the flickering disappears and it won't jump back to page at index 0.因此,当调用
SetState()
时,flutter 将知道某些小部件可以重复使用,因为它们具有相同的键,因此闪烁消失并且它不会跳回到索引 0 处的页面。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.