Kdon
Kdon

Reputation: 1235

How to create an indefinite smooth-scrolling list of images in Flutter?

I am trying to dynamically add items to the list in Flutter so this list runs indefinitely. (I am trying to achieve this using a ListView.builder and the Future class).

The end-effect I am seeking is an endless auto-scrolling of randomly generated images along the screen at a smooth rate (kind of like a news ticker).

Is this possible? I have been reworking for ages (trying AnimatedList etc) but cant seem to make it work!

Would love any help to solve this problem or ideas.


import 'package:flutter/material.dart';

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

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

class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Offset> _anim;

  List<String> _list = ItemsList().createList;

  void addToList() {

    Future ft = Future((){});

    ft = ft.then((value) => Future.delayed(Duration(milliseconds: 200), (){
      setState(() {
        _list.insert(_list.length, 'Ant'); //This part will replace with a method to randomly select images
    });
    }));
  }

  void initState() {
    
    _controller = AnimationController(
        duration: Duration(milliseconds: 8000), vsync: this);

    _anim = Tween<Offset>(begin: Offset(0, 0), end: Offset(-5, 0))
        .animate(_controller)
          ..addStatusListener((status) {});

    _controller.forward();

    addToList();
    
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Material(
        child: ListView.builder(
            scrollDirection: Axis.horizontal,
            itemBuilder: (context, index) {
              return SlideTransition(
                position: _anim,
                child: Center(
                  child: Padding(
                    padding: const EdgeInsets.all(58.0),
                    child: Container(
                      height: 50,
                      width: 100,
                      color: Colors.white54,
                      child:
                          Image.asset('assets/images/${_list[index]}.png'),
                    ),
                  ),
                ),
              );
            }));
  }
}

class ItemsList {
  List<String> createList = [
    'Ant',
    'Apple',
    'Artist',
    'Baby',
    'Bag',
//etc
  ];
}

Upvotes: 0

Views: 1724

Answers (1)

hnnngwdlch
hnnngwdlch

Reputation: 3051

In the following example code, which you can also run in DartPad, a new item is added to the list every two seconds. The ScrollController is then used to scroll to the end of the list within one second.

The timer is only used to continuously add random items to the list, you could, of course, listen to a stream (or similar) instead.

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:math';

final Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

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

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

class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late Timer _timer;
  final _controller = ScrollController();
  final _rnd = Random();

  List<String> _list = ItemsList().createList;

  void initState() {
    _timer = Timer.periodic(Duration(seconds: 2), (timer) {
      setState(() {
        _list.add('Item ${_rnd.nextInt(100)}');
      });
      _controller.animateTo(
        _controller.position.maxScrollExtent,
        duration: Duration(seconds: 1),
        curve: Curves.fastOutSlowIn,
      );
    });

    super.initState();
  }

  @override
  void dispose() {
    _timer.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: ListView.builder(
        controller: _controller,
        itemCount: _list.length,
        scrollDirection: Axis.horizontal,
        itemBuilder: (context, index) {
          return Center(
            child: Padding(
              padding: const EdgeInsets.all(58.0),
              child: Container(
                height: 50,
                width: 100,
                color: Colors.white54,
                child: Center(
                  child: Text(
                    _list[index],
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

class ItemsList {
  List<String> createList = [
    'Ant',
    'Apple',
    'Artist',
    'Baby',
    'Bag',
//etc
  ];
}

Upvotes: 1

Related Questions