void valuerandomer() {
Future.delayed(Duration(milliseconds: 500), () {
int count = 0;
int max = 1000;
int min = 1;
Random rnd = new Random();
while (count != -1) {
count++;
value += rnd.nextInt(6) + (-5);
}
if (value > (max - 1)) {
value = 999;
} else if (value < 0) {
value = 0;
}
print(value);
});
}
I want the function to print every 500 miliseconds in the text widget so the value parameter starts with the value of 75 and changes every 500 milliseconds with this function.
How do I do that?
How do I declare this function in the text widget like Text('$valuerandomer')? cuz its just dont work. I tried just to type there $value but still doesnt work
For every x time, try using Timer.periodic
Timer? _timer;
String text = "initText";
#override
void dispose() {
_timer?.cancel();
super.dispose();
}
void valuerandomer() {
_timer = Timer.periodic(
Duration(milliseconds: 500),
(t) {
//perform your work
text = "newText ";
setState(() {});
},
);
}
Use funtion
Timer.periodic(Duration(/..),(timer){
//Put your logic
setState((){});
})
Related
*** UPDATE ***
I have a problem. When I use a Timer in Flutter and cancel() it afterwards, but as soon the cancel method is triggered, nothing happens.
var counter = 0;
Timer.periodic(const Duration(milliseconds: 50), (timer) {
developer.log('Actual counter ' + counter.toString());
counter++;
if (counter == 5) {
developer.log('TIMER DONE');
timer.cancel();
}
});
developer.log('This comes afterwards');
Expected out put:
Actual counter 0
Actual counter 1
Actual counter 2
Actual counter 3
Actual counter 4
TIMER DONE
This comes afterwards
The Output:
Actual counter 0
Actual counter 1
Actual counter 2
Actual counter 3
Actual counter 4
TIMER DONE
normally I should see a message 'this is afterwards' in the console, but it seems that with the cancel the complete method will be canceled.
Many thanks in advance.
Update: perform operation end of timer.
You need to add logic inside if condition to perform operation.
if (counter == firmwareList.length) {
timer.cancel();
developer.log('This comes afterwards'); //here
}
});
Here is an widget example
class TimerF extends StatefulWidget {
const TimerF({super.key});
#override
State<TimerF> createState() => _TimerFState();
}
class _TimerFState extends State<TimerF> {
var counter = 0;
Timer? timer;
bool isTimerActive = true;
#override
void initState() {
super.initState();
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
print('Still timer');
if (counter == 5) {
timer.cancel();
isTimerActive = false;
}
counter++;
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Text("current value ${counter}"),
if (timer?.isActive == false) Text("Timer isnt active"),
if (isTimerActive == false) Text("Timer isnt active $isTimerActive"),
],
),
);
}
}
I can't see any increment on counter on current snippet. that's why counter remains 0 and doesnt meet the condition to cancel the timer.
Perhaps it will be
var counter = 0;
Timer.periodic(const Duration(milliseconds: 50), (timer) {
print('Still timer');
if (counter == 5) {
timer.cancel();
}
counter++; //increment the value
print('this is afterwards');
});
Here is a fully working example using a Timer
Timer? timer;
startTimer() {
var counter = 0;
timer = Timer.periodic(const Duration(milliseconds: 50), (timer) {
counter += 1;
print('Actual step $counter');
if(counter==5) {
cancelTimer();
}
});
}
cancelTimer() {
timer?.cancel();
print('this is afterwards');
//do something here
}
When you startTimer(), here is the output
Actual step 1
Actual step 2
Actual step 3
Actual step 4
Actual step 5
this is afterwards
I just got back to Flutter, and wanted to test the countdown for a simple practice app.
I can scroll the countdown second by second but I haven't figured out how to do it with the milliseconds.
the current code:
import 'package:quiver/async.dart';
int _start = 10;
int _current = 10;
void startTimer() {
CountdownTimer countDownTimer = CountdownTimer(
Duration(seconds: _start),
const Duration(seconds: 1),
);
var sub = countDownTimer.listen(null);
sub.onData((duration) {
setState(() {
int _current = _start - duration.elapsed.inSeconds;
dureedefaut = _current;
});
});
}
I updated on my page the variable : dureedefaut
Thank you for your help
import 'package:quiver/async.dart';
int _start = 10;
int _current = 10;
void startTimer() {
CountdownTimer countDownTimer = CountdownTimer(
Duration(milliseconds: _start),
const Duration(milliseconds: 1),
);
var sub = countDownTimer.listen(null);
sub.onData((duration) {
setState(() {
int _current = _start - duration.elapsed.inSeconds;
dureedefaut = _current;
});
});
}
Simply use this :
Duration(milliseconds: )
you can use milisecond , second and etc in Duration Widget
I made a counter application, the user can determine the number of their own count. if the count reaches the count limit, I want it vibrate at the last count. For example, if I specify the number 5, the smartphone will vibrate on the 5th tap. However, I have a problem, because the vibration appears on the 6th tap.
How to make it vibrate on the 5th beat?
here is my code:
int _counter = 0;
int _five = 5;
onTap: () async {
setState(() {
if (_counter != _five) {
_counter++;
} else if (_counter == _five) {
Vibration.vibrate(duration: 500);
_counter = _counter + 0;
} else {}
});
},
Your code need a little change like:
onTap: () async {
setState(() {
if (_counter < _five) {
_counter++;
}
if (_counter == _five) {
Vibration.vibrate(duration: 500);
} else {}
});
}
I have a simple animation :
Animation<double> animation;
Tween<double> tween = Tween(begin: 1, end: 1.15);
AnimationController animationController;
#override
void initState() {
super.initState();
animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 300));
animation = animationController.drive(tween);
}
What i want ?
make this animation repeats e.g 20 times .
What i tried before posted this question ?
1- This method not have a parameter or way that makes me repeats this animation e.g 20 times.
it repeats and repeats and repeats forever :
animationController.repeat();
2- Use simple loops . It hangs my app, it requires to stop entire application and rerun it to solve that hanging . It's seems that loops completely not dealing with futures :
do {
animationController.forward().then((x) {
animationController.reverse().then((x) {
repeats++;
});
});
} while (repeats < 20);
3- Making int variable and add a listener ..etc,it's working , but seems that it's not the best way to do that matter :
int repeats = 0;
animation.addStatusListener((status) {
if (repeats < 20) {
if (status == AnimationStatus.completed) {
animationController.reverse();
} else if (status == AnimationStatus.dismissed) {
animationController.forward();
}
repeats++;
} });
4- make chain of then . **No comment on it ** 😂😂😂 :
animationController.forward().then((x) {
animationController.reverse().then((x) {
animationController.forward().then((x) {
animationController.reverse().then((x) {
animationController.forward().then((x) {
animationController.reverse();
});
});
});
});
});
Now , shortly how can i repeat animation 20 times
You can try it:
5 - Use TickerFuture return from repeat, set timeout then stop animation.
AnimationController _animationController;
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 3),
);
_animationController.addListener(() => setState(() {}));
TickerFuture tickerFuture = _animationController.repeat();
tickerFuture.timeout(Duration(seconds: 3 * 10), onTimeout: () {
_animationController.forward(from: 0);
_animationController.stop(canceled: true);
});
}
This can be easily done without the timer with extension method:
extension on AnimationController {
void repeatEx({#required int times}) {
var count = 0;
addStatusListener((status) {
if (status == AnimationStatus.completed) {
if (++count < times) {
reverse();
}
} else if (status == AnimationStatus.dismissed) {
forward();
}
});
}
}
And you could use it like this:
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
)
..repeatEx(times: 10)
..forward();
If you have a Widget with a playing argument that can set to true or false dynamically (to start and stop animation dynamically), you can improve behaviour by using a cancellable Timer() instead of Future.timeout :
void updatePlaying() {
if (widget.playing != false && !_controller.isAnimating && !_loopHasCompleted) {
_controller.repeat();
_timeout?.cancel();
_timeout = Timer(widget.duration * widget.loops, () {
_controller.reset();
_loopHasCompleted = true;
});
} else if (widget.playing == false) {
if (_controller.isAnimating)
_controller.reset();
_loopHasCompleted = false;
}
}
AnimationController(
lowerBound: 0.0,
upperBound: 20.0,
vsync: this, duration: Duration(milliseconds: 300))
It's easy to use just like below
var counter = 0;
int repeatTimes = 10 // how many times you want to repeat animation
animationController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
if (++counter < repeatTimes) {
animation.reverse();
}
} else if (status == AnimationStatus.dismissed) {
animation.forward();
}
});
I created a simple widget for this purpose
import 'package:flutter/widgets.dart';
import 'package:lottie/lottie.dart';
class LottieRepeat extends StatefulWidget {
final String asset;
final int repeatTimes;
final VoidCallback onComplete;
const LottieRepeat(
{Key? key,
required this.asset,
required this.repeatTimes,
required this.onComplete})
: super(key: key);
#override
State<LottieRepeat> createState() => _MyLottieRepeatState();
}
class _MyLottieRepeatState extends State<LottieRepeat>
with TickerProviderStateMixin {
late final AnimationController _controller;
int count = 0;
#override
void initState() {
super.initState();
/// validate
if (widget.repeatTimes <= 0) throw Exception('invalid repeat time');
_controller = AnimationController(vsync: this);
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
count++;
if (count < widget.repeatTimes) {
_controller.reset();
_controller.forward();
} else {
widget.onComplete();
}
}
});
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Lottie.asset(
widget.asset,
controller: _controller,
onLoaded: (composition) {
// Configure the AnimationController with the duration of the
// Lottie file and start the animation.
_controller
..duration = composition.duration
..forward();
},
);
}
}
sample usage:
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: LottieRepeat(
asset: 'assets/image/tick.json',
repeatTimes: 2,
onComplete: () => Navigator.of(context).pop(true),
),
);
});
I would like to be able to detect a triple tap (or even more) in a Flutter widget, although GestureDetector only has detection for double-tap built in.
What is the easiest way for me to detect a triple tap on a widget?
(I want continually clicking on a part of the screen to unlock some developer options)
Was a bit lazy with this one, in reality it's not that hard
// init
int lastTap = DateTime.now().millisecondsSinceEpoch;
int consecutiveTaps = 0;
GestureDetector(
onTap: () {
int now = DateTime.now().millisecondsSinceEpoch;
if (now - lastTap < 1000) {
print("Consecutive tap");
consecutiveTaps ++;
print("taps = " + consecutiveTaps.toString());
if (consecutiveTaps > 4){
// Do something
}
} else {
consecutiveTaps = 0;
}
lastTap = now;
},
child: ...
)
I tried the method mentioned here, but it didn't work for me. GestureDetector onTap is called only once,
regardless of the number of taps. Probably something has changed in flutter (I'm on the beta channel).
However, I dug into the source code of flutter and come to the solution (https://api.flutter.dev/flutter/gestures/SerialTapGestureRecognizer-class.html):
import "package:flutter/gestures.dart";
RawGestureDetector(gestures: {
SerialTapGestureRecognizer:
GestureRecognizerFactoryWithHandlers<SerialTapGestureRecognizer>(
() =>SerialTapGestureRecognizer(), (SerialTapGestureRecognizer instance) {
instance.onSerialTapDown = (SerialTapDownDetails details) {
if (details.count == 3) print("Consecutive tap 3");
};
})
I took a little different approach. Instead of having to compare timestamps, I set a Timer, which will reset the tapped state. But each time there is a tap, the old timer is canceled.
Timer? devPageClickTimer;
num devPageTapped = 0;
final devPageTapGoal = 5;
GestureDetector(
onTap: () {
devPageTapped++;
if (devPageTapped >= devPageTapGoal) {
router.push(const DeveloperRoute());
}
if (devPageClickTimer != null) {
devPageClickTimer!.cancel();
}
devPageClickTimer = Timer(const Duration(milliseconds: 200), () => devPageTapped = 0);
},
I have tried this method with reduced timeout and with both double and triple tap
int lastTap = DateTime.now().millisecondsSinceEpoch;
int consecutiveTaps = 1;
GestureDetector(
onTap: () {
int now = DateTime.now().millisecondsSinceEpoch;
if (consecutiveTaps == 1) {
print("taps = " + consecutiveTaps.toString());
lastTap = now;
}
if (now - lastTap < 300) {
print("Consecutive tap");
consecutiveTaps++;
print("taps = " + consecutiveTaps.toString());
if (consecutiveTaps == 3) {
print("Consecutive tap 3");
} else if (consecutiveTaps == 2) {
print("Consecutive tap 2");
}
} else {
consecutiveTaps = 1;
}
lastTap = now;
},
child: \\child);
Relevant solution.
Here is flexible reusable multiple tap widget based on Listener widget that reports raw pointer events:
class AppMultipleTap extends StatefulWidget {
final Widget child;
final VoidCallback onMultipleTap;
final int taps;
final Duration duration;
const AppMultipleTap({
super.key,
required this.child,
required this.onMultipleTap,
/// feel free to override these values
this.taps = 3,
this.duration = const Duration(milliseconds: 600),
});
#override
State<AppMultipleTap> createState() => _AppMultipleTapState();
}
class _AppMultipleTapState extends State<AppMultipleTap> {
/// in _count we store current number of taps
int _count = 0;
Timer? _timer;
#override
Widget build(BuildContext context) {
return Listener(
onPointerDown: (_) {
if (_timer == null) _startTimer();
_count++;
},
child: widget.child,
);
}
void _startTimer() {
_timer = Timer(widget.duration, () {
/// you can change this condition to ==, if you need 100% match
if (_count >= widget.taps) {
widget.onMultipleTap.call();
}
_timer = null;
_count = 0;
});
}
}
Then you can use it like that:
#override
Widget build(BuildContext context) {
return AppMultipleTap(
onMultipleTap: /// Do some action
I like this simple approach, without so many nested if blocks.
// Variables in the state class
var startTap = timeNow;
var consecutiveTaps = 0;
static const int serialTaps = 4;
static const int tapDurationInMs = 1000;
static int get timeNow => DateTime.now().millisecondsSinceEpoch;
// Build method
GestureDetector(
onTap: () {
final now = timeNow;
final userExceededTapDuration = now - startTap > tapDurationInMs;
if (userExceededTapDuration) {
consecutiveTaps = 0;
startTap = now;
}
consecutiveTaps++;
if (consecutiveTaps == serialTaps) {
// widget.onTap();
}
},
);