Jaswant Singh
Jaswant Singh

Reputation: 10699

How to make a Text widget act like marquee when the text overflows in Flutter

I'm looking for a way to implement Marquee style on a Text widget so that it automatically start scrolling when the text is overflowed from the screen. Is there a way to do it. I've tried all the decoration modes but cant seem to find a Marquee option there.

Upvotes: 19

Views: 21967

Answers (2)

leodriesch
leodriesch

Reputation: 5780

This widget is what I came up with, and I think it serves your needs:

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,
        );
      }
    }
  }
}

Its functionality should be pretty obvious. An example implementation would look like this:

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"),
          ),
        ),
      ),
    );
  }
}

Upvotes: 67

ATEF SHAHRIER EVAN
ATEF SHAHRIER EVAN

Reputation: 89

Use The Marquee package. and if you get any 'hasSize' Error or 'Incorrect uses of Parent Widget' Error..

Just wrap Marquee widget with container and give height and width of that container.

Upvotes: 3

Related Questions