Flutter 全局List Widget 不刷新问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 全局List Widget 不刷新问题相关的知识,希望对你有一定的参考价值。
参考技术A 我是在StatefulWidget里面设置了一个全局的List,然后动态改变List里面的内容,然后使用setState刷新,结果发现没有用,点击一下虽然会多出一个新的Item,但是还是原来那个,就是List长度、内容不同,Widget显示的是同一个Widget。比如:九宫格添加图片,第一个是添加图片,点击添加图片把图片放到List里面,然后setState刷新,结果发现页面没变化,触碰添加图片Item,就会多出一个添加图片Item。
根据Flutter基于不可变数据的原理,我们直接把List换一个引用,创建一个新的List。
Flutter 局部Widget刷新
更新局部Widget,避免全局刷新 ,总结自己遇到和需要的情况整理如下,原理不做解释,只记录用法
1、GlobalKey
通过传递GlobalKey 获取Widget的State, 调用 setState(VoidCallback fn) 刷新Widget
注意:使用GlobalKey开销较大,如果有其他可选方案,应尽量避免使用它。另外同一个GlobalKey在整个widget树中必须是唯一的,不能重复 。
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main()
runApp(new MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: '动态更新叶子节点的Widget',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: '动态更新叶子节点的Widget'),
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key, this.title) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
int _counter = 0;
//设置key,绑定待刷新控件.
GlobalKey textKey = GlobalKey();
@override
Widget build(BuildContext context)
print('Enter _MyHomePageState.build()');
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
TextWidget(textKey),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: ()
_counter++;
//动态刷新局部widget(widget内部更新)
(textKey.currentState as TextWidgetState).onPressed(_counter);
,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
//********使用GlobalKey局部刷新*****/
class TextWidget extends StatefulWidget
//! 接收传过来的key
TextWidget(Key key) : super(key: key);
@override
State createState()
return TextWidgetState();
class TextWidgetState extends State<TextWidget>
int _counter = 0;
@override
Widget build(BuildContext context)
return Center(
child: Text(
'$_counter',
style: TextStyle(fontSize: 20, color: Colors.green),
),
);
//在TextWidget的onPressed中单独调用TextWidget的setState,刷新本控件.
void onPressed(int count)
setState(()
_counter = count;
);
2、替换Wiget,Element update(covariant Widget newWidget)
感觉类似于Android 的切换缓存的Fragment 列表来更新布局。
以下demo,创建两个TextUpdateWidget存于upWidgetPages中,counter奇偶判断切换两个TextUpdateWidget的显示。
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main()
runApp(new MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: '动态替换叶子节点的Widget',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: '动态替换叶子节点的Widget'),
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key, this.title) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
int _counter = 0;
//用于更换的组件,类似于Android fragment替换更新
TextUpdateWidget updateWidget;
//存储组件列表
List<Widget> upWidgetPages = [];
static Element findChild(Element e, Widget w)
Element child;
void visit(Element element)
if (w == element.widget)
child = element;
else
element.visitChildren(visit);
visit(e);
return child;
@override
Widget build(BuildContext context)
print('Enter _MyHomePageState.build()');
updateWidget = TextUpdateWidget(counter: _counter);
upWidgetPages.add(updateWidget);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
updateWidget,
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: ()
print('Enter floatingActionButton.onPressed()');
_counter++;
//创建widget 存于upWidgetPages 用于替换
if (_counter == 1)
TextUpdateWidget updateWidget = TextUpdateWidget(counter: _counter);
upWidgetPages.add(updateWidget);
Element e = findChild(context as Element, updateWidget);
if (e != null)
if ((_counter + 1) % 2 == 1)
updateWidget = upWidgetPages[0];
else
updateWidget = upWidgetPages[1];
e.owner.lockState(()
e.update(updateWidget);
);
,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
//*******局部替换Widget********/
class TextUpdateWidget extends StatefulWidget
int counter = 0;
TextUpdateWidget(Key key, this.counter) : super(key: key);
@override
State<StatefulWidget> createState() => TextUpdateWidgetState();
class TextUpdateWidgetState extends State<TextUpdateWidget>
@override
Widget build(BuildContext context)
return Center(
child: (widget.counter + 1) % 2 == 0
? Text('another times: $widget.counter',
style: TextStyle(fontSize: 24, color: Colors.cyan))
: Text('another times: $widget.counter',
style: TextStyle(fontSize: 28, color: Colors.amberAccent)),
);
3、Provider 状态共享,更新wiget
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
// return MultiProvider(
// providers: [
// //这里是关键注册通知吧
// ChangeNotifierProvider(create: (_) => Counter()),
// ],
// child: MaterialApp(
// title: 'Test',
// //设置主题
// theme: ThemeData(primaryColor: Colors.pink),
// home: CountPage(),
// ),
// );
return ChangeNotifierProvider(
create: (_) => Counter(),
child: MaterialApp(
title: 'Test',
theme: ThemeData(primaryColor: Colors.pink),
home: CountPage(),
),
);
class CountPage extends StatefulWidget
@override
State<StatefulWidget> createState()
// TODO: implement createState
return CountPageState();
class CountPageState extends State<CountPage>
@override
Widget build(BuildContext context)
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("你都点击$Provider.of<Counter>(context).value次了",
style: TextStyle(
color: Colors.red,
fontSize: 33.0,
)),
TextUpdateWidget()
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: ()
Provider.of<Counter>(context, listen: false)..increment();
,
tooltip: 'add',
child: Icon(Icons.add),
));
class TextUpdateWidget extends StatefulWidget
@override
State<StatefulWidget> createState() => TextUpdateWidgetState();
class TextUpdateWidgetState extends State<TextUpdateWidget>
@override
Widget build(BuildContext context)
return Center(
child: (Provider.of<Counter>(context).value + 1) % 2 == 0
? Text('another times: $Provider.of<Counter>(context).value',
style: TextStyle(fontSize: 24, color: Colors.cyan))
: Text('another times: $Provider.of<Counter>(context).value',
style: TextStyle(fontSize: 28, color: Colors.amberAccent)),
);
//混入
class Counter with ChangeNotifier
int value = 0;
increment()
value += 1;
//发送通知
notifyListeners();
以上是关于Flutter 全局List Widget 不刷新问题的主要内容,如果未能解决你的问题,请参考以下文章