FlutterSoundRecorder.onProgress never hasData in StreamBuilder - ios

I am following this 5 minutes video to set up an audio recorder in Flutter.
When I click the ElevatedButton to start recording the audio, it does change between play and stop, and an audio file is created, but the snapshot.hasData is always false, so the Text stays 00:00 during recording. The only information I found is about setSubscriptionDuration, which I did set. I also tried flutter clean, etc. What else can it be?
I'm using Flutter 3.3.8, on macOS, flutter_sound: ^9.1.9. I'm running the app on a real iPhone XR with flutter run
I am new to flutter. I really appreciate any help you can provide!
I have
StreamBuilder
StreamBuilder<RecordingDisposition>(
stream: recorder.onProgress,
builder: (context, snapshot) {
print('snapshot.hasData :${snapshot.hasData}');
final duration =
snapshot.hasData ? snapshot.data!.duration : Duration.zero;
print('duration :$duration');
String twoDigits(int n) => n.toString().padLeft(2, '0');
final twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
final twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return Text(
'$twoDigitMinutes:$twoDigitSeconds',
style: const TextStyle(
fontSize: 20,
),
);
},
),
ElevatedButton
ElevatedButton(
child: Icon(
recorder.isRecording ? Icons.stop : Icons.mic,
size: 20,
),
onPressed: () async {
if (recorder.isRecording) {
await stop();
} else {
await record();
}
setState(() {});
},
)
Initialize the recorder properly
final recorder = FlutterSoundRecorder();
Future<void> initRecorder() async {
final status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
throw 'Microphone permission not granted';
}
await recorder.openRecorder();
isRecorderReady = true;
recorder.setSubscriptionDuration(
const Duration(
microseconds: 100,
),
);
}
#override
void initState() {
super.initState();
initRecorder();
}
This is what it looks like so far:

So, I found a solution, but the StreamBuilder question is not answered. Instead of using StreamBuilder, create a stateful TimerWidget that's initialized by a ValueNotifier.
import 'dart:async';
import 'package:flutter/material.dart';
enum Time { start, pause, reset }
class TimerController extends ValueNotifier<Time> {
TimerController({Time time = Time.reset}) : super(time);
void startTimer() => value = Time.start;
void pauseTimer() => value = Time.pause;
void resetTimer() => value = Time.reset;
}
class TimerWidget extends StatefulWidget {
final TimerController controller;
const TimerWidget({
Key? key,
required this.controller,
}) : super(key: key);
#override
_TimerWidgetState createState() => _TimerWidgetState();
}
class _TimerWidgetState extends State<TimerWidget> {
Duration duration = const Duration();
Timer? timer;
#override
void initState() {
super.initState();
widget.controller.addListener(() {
switch (widget.controller.value) {
case Time.start:
startTimer();
break;
case Time.pause:
stopTimer();
break;
case Time.reset:
reset();
stopTimer();
break;
}
});
}
void reset() => setState(() => duration = const Duration());
void addTime() {
const addSeconds = 1;
setState(() {
final seconds = duration.inSeconds + addSeconds;
if (seconds < 0) {
timer?.cancel();
} else {
duration = Duration(seconds: seconds);
}
});
}
void startTimer({bool resets = true}) {
if (!mounted) return;
timer = Timer.periodic(const Duration(seconds: 1), (_) => addTime());
}
void stopTimer() {
if (!mounted) return;
setState(() => timer?.cancel());
}
#override
Widget build(BuildContext context) => Center(child: buildTime());
Widget buildTime() {
String twoDigits(int n) => n.toString().padLeft(2, "0");
final twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
final twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return Text(
'$twoDigitMinutes:$twoDigitSeconds',
style: const TextStyle(
fontSize: 80,
fontWeight: FontWeight.bold,
),
);
}
}

change the microseconds: 100, to millisecond:100 in recorder.setSubscriptionDuration
recorder.setSubscriptionDuration(
const Duration(milliseconds: 100),
);
like this

Related

StateError (Bad state: No element) on IOS only

This error does not occur on Android or web but only on IOS. It seem very trivial but I can't figure out what's wrong.
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'dart:convert';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class ScanQrPage extends StatefulWidget {
#override
_ScanQrPageState createState() => _ScanQrPageState();
}
class _ScanQrPageState extends State<ScanQrPage> {
final qrKey = GlobalKey();
late QRViewController qrViewController;
late Barcode barcode;
// In order to get hot reload to work we need to pause the camera if the platform
// is android, or resume the camera if the platform is iOS.
#override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
qrViewController.pauseCamera();
} else if (Platform.isIOS) {
qrViewController.resumeCamera();
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
Navigator.of(context).pop("");
return new Future(() => true);
},
child: Scaffold(
body: Stack(
children: [
buildQrView(context),
],
),
),
);
}
Widget buildQrView(BuildContext context) {
return QRView(
onQRViewCreated: onQRViewCreated,
key: qrKey,
overlay: QrScannerOverlayShape(
cutOutSize: MediaQuery.of(context).size.width * 0.8),
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
);
}
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
if (!p) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('no Permission')),
);
}
}
#override
void dispose() {
qrViewController.dispose();
super.dispose();
}
void onQRViewCreated(QRViewController qrViewController) {
setState(() {
this.qrViewController = qrViewController;
});
qrViewController.scannedDataStream.listen((event) {
setState(() {
this.barcode = event;
if (Platform.isAndroid) {
qrViewController.pauseCamera();
} else if (Platform.isIOS) {
qrViewController.resumeCamera();
}
String rawData = event.code;
Uri data = Uri.dataFromString(rawData);
String para1 = data.queryParameters["buy"] ??
""; //get parameter with attribute "para1"
Codec<String, String> stringToBase64 = utf8.fuse(base64);
if (para1 != "") {
placer = stringToBase64.decode(para1);
}
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
Navigator.pop(context, placer);
});
});
});
}
}
I've tried all the solutions with the same error found on stackoverflow (addPostFrameCallback and Future(Duration.zero)) but none of them are exactly the same and does not seem to fix my problem.
I don't think I have having the same issue as any of the other questions.
The exception is happening on the Navigator.pop(context, placer);
Does anyone have any idea how to overcome this?
Why does this only happen on IOS?

Countdown in text flutter

We need to create a 5 minute countdown text object in Flutter, once the countdown reaches zero then we need to launch a new screen. here is the current code:
Container(
margin: EdgeInsets.only(left: 0.0,top: 60.0, bottom: 50.0, right:0.0),
child: Text(
'5:00', style: new TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100.0 ))
,
),
I usually don't post just sample code, but I was in the mood of coding a bit in flutter. So here's my quick suggestion on how you can implement this:
class _MyHomePageState extends State<MyHomePage> {
TickViewModel _viewModel;
int _seconds;
StreamSubscription<int> _tickSubscription;
#override
void initState() {
super.initState();
_viewModel = TickViewModel();
_tickSubscription = _viewModel._tickStream.listen((newTime) {
if (newTime == 0) {
//TODO: DO THE SCREEN CHANGE HERE;
}
setState(() {
_seconds = newTime;
});
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("My Flutter App"),
backgroundColor: Colors.red,
),
body: Text(_computeTime()));
}
String _computeTime() {
if (_seconds == null) {
return "-";
}
String minutes = "${_seconds ~/ 60}".padLeft(2, "0");
String seconds = "${_seconds % 60}".padLeft(2, "0");
return "$minutes:$seconds";
}
#override
void dispose() {
//We cleanup the stuffs here
_tickSubscription.cancel();
_viewModel.destroy();
super.dispose();
}
}
class TickViewModel {
static const int _fiveMinutes = 5 * 60;
StreamController<int> _ticker;
Stream<int> get _tickStream => _ticker.stream;
Timer _timer;
final int seconds;
int _internalSeconds;
TickViewModel({this.seconds = _fiveMinutes}) : _internalSeconds = seconds {
_ticker = StreamController(onListen: () {
//start timer only when we have a subscriber
_startTimer();
}, onCancel: () {
_timer.cancel();
});
}
void _startTimer() {
//start timer to tick every 1 second
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
_internalSeconds -= 1;
if (_internalSeconds < 0) {
_timer.cancel();
} else {
_ticker.add(_internalSeconds);
}
});
}
void destroy() {
_ticker.close();
_timer.cancel();
}
}

Pause Flutter Countdown Timer

I have been playing with Dart Timer Class that I got it to work in its very basic form, however I am stuck trying to add a pause function to it. I have looked into their documentations, but their is not much about their Timer class...
Is there any way I can pause and resume the timer/countdown on click? This is what I have achieved so far:
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Timer _timer;
int _start = 10;
void startTimer() {
const oneSec = const Duration(seconds: 1);
_timer = new Timer.periodic(
oneSec,
(Timer timer) => setState(() {
if (_start < 1) {
timer.cancel();
} else {
_start = _start - 1;
}
}));
}
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: Text("Timer test")),
body: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
startTimer();
},
child: Text("start"),
),
Text("$_start")
],
));
}
}
I just uploaded this package to implement exactly this: https://pub.dev/packages/pausable_timer
// It starts paused
final timer = PausableTimer(Duration(seconds: 1), () => print('Fired!'));
timer.start();
timer.pause();
timer.start();
There is also an issue requesting the feature in Dart itself, but it doesn't look like it will be added soon.
There is no built-in pause function, since the Timer class is mainly intended for scheduling blocks of code for later.
What is your use case? The Stopwatch class has pause and resume funtionality.
Working flutter example with pause and vibrations is below (source)
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:vibration/vibration.dart';
void main() => runApp(MaterialApp(home: CountdownCard()));
class CountdownCard extends StatefulWidget {
// This widget is the root of your application.
#override
_CountdownCardState createState() => _CountdownCardState();
}
class _CountdownCardState extends State<CountdownCard> {
Timer _timer;
int _start = 0;
bool _vibrationActive = false;
void startTimer(int timerDuration) {
if (_timer != null) {
_timer.cancel();
cancelVibrate();
}
setState(() {
_start = timerDuration;
});
const oneSec = const Duration(seconds: 1);
print('test');
_timer = new Timer.periodic(
oneSec,
(Timer timer) => setState(
() {
if (_start < 1) {
timer.cancel();
print('alarm');
vibrate();
} else {
_start = _start - 1;
}
},
),
);
}
void cancelVibrate() {
_vibrationActive = false;
Vibration.cancel();
}
void vibrate() async {
_vibrationActive = true;
if (await Vibration.hasVibrator()) {
while (_vibrationActive) {
Vibration.vibrate(duration: 1000);
await Future.delayed(Duration(seconds: 2));
}
}
}
void pauseTimer() {
if (_timer != null) _timer.cancel();
}
void unpauseTimer() => startTimer(_start);
#override
void dispose() {
_timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Countdown'),
),
body: Wrap(children: <Widget>[
Column(
children: <Widget>[
RaisedButton(
onPressed: () {
startTimer(10);
},
child: Text("start"),
),
Text("$_start"),
RaisedButton(
onPressed: () {
pauseTimer();
},
child: Text("pause"),
),
RaisedButton(
onPressed: () {
unpauseTimer();
},
child: Text("unpause"),
),
RaisedButton(
onPressed: () {
cancelVibrate();
},
child: Text("stop alarm"),
),
],
),
]));
}
}
variables we define
start timer on page opening.
timer off when page is closed.
if the screen is touched, the variable duration becomes true and the timer stops counting down
Timer? _timer;
int _start = 200;
bool duration = false;
Duration oneSec = const Duration(milliseconds: 10);
#override
void initState() {
// TODO: implement initState
super.initState();
startTimer();
}
#override
void dispose() {
_timer!.cancel();
super.dispose();
}
```
GestureDetector(
onTap: () {},
onTapDown: (e) {
setState(() {
duration = true;
});
},
onHorizontalDragEnd: (e) {
Navigator.pop(context);
},
onTapUp: (e) {
setState(() {
duration = false;
});
},
child:Text("demo page")}
void startTimer() {
_timer = new Timer.periodic(
oneSec,
(Timer timer) {
if (_start == 0) {
setState(() {
timer.cancel();
Navigator.pop(context);
});
} else {
setState(() {
duration == false ? _start-- : null;
});
}
},
);
}
}

Flutter architecture question / callback functions

I'm new to Flutter and I have a question about structuring the following code. It's a work in progress but it should do to illustrate my question. Basically I have a list of countdown timers (TimerEntry) with a start button. However, I want to get rid of the button logic inside the timer objects and move it up to a list of timers (TimerList), in order to do things like start timer 2 after timer 1 finishes, or stop all other timers when a new timer gets started, etc..
Like I said, I'm totally new to Flutter and I hope someone can point me in a direction of how to do that. I'm guessing some sort of custom callback function?
import 'package:flutter/material.dart';
class TimedItem extends AnimatedWidget {
TimedItem({this.task, this.timeRemainingInSeconds})
: super(listenable: timeRemainingInSeconds);
final Animation<int> timeRemainingInSeconds;
final String task;
Widget build(BuildContext context) {
String minutes =
'${(timeRemainingInSeconds.value / 60).floor()}'.padLeft(2, '0');
String seconds = '${(timeRemainingInSeconds.value % 60)}'.padLeft(2, '0');
return ListTile(
title: Text(
'$minutes:$seconds',
style: Theme.of(context).textTheme.display2,
),
subtitle: Text(task),
);
}
}
class TimerEntry extends StatefulWidget {
final int index;
final String task;
final Duration duration;
bool currentlyActive;
TimerEntry({this.index, this.task, this.duration, this.currentlyActive});
TimerEntryState createState() => TimerEntryState();
}
class TimerEntryState extends State<TimerEntry> with TickerProviderStateMixin {
AnimationController _controller;
AnimationController get controller {
return _controller;
}
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
}
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Flexible(
child: TimedItem(
task: widget.task,
timeRemainingInSeconds: IntTween(
begin: controller.duration.inSeconds,
end: widget.currentlyActive ? 0 : widget.duration.inSeconds,
).animate(controller)
),
),
toggleButton()
],
);
}
Widget toggleButton() {
return FloatingActionButton(
onPressed: () {
controller.forward(from: 0.0);
widget.currentlyActive = true;
},
child: widget.currentlyActive
? Icon(Icons.pause_circle_outline)
: Icon(Icons.play_circle_outline),
);
}
}
class TimerList extends StatefulWidget {
final int currentActiveTimer = 0;
/// TODO: get them from outside
final entries = <TimerEntry>[
TimerEntry(
index: 0,
task: "The first task",
duration: Duration(minutes: 3),
currentlyActive: true,
),
TimerEntry(
index: 1,
task: "Another task altogether",
duration: Duration(minutes: 1),
currentlyActive: false,
)
];
#override
_TimerListState createState() => _TimerListState();
}
class _TimerListState extends State<TimerList> {
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.entries.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return TimerEntry(
task: widget.entries[index].task,
duration: widget.entries[index].duration,
currentlyActive: widget.entries[index].currentlyActive,
);
});
}
}
Edit:
Here's a new version that works with a custom callback GetTaskButton but now I've lost access to my animation controller (see toggleButton function at the bottom). Is there a way to do it without moving the controller to the list class?
import 'package:flutter/material.dart';
typedef Widget GetTaskButton(TimerEntry t);
class TimedItem extends AnimatedWidget {
TimedItem({this.task, this.timeRemainingInSeconds})
: super(listenable: timeRemainingInSeconds);
final Animation<int> timeRemainingInSeconds;
final String task;
Widget build(BuildContext context) {
String minutes =
'${(timeRemainingInSeconds.value / 60).floor()}'.padLeft(2, '0');
String seconds = '${(timeRemainingInSeconds.value % 60)}'.padLeft(2, '0');
return ListTile(
title: Text(
'$minutes:$seconds',
style: Theme.of(context).textTheme.display2,
),
subtitle: Text(task),
);
}
}
class TimerEntry extends StatefulWidget {
final int index;
final String task;
final Duration duration;
final GetTaskButton getButton;
bool currentlyActive;
TimerEntry({this.index, this.task, this.duration, this.currentlyActive, this.getButton});
TimerEntryState createState() => TimerEntryState();
}
class TimerEntryState extends State<TimerEntry> with TickerProviderStateMixin {
AnimationController _controller;
AnimationController get controller {
return _controller;
}
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
}
#override
Widget build(BuildContext context) {
// return Text("test");
return Row(
children: <Widget>[
Flexible(
child: TimedItem(
task: widget.task,
timeRemainingInSeconds: IntTween(
begin: controller.duration.inSeconds,
end: widget.currentlyActive ? 0 : widget.duration.inSeconds,
).animate(controller)
),
),
widget.getButton(widget)
],
);
}
}
class TimerList extends StatefulWidget {
final int currentActiveTimer = 0;
/// TODO: get them from outside
final entries = <TimerEntry>[
TimerEntry(
index: 0,
task: "The first task",
duration: Duration(minutes: 3),
currentlyActive: true,
),
TimerEntry(
index: 1,
task: "Another task altogether",
duration: Duration(minutes: 1),
currentlyActive: false,
)
];
#override
_TimerListState createState() => _TimerListState();
}
class _TimerListState extends State<TimerList> {
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.entries.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return TimerEntry(
task: widget.entries[index].task,
duration: widget.entries[index].duration,
currentlyActive: widget.entries[index].currentlyActive,
getButton: (Widget tButton) => toggleButton(widget.entries[index]),
);
});
}
Widget toggleButton(TimerEntry t) {
return FloatingActionButton(
onPressed: () {
setState(() {
/// TODO: how to access this one?
// t.controller.forward(from: 0.0);
t.currentlyActive = !t.currentlyActive;
});
},
child: t.currentlyActive
? Icon(Icons.pause_circle_outline)
: Icon(Icons.play_circle_outline),
);
}
}
Here are Few things you can Do:
Create a Global List variable.
List<TimerEntry> myEntries = List<TimerEntry>();
A function to add the Value in the myEntries List. I have hard-Coded the Values you can pass the Arguments to make it Dynamic.
void _addTimers() {
myEntries.add(TimerEntry(
index: 0,
task: "The first task",
duration: Duration(minutes: 3),
currentlyActive: true,
));
myEntries.add(TimerEntry(
index: 1,
task: "The Second task",
duration: Duration(minutes: 3),
currentlyActive: true,
));
}
You can Call the Function Whenever you need to Add the timer _addTimers();
In the Class TimerList - you need to Define a Constructor to get the List.
class TimerList extends StatefulWidget {
final int currentActiveTimer = 0;
final List<TimerEntry> entries;
TimerList({this.entries});
& last you need the Pass the global List variable to the Class where you have Initialize it.
body: TimerList(entries: myEntries,),
update:
Edited toggleButton() to make sure it responds correctly to the onTap().
Widget toggleButton() {
return FloatingActionButton(
onPressed: () {
setState(() {
controller.forward(from: 0.0);
widget.currentlyActive = !widget.currentlyActive;
});
},
child: widget.currentlyActive
? Icon(Icons.pause_circle_outline)
: Icon(Icons.play_circle_outline),
);
}
Update: Passing AnimationController to Timer
class _TimerListState extends State<TimerList> with TickerProviderStateMixin {
List<AnimationController> myAnimationControllers =
List<AnimationController>();
#override
void initState() {
_getControllerList();
super.initState();
}
void _getControllerList() {
widget.entries.forEach((f) {
myAnimationControllers
.add(AnimationController(vsync: this, duration: f.duration));
});
}
Then in build pass it to TimerEntry:
TimerEntry(
task: widget.entries[index].task,
duration: widget.entries[index].duration,
currentlyActive: widget.entries[index].currentlyActive,
controller: myAnimationControllers[index]),
)
class TimerEntry extends StatefulWidget {
final int index;
final String task;
final Duration duration;
bool currentlyActive;
AnimationController controller;
TimerEntry({
this.index,
this.task,
this.duration,
this.currentlyActive,
this.controller,
});

how to display animations one after the other in flutter

I have mapped an array to a class and I am displaying the animation accordingly but the animation works for the entire thing at once. I want to have a delay between the subsequent animations.
The screenshot of the game is here. The stars should appear with animation one after the other The code that i am using is :
for (var i = 0; i < 4; i++) {
myScore > (10*i) ? stars.add("true") : stars.add("false");
}
Widget _buildItem(int index, String text) {
return new MyButton(
key: new ValueKey<int>(index),
text: text,
keys: keys++,
onPress: () {
}
);
}
class MyButton extends StatefulWidget {
MyButton(
{Key key,
this.text,
this.keys,
this.onPress})
: super(key: key);
final String text;
final VoidCallback onPress;
int keys;
#override
_MyButtonState createState() => new _MyButtonState();
}
class _MyButtonState extends State<MyButton> with TickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
String _displayText;
initState() {
super.initState();
print("_MyButtonState.initState: ${widget.text}");
_displayText = widget.text;
controller = new AnimationController(
duration: new Duration(milliseconds: 600), vsync: this);
animation = new CurvedAnimation(parent: controller, curve: Curves.easeIn)
..addStatusListener((state) {
// print("$state:${animation.value}");
if (state == AnimationStatus.dismissed) {
print('dismissed');
if (widget.text != null) {
setState(() => _displayText = widget.text);
controller.forward();
}
}
});
}
#override
void didUpdateWidget(MyButton oldWidget) {
super.didUpdateWidget(oldWidget);
// sleep(const Duration(microseconds: 10)); //I tried adding a delay here but instead it delays the entire thing.
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
Size media = MediaQuery.of(context).size;
double ht = media.height;
double wd = media.width;
widget.keys++;
print("_MyButtonState.build");
return new Shake(
animation: animation,
child: new GestureDetector(
child: new Container(
child: new FlatButton(
onPressed: () => widget.onPress(),
color: Colors.transparent,
child: new Icon(
_displayText == "true" ? Icons.star : Icons.star_border,
key: new Key("${widget.keys}"),
size: ht > wd ? ht * 0.05 : wd * 0.05,
color: Colors.black,
)
),)
) );
}
}
Use Staggered Animations in Flutter for series of operations , rather than all at once .Follow the link Staggered Animations to build Staggered Animations using Flutter .

Resources