如何在Flutter中使文本小部件在文本溢出时像跑马灯一样滚动

17

我正在寻找一种在文本小部件中实现跑马灯样式的方式,使得当文本从屏幕溢出时,它会自动开始滚动。有没有办法做到这一点?我已经尝试了所有的装饰模式,但似乎没有找到跑马灯选项。


你能详细说明一下你想要实现的目标吗,也就是你所说的“跑马灯样式”具体指什么。 - creativecreatorormaybenot
1
跑马灯是指当文本溢出时,文本自动滚动来回显示整个文本。它在Android的文本视图中可用。 - Jaswant Singh
2个回答

60

这个小部件就是我想出来的,我认为它能够满足你的需求:

class MarqueeWidget extends StatefulWidget {
  final Widget child;
  final Axis direction;
  final Duration animationDuration, backDuration, pauseDuration;

  const MarqueeWidget({
    Key? key,
    required this.child,
    this.direction = Axis.horizontal,
    this.animationDuration = const Duration(milliseconds: 6000),
    this.backDuration = const Duration(milliseconds: 800),
    this.pauseDuration = const Duration(milliseconds: 800),
  }) : super(key: key);

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

class _MarqueeWidgetState extends State<MarqueeWidget> {
  late ScrollController scrollController;

  @override
  void initState() {
    scrollController = ScrollController(initialScrollOffset: 50.0);
    WidgetsBinding.instance.addPostFrameCallback(scroll);
    super.initState();
  }

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      physics: NeverScrollableScrollPhysics(),
      child: widget.child,
      scrollDirection: widget.direction,
      controller: scrollController,
    );
  }

  void scroll(_) async {
    while (scrollController.hasClients) {
      await Future.delayed(widget.pauseDuration);
      if (scrollController.hasClients) {
        await scrollController.animateTo(
          scrollController.position.maxScrollExtent,
          duration: widget.animationDuration,
          curve: Curves.ease,
        );
      }
      await Future.delayed(widget.pauseDuration);
      if (scrollController.hasClients) {
        await scrollController.animateTo(
          0.0,
          duration: widget.backDuration,
          curve: Curves.easeOut,
        );
      }
    }
  }
}

它的功能应该很明显。一个示例实现看起来像这样:

class FlutterMarqueeText extends StatefulWidget {
  const FlutterMarqueeText({Key? key}) : super(key: key);

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

class _FlutterMarqueeTextState extends State<FlutterMarqueeText> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Flutter Marquee Text"),
      ),
      body: const Center(
        child: SizedBox(
          width: 200.0,
          child: MarqueeWidget(
            direction: Axis.horizontal,
            child: Text("This text is to long to be shown in just one line"),
          ),
        ),
      ),
    );
  }
}

1
'_positions.isNotEmpty': ScrollController未附加到任何滚动视图上。在退出带有此小部件的页面时显示此错误。 - Vettiyanakan
MarqueeWidget是否在像ListView这样的滚动容器中?这可能会导致崩溃,因为它尚未被渲染,所以ScrollController尚未附加。 - leodriesch
1
为我节省了很多时间...而且不想使用任何软件包。这个方法百分之百有效.. - rohan koshti
简单而优雅。我想突然将光标移动到最后一个输入的数字,所以我用jumpTo()替换了animateTo()并删除了动画持续时间。效果很好。 - Priya Sindkar
@leodriesch,请根据空安全性进行更新。非常感谢 :) - Kamlesh
显示剩余2条评论

3
使用跑马灯包,如果出现'hasSize'错误或'父部件使用不正确'的错误,请将跑马灯小部件包装在容器中,并为该容器提供高度和宽度。

2
你能举个例子吗? - Alok Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接