【问题标题】:Finding Sum of 'length's of 'text's in TextSpans in Flutter在 Flutter 的 TextSpan 中查找“文本”的“长度”总和
【发布时间】:2021-06-22 12:25:38
【问题描述】:

信息

我需要将打字动画应用于我使用 Flutter 构建的网站上的文本。我已经成功实现了这个动画。对于要应用的动画,必须知道要写入屏幕并作为参数的文本的“长度”和“样式”属性的值。这是我写的小部件:

// @dart=2.9
import 'package:flutter/material.dart';

// ignore: must_be_immutable
class TypeWriterAnimatedText extends StatefulWidget {
  TextSpan textSpan;
  TypeWriterAnimatedText({Key key, @required this.textSpan}) : super(key: key);

  @override
  _TypeWriterAnimatedTextState createState() => _TypeWriterAnimatedTextState();
}

class _TypeWriterAnimatedTextState extends State<TypeWriterAnimatedText> with TickerProviderStateMixin {
  Animation<double> _textBlinkCursorAnimation;
  Animation<double> _textBlinkCursorAnimationCurve;
  AnimationController _textBlinkCursorAnimationController;
  
  bool _blink = true;


  @override
  void initState() {
    super.initState();
    _textBlinkCursorAnimationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 200));
    _textBlinkCursorAnimationCurve = CurvedAnimation(
        parent: _textBlinkCursorAnimationController,
        curve: Curves.easeInOutQuart,
        reverseCurve: Curves.linear);
    _textBlinkCursorAnimation = Tween<double>(begin: 0, end: 1)
        .animate(_textBlinkCursorAnimationCurve)
      ..addListener(() {
        setState(() {});
      })
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed && _blink == true) {
          _textBlinkCursorAnimationController.reverse();
        } else if (status == AnimationStatus.dismissed && _blink == true) {
          _textBlinkCursorAnimationController.forward();
        }
      });
    _textBlinkCursorAnimationController.forward();

  }
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      child: TweenAnimationBuilder<int>(
        tween: IntTween(begin: 0, end: widget.textSpan.text.length),
        builder: (BuildContext context, int value, Widget child){
          WidgetsBinding.instance.addPostFrameCallback((_){
            if(value == widget.textSpan.text.length){
              Future.delayed(Duration(milliseconds: 1800)).then((value){
                setState(() {
                  _blink = false;
                  _textBlinkCursorAnimationController.reset();
                });
              });
            }
          });
          return SelectableText.rich(
            TextSpan(
                children: [
                  widget.textSpan,
                  TextSpan(
                    text: _blink == false ? '' : '_',
                    style: widget.textSpan.style.copyWith(color: widget.textSpan.style.color.withOpacity(_textBlinkCursorAnimation.value)),
                  ),
                ]),
          );
        },
        duration: Duration(seconds: 2),
      ),
    );
  }
}


问题

但是我编写的应用动画的小部件需要在构造函数中将 TextSpan 作为参数。在这里,我遇到了一个问题。 TextSpan 处于嵌套结构中。另一方面,我需要在作为参数的 TextSpan 中找到所有“文本”属性的“长度”总和,以及最后一个 TextSpan 的“文本”属性的“样式”。但是由于 TextSpan 是嵌套的,因此其中一些对于“长度”和“样式”getter(widget.textSpan.text.lengthwidget.textSpan.style)返回 null。这导致我收到错误消息。

我想做什么?

即使我作为 TextSpan 提供给 Widget 的数据包含嵌套的 TextSpan,我也需要访问所有“文本”的“长度”属性并找到它的总和。例如,我需要找到'Text1-1','Text1-2'和'Text2'字符串的长度之和,即使有这样的数据:

TextSpan(
    children: [
        TextSpan(
          children: [
        TextSpan(
          text: 'Text1-1',
          style: TextStyle(
              fontSize: 40,
              fontFamily: 'RobotoMono-Bold',
              color: Colors.white),
            ),
        TextSpan(
          text: 'Text1-2',
          style: TextStyle(
              fontSize: 16,
              fontFamily: 'RobotoMono-Bold',
              color: Colors.white),
            ),
          ],
          style: TextStyle(
              fontSize: 40,
              fontFamily: 'RobotoMono-Bold',
              color: Colors.white),
            ),
        TextSpan(
          text: 'Text2',
          style: TextStyle(
              fontSize: 16,
              fontFamily: 'RobotoMono-Bold',
              color: Colors.white),
            ),
          ],
        ),

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    如果有嵌套的TextSpan,可以调用toPlainText将全文渲染成String

    final span = TextSpan(
      children: [
        TextSpan(text: 'hello'),
        TextSpan(text: 'world'),
      ],
    );
    span.toPlainText()  // returns 'helloworld'
    

    然后你可以在那个String上拨打length

    int totalLength(TextSpan span) => span.toPlainText().length;
    

    对于样式,您可以使用 Flutter 广泛使用的访问者模式。您可以调用textSpan.visitChildren(visitor) 来遍历整个树并递归地“访问”每个孩子。

    例如,如果您想获取树中的最后一个样式,您可以使用:

    TextStyle finalStyle(TextSpan span) {
    
      TextStyle? style;
    
      bool visit(InlineSpan span) {
        if (span.style != null) style = span.style;  // if you find a style, keep a reference to it
        return true;  // continue through the tree
      }
    
      span.visitChildren(visit);
    
      return style ?? (throw AssertionError('no styles found'));
    }
    

    如果没有找到,您也可以返回 TextStyle? 而不是抛出,这取决于您的用例。

    【讨论】:

    • 感谢您的回答! toPlainText() 有效,但 finalStyle() 函数返回第一个 TestSpan 样式。我努力了。你建议我怎么做?我猜visitChildren 只访问儿童。它不会访问树中同一级别的项目。我需要的是,如果有一个相同级别的元素,它也会访问它。所以它应该遍历 TextSpan 中的整个 children[] 列表。有没有像 visitParent 这样的结构?
    猜你喜欢
    • 2020-01-01
    • 1970-01-01
    • 2011-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 2018-12-16
    相关资源
    最近更新 更多