如何解决Flutter setState 不更新 RichText 小部件
我正在尝试使用异步接收的消息填充 RichText 小部件。消息存储在 TextSpan 对象列表中。在附加的示例中,我将对象从计时器添加到列表中,但 RichText 小部件未显示新消息。有人能看到我做错了什么吗?
import 'package:Flutter/material.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',theme: ThemeData(
primarySwatch: Colors.blue,),home: TstWidget(name: 'tst'),);
}
}
class TstWidget extends StatefulWidget {
final String name;
TstWidget({this.name});
@override
_TstWidgetState createState() => _TstWidgetState();
}
class _TstWidgetState extends State<TstWidget> {
Timer _timer;
int _idx = 10;
List<TextSpan> _messages = [];
@override
void initState() {
super.initState();
// Create a couple of initial messages just so see something in the RichText widget.
_messages.add(TextSpan(text: 'pre set message 1\n'));
_messages.add(TextSpan(text: 'pre set message 2\n'));
_timer = new Timer.periodic(new Duration(seconds: 1),(time) {
print('adding message $_idx');
setState(() {
_messages.add(TextSpan(text: 'this is message $_idx\n'));
});
if (--_idx == 0) {
print('timer complete');
_timer.cancel();
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.name),body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,children: [
Expanded(
child: Container(
decoration: Boxdecoration(border: Border.all(width: 1)),margin: EdgeInsets.all(4.0),padding: EdgeInsets.all(4.0),child: RichText(
text: TextSpan(
children: _messages,],);
}
}
解决方法
Flutter 不支持这种情况。 TextSpan 的 children
属性文档:
不支持在创建 TextSpan 后修改列表,可能会产生意外结果。
https://api.flutter.dev/flutter/painting/TextSpan/children.html
简单的解决方案是在每次渲染时复制列表:
child: RichText(
text: TextSpan(
children: List.from(_messages),),
不同的,可能更好的解决方案是为每个消息使用单独的 TextSpans(将消息映射到 TextSpan),如示例中所示:
RichText(
text: TextSpan(
text: 'Hello ',style: DefaultTextStyle.of(context).style,children: <TextSpan>[
TextSpan(text: 'bold',style: TextStyle(fontWeight: FontWeight.bold)),TextSpan(text: ' world!'),],)
,
小部件没有更新,因为您没有更改实际的 List
对象,而只是向现有的 List
对象添加更多项目。
还有setState
通知框架该对象的内部状态已经改变。
因此,要实际更改 _messages
对象的状态,您需要使用更新的项目创建一个新的 List
并将其分配给您的 _messages
变量,以便框架可以检测到状态发生了变化。
为此,您应该更新:
setState(() {
_messages.add(TextSpan(text: 'this is message $_idx\n'));
});
到:
setState(() {
_messages = [..._messages,TextSpan(text: 'this is message $_idx\n'))];
});
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。