You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter循环生成TextSpan时重复最后句子的问题求助

Flutter嵌套TextSpan重复显示最后一句的问题解决

问题描述

我是Flutter新手,想要开发一款语言学习APP,实现文本中每个单词可点击并高亮,同时包含该单词的句子也能以不同样式高亮。采用嵌套TextSpan设置样式时,遇到了生成内容全部为文本最后一个句子的问题。

预期结果应该是“句子一 句子二 … 最后一句”,但实际结果却是“最后一句 最后一句 … 最后一句”。推测问题出在将listOfWords添加到listOfTextSpans时,存储的是指向listOfWords的引用而非内容副本,导致每次循环更新内容时所有元素随之改变。

问题代码

List<TextSpan> TextSpanSentences(List sentences) {
    List<Sentence> listOfSentences = [];
    List<TextSpan> listOfWords = [];
    List<TextSpan> listOfTextSpans = [];

    for (String sentence in sentences) {
      listOfSentences.add(Sentence(sentence: sentence));
    }

    for (Sentence sentence in listOfSentences) {
      listOfWords.clear();

      for (String word in sentence.words) {
        listOfWords.add(
          TextSpan(
            text: '$word ',
            style: TextStyle(color: Colors.black, fontSize: 20, height: 1.8),
            recognizer: wordTapRecognizer(word),
          ),
        );
      }
      listOfTextSpans.add(TextSpan(
        children: listOfWords,
      ));
    }
    return listOfTextSpans;
  }

(Sentence是一个存储完整句子及其拆分后单词的简单类)

解决方案

你的推测完全正确——Dart中列表属于引用类型,listOfWords.clear()只是清空原有列表的内容,而非创建新的列表实例。这导致所有添加到listOfTextSpans的TextSpan,其children属性都指向同一个listOfWords列表,最终所有元素都会显示最后一次循环的内容。

修改核心是避免复用同一个列表实例,每次循环时创建新的listOfWords即可:

修正后的代码

List<TextSpan> TextSpanSentences(List sentences) {
    List<Sentence> listOfSentences = [];
    List<TextSpan> listOfTextSpans = [];

    for (String sentence in sentences) {
      listOfSentences.add(Sentence(sentence: sentence));
    }

    for (Sentence sentence in listOfSentences) {
      // 每次循环创建新的列表实例,不再复用旧列表
      List<TextSpan> listOfWords = [];

      for (String word in sentence.words) {
        listOfWords.add(
          TextSpan(
            text: '$word ',
            style: TextStyle(color: Colors.black, fontSize: 20, height: 1.8),
            recognizer: wordTapRecognizer(word),
          ),
        );
      }
      listOfTextSpans.add(TextSpan(
        children: listOfWords,
      ));
    }
    return listOfTextSpans;
  }

简化版代码

可以去掉中间的listOfSentences变量,直接遍历原句子列表,让代码更简洁:

List<TextSpan> TextSpanSentences(List<String> sentences) {
    final listOfTextSpans = <TextSpan>[];

    for (final sentenceStr in sentences) {
      final sentence = Sentence(sentence: sentenceStr);
      final listOfWords = <TextSpan>[];

      for (final word in sentence.words) {
        listOfWords.add(
          TextSpan(
            text: '$word ',
            style: const TextStyle(color: Colors.black, fontSize: 20, height: 1.8),
            recognizer: wordTapRecognizer(word),
          ),
        );
      }
      listOfTextSpans.add(TextSpan(children: listOfWords));
    }
    return listOfTextSpans;
  }

这样每个TextSpan的children都会指向独立的列表实例,不会互相干扰,就能正确显示每一句的内容了。

内容的提问来源于stack exchange,提问作者biodegradablePotatoChip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:36:30