Search code examples
flutteranimationcarousel

How to create a constant looping auto-scroll in Flutter?


I am seeking to create a constant scroll of a dynamic number of images across my screen (similar to a news ticker) in Flutter. I want this to be automatic and a constant speed, that also loops.

The simplest solution I have found is to use the Carousel Package which ticks almost all the boxes, except one. I am unable to get a constant scroll speed

A possible solution was to adjust autoPlayInterval to zero, but unfortunately, this paramater appears to need a value of around 50 or greater to run - therefore creating an even scroll.

Any idea on how to tweak it this with this package? Or another suitable solution?

Simplified code:

@override
  Widget build(BuildContext context) {
      return Container(
        child: CarouselSlider(
          items: DynamicImages.list
              .map(
                (e) => Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Image.asset('assets/images/$e.png'),
                ),
              )
              .toList(),
          options: CarouselOptions(
            autoPlay: true,
            autoPlayCurve: Curves.linear,
            autoPlayInterval: Duration(milliseconds: 0), /// carousel will not run if set to zero
            autoPlayAnimationDuration: Duration(milliseconds: 1000)
          ),
        ),
      );
  }
}

Solution

  • I found a workaround that still takes advantage of the carousel_slider package. Instead of using autoplay, you just give it a CarouselController.

    Start the animation by calling nextPage() in initState. Then in the carousel, set onPageChanged to call nextPage() again, which will continuously scroll from page to page with constant speed. Set the duration for the two nextPage() calls to whatever you want, as long as it's the same duration.

    The only pause I experience is when it reaches the end of the list, where it needs to loop back to the first image. But it's negligible enough for my use case.

    class _WelcomeScreenState extends State<WelcomeScreen> {
      List<String> _images = [
        "assets/image.jpg",
        // ...
      ];
    
      final CarouselController _carouselController = CarouselController();
    
      @override
      void initState() {
        super.initState();
        
        // Add this to start the animation
        WidgetsBinding.instance.addPostFrameCallback((_) {
          _carouselController.nextPage(duration: Duration(milliseconds: 2000));
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return WillPopScope(
          onWillPop: () async => false,
          child: ScreenBackgroundContainer(
            child: Scaffold(
              body: SafeArea(
                child: Container(
                  height: double.maxFinite,
                  width: double.maxFinite,
                  child: SingleChildScrollView(
                    physics: BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
                    padding: const EdgeInsets.symmetric(vertical: 16.0),
                    child: Column(
                      children: [
                        // Carousel
                        CarouselSlider(
                          carouselController: _performerCarouselController,
                          options: CarouselOptions(
                              pageSnapping: false,
                              height: 146,
                              viewportFraction: 114 / MediaQuery.of(context).size.width,
                              // Add this
                              onPageChanged: (_, __) {
                                _performerCarouselController.nextPage(duration: Duration(milliseconds: 2000));
                              }),
                          items: _performerImages
                              .map((image) => ClipRRect(
                                  borderRadius: BorderRadius.circular(16.0),
                                  child: Image.asset(image, width: 90, fit: BoxFit.cover)))
                              .toList(),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
        );
      }
    }
    

    Screenshot