【问题标题】:Flutter setState not updating RichText widgetFlutter setState 不更新 RichText 小部件
【发布时间】:2021-02-11 15:14:49
【问题描述】:

我正在尝试使用异步接收的消息填充 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 setstate richtext


    【解决方案1】:

    Flutter 不支持这种情况。 TextSpan 的children 属性的文档:

    不支持在创建 TextSpan 后修改列表,并且可能会产生意外结果。

    https://api.flutter.dev/flutter/painting/TextSpan/children.html

    简单的解决方案是在每次渲染时复制列表:

    child: RichText(
      text: TextSpan(
        children: List.from(_messages),
      ),
    ),
    

    不同的,可能更好的解决方案是为每个消息使用单独的 TextSpan(将消息映射到 TextSpan),如示例中所示:

    RichText(
      text: TextSpan(
        text: 'Hello ',
        style: DefaultTextStyle.of(context).style,
        children: <TextSpan>[
          TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),
          TextSpan(text: ' world!'),
        ],
      ),
    )
    

    【讨论】:

      【解决方案2】:

      小部件没有更新,因为您没有更改实际的 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'))];
            });
      

      【讨论】:

        猜你喜欢
        • 2020-08-18
        • 1970-01-01
        • 2018-07-28
        • 1970-01-01
        • 1970-01-01
        • 2020-12-09
        • 2021-05-01
        • 1970-01-01
        • 2021-12-14
        相关资源
        最近更新 更多