我正在尝试使用异步接收的消息填充 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,
),
),
),
),
],
),
),
);
}
}
答案 0 :(得分:2)
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!'),
],
),
)
答案 1 :(得分:-1)
小部件没有更新,因为您没有更改实际的 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'))];
});