【问题标题】:How get moving text in widget with given width如何在给定宽度的小部件中移动文本
【发布时间】:2019-09-07 01:27:55
【问题描述】:

我正在构建一个广播应用程序。就像在 Spotify 中一样,有一个带有当前标题和艺术家的栏,文本应该在一行中并具有给定的宽度。如何让文本从右到左再向后移动?

在使用自制动画的时候,我想有一个固定的移动文本的速度,所以我需要文本小部件的时间和宽度。

是否有执行此操作的包/内置选项? 还是我必须使用自制动画?如果是这样,我怎样才能获得文本小部件的宽度?

控制器和动画:

    AnimationController(duration: Duration(seconds: 10), vsync: this);
    animation = Tween<double>(begin: 0, end: 1)
        .animate(CurvedAnimation(parent: _controller, curve: Curves.linear));
    animation.addListener(() {
      setState(() {});
    });
    _controller.repeat();

构建方法

    double value =
        -300 * (animation.value <= 0.5 ? animation.value : 1 - animation.value);
    return Container(
      child: SizedBox(
        width: widget.width,
        height: 24,
        child: Transform.translate(
          offset: Offset(value, 0),
          child: widget.text,
        ),
      ),
    );

【问题讨论】:

    标签: text flutter flutter-layout flutter-animation


    【解决方案1】:

    你可以这样做:

    import 'dart:async';
    
    import 'package:flutter/material.dart';
    
    class ScrollingText extends StatefulWidget {
      final String text;
      final TextStyle textStyle;
      final Axis scrollAxis;
      final double ratioOfBlankToScreen;
    
      ScrollingText({
        @required this.text,
        this.textStyle,
        this.scrollAxis: Axis.horizontal,
        this.ratioOfBlankToScreen: 0.25,
      }) : assert(text != null,);
    
      @override
      State<StatefulWidget> createState() {
        return ScrollingTextState();
      }
    }
    
    class ScrollingTextState extends State<ScrollingText>
        with SingleTickerProviderStateMixin {
      ScrollController scrollController;
      double screenWidth;
      double screenHeight;
      double position = 0.0;
      Timer timer;
      final double _moveDistance = 3.0;
      final int _timerRest = 100;
      GlobalKey _key = GlobalKey();
    
      @override
      void initState() {
        super.initState();
        scrollController = ScrollController();
        WidgetsBinding.instance.addPostFrameCallback((callback) {
          startTimer();
        });
      }
    
      void startTimer() {
        if (_key.currentContext != null) {
          double widgetWidth =
              _key.currentContext.findRenderObject().paintBounds.size.width;
          double widgetHeight =
              _key.currentContext.findRenderObject().paintBounds.size.height;
    
          timer = Timer.periodic(Duration(milliseconds: _timerRest), (timer) {
            double maxScrollExtent = scrollController.position.maxScrollExtent;
            double pixels = scrollController.position.pixels;
            if (pixels + _moveDistance >= maxScrollExtent) {
              if (widget.scrollAxis == Axis.horizontal) {
                position = (maxScrollExtent -
                            screenWidth * widget.ratioOfBlankToScreen +
                            widgetWidth) /
                        2 -
                    widgetWidth +
                    pixels -
                    maxScrollExtent;
              } else {
                position = (maxScrollExtent -
                            screenHeight * widget.ratioOfBlankToScreen +
                            widgetHeight) /
                        2 -
                    widgetHeight +
                    pixels -
                    maxScrollExtent;
              }
              scrollController.jumpTo(position);
            }
            position += _moveDistance;
            scrollController.animateTo(position,
                duration: Duration(milliseconds: _timerRest), curve: Curves.linear);
          });
        }
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        screenWidth = MediaQuery.of(context).size.width;
        screenHeight = MediaQuery.of(context).size.height;
      }
    
      Widget getBothEndsChild() {
        if (widget.scrollAxis == Axis.vertical) {
          String newString = widget.text.split("").join("\n");
          return Center(
            child: Text(
              newString,
              style: widget.textStyle,
              textAlign: TextAlign.center,
            ),
          );
        }
        return Center(
            child: Text(
          widget.text,
          style: widget.textStyle,
        ));
      }
    
      Widget getCenterChild() {
        if (widget.scrollAxis == Axis.horizontal) {
          return Container(width: screenWidth * widget.ratioOfBlankToScreen);
        } else {
          return Container(height: screenHeight * widget.ratioOfBlankToScreen);
        }
      }
    
      @override
      void dispose() {
        super.dispose();
        if (timer != null) {
          timer.cancel();
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return ListView(
          key: _key,
          scrollDirection: widget.scrollAxis,
          controller: scrollController,
          physics: NeverScrollableScrollPhysics(),
          children: <Widget>[
            getBothEndsChild(),
            getCenterChild(),
            getBothEndsChild(),
          ],
        );
      }
    }
    

    并像这样使用小部件:

    ScrollingText(
      text: text,
      textStyle: TextStyle(fontSize: 12),
    )
    
    

    【讨论】:

    • 如果你使用 Marquee(另一个答案)或者这个答案,不要忘记把它放在一个容器中并给它高度和宽度,因为 Marque 和上面的例子是listview
    【解决方案2】:

    使用来自 pub.dev marquee 的这个小部件。

    Marquee(
      text: 'There once was a boy who told this story about a boy: "',
    )
    

    【讨论】:

      猜你喜欢
      • 2023-04-10
      • 1970-01-01
      • 2021-10-21
      • 2021-11-12
      • 1970-01-01
      • 1970-01-01
      • 2021-08-09
      • 2021-05-19
      • 1970-01-01
      相关资源
      最近更新 更多