flutter - How to make delay to ListView, so item show one by one

1,481
  1. Set default delay.
  2. Think how to calculate delay for a item, if previous item hasn't appeared yet.
  3. Use opacity widget.

I've made a simple example, how you can do it.

enter image description here

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        backgroundColor: Colors.blue,
        body: Test(),
      ),
    );
  }
}

class Test extends StatelessWidget {
  DateTime lastRender;

  get _duration {
    var now = DateTime.now();
    var defaultDelay = Duration(milliseconds: 100);
    Duration delay;

    if (lastRender == null) {
      lastRender = now;
      delay = defaultDelay;
    } else {

      var difference = now.difference(lastRender);
      if (difference > defaultDelay) {
        lastRender = now;
        delay = defaultDelay;
      } else {
        var durationOffcet = difference - defaultDelay;
        delay = defaultDelay + (-durationOffcet);

        lastRender = now.add(-durationOffcet);
      }
      return delay;
    }

    return defaultDelay;
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: List.generate(
        100,
        (index) => Item('item $index', _duration),
      ),
    );
  }
}

class Item extends StatefulWidget {
  const Item(this.text, this.duration);

  final Duration duration;
  final String text;

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

class _ItemState extends State<Item> with SingleTickerProviderStateMixin {
  Animation<double> animation;
  AnimationController animationController;

  bool visible = false;

  @override
  void initState() {
    super.initState();
    animationController = AnimationController(
      duration: widget.duration,
      vsync: this,
    );

    animation = Tween(begin: 0.0, end: 1.0).animate(animationController);
    animation.addStatusListener((status) {
      setState(() {});
    });
    animationController.forward();
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return Opacity(
      opacity: animation.value,
      child: Container(
        decoration: BoxDecoration(
          color: Colors.white,
          border: Border.all(
            width: 4,
            color: Colors.blueAccent,
          ),
        ),
        height: 80,
        child: Text(widget.text, style: TextStyle(fontSize: 20.0)),
      ),
    );
  }
}
Share:
1,481
questionasker
Author by

questionasker

I'm Web, Unity3D &amp; Flutter Developer. I love to share my ideas at my web, please visit my website for any tutorial related to marketing, programming, docker, linux, etc

Updated on December 13, 2022

Comments

  • questionasker
    questionasker over 1 year

    I have a ListView that contains dynamic items, generated via StreamBuilder. Currently, these items show all at once like normal ListView. However, I want to make it so the items of the ListView show one by one with delay.

    Is it even possible?

    StreamBuilder(
      stream: greetingBloc.list,
      builder: (BuildContext context,AsyncSnapshot<List<Greeting>> snapshot){
        if(snapshot.hasData){
          return ListView.builder(
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              itemCount: snapshot.data.length,
              itemBuilder: (ctx,i){
                return Padding(
                  padding: EdgeInsets.all(8),
                  child: Container(
                    padding: EdgeInsets.all(16),
                    color: Colors.green,
                    child: Text(snapshot.data[i].description,
                      style: TextStyle(
                          color: Colors.white
                      ),),
                  ),
                );
              },
            );
        }else{
          return GreetingShimmer();
        }  
      },
    ),