I want my flutter web page display a photo , and change for every 3 seconds to display another photo ..
here is my code
class _contactPageState extends State<contactPage> {
List<String> randomPics= ['profiles/github.png', 'profiles/linkedIn.png', 'profiles/stack.png'];
Timer timer;
var random= Random();
String photo;
#override
void initState() {
photo = randomPics[random.nextInt(randomPics.length)];
openLink = new linksToOpen();
super.initState();
timer = new Timer(new Duration(seconds: 1), ( ){
setState(() {
photo= randomPics[random.nextInt(randomPics.length)];
print('${photo}');
});
});
}
#override
Widget build(BuildContext context) {
Container(
child: Image(image : AssetImage(photo),gaplessPlayback: true,),
width: 400, height: 400,
),
What is the problem with my code ?
Please , can anyone help me !
I did some test and I think this could work for you:
import 'dart:async';
import 'dart:math';
import 'package:flutter/widgets.dart';
class ContactPageState extends StatefulWidget {
ContactPageState({Key key}) : super(key: key);
#override
_ContactPageState createState() => _ContactPageState();
}
class _ContactPageState extends State<ContactPageState> {
List<String> randomPics = ['assets/a.jpg', 'assets/b.jpg', 'assets/c.jpg'];
String photo;
final random = new Random();
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) => configureTimer());
super.initState();
}
configureTimer() {
Timer.periodic(Duration(milliseconds: 3000), (timer) {
final int index = random.nextInt(randomPics.length);
setState(() {
photo = randomPics[index];
debugPrint('Select picture $photo in index $index');
});
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Image(
image: AssetImage(photo != null ? photo : 'assets/a.jpg'),
gaplessPlayback: true,
),
width: 400,
height: 400,
);
}
}
For a quick fix, you need to add function setStatus ... as a callback function so it can call itself infinitely.
void _nextPic(){
setState(() {
photo= randomPics[random.nextInt(randomPics.length)];
print('${photo}');
});
timer = new Timer(new Duration(seconds: 1), _nextPic);
}
This function create another timer after this one is done. So you can just need to create the first timer in initState...
#override
void initState() {
photo = randomPics[random.nextInt(randomPics.length)];
super.initState();
timer = new Timer(new Duration(seconds: 1), _nextPic);
}
For one thing, you will need to specify 3 seconds instead of 1. Another, you may be looking for timer.periodic to have this execute multiple times (until you tell it to stop) instead of a single timer countdown that happens starting from state initialization.
An example, see selected answer here:
Flutter Countdown Timer
Documentation:
https://api.flutter.dev/flutter/dart-async/Timer/Timer.periodic.html
Related
I am developing a flutter app that user click the button and the counter increase by one.
I want to rest the value of the counter to zero after one day.
Can u please tell me is there anyway to achieve that?
Thank you
You can use flutter_cache package
https://pub.dev/packages/flutter_cache/
import 'package:flutter_cache/flutter_cache.dart' as cache;
void main() async {
// create new cache.
cache.remember('key', 'data');
cache.write('key', 'data');
// add Cache lifetime on create
cache.remember('key', 'data', 120);
cache.write('key', 'data', 120);
// load Cache by key
// return `defaultValue` if key not exists
cache.load('key', 'defaultValue');
// destroy single cache by key
cache.destroy('key');
// destroy all cache
cache.clear();
await cache.remember('key', () {
return 'test'; // or logic fetching data from api;
});
// or
await cache.remember('key', () => 'test');
cache.remember('key', 'data', 120); // saved for 2 mins or 120 seconds
cache.write('key', 'data', 120);
// multi depth map datatype.
cache.remember('key', {
'name': 'Ashraf Kamarudin',
'depth2': {
'name': 'depth2',
'depth3': {'name': 'depth3'}
}
});
cache.load('key'); // will return data in map datatype.
}
Is your requirement passive or active? If it is active, you can refer to the following code. If it is passive, you need to poll regularly
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> with WidgetsBindingObserver {
DateTime? _presedDate;
var number = 0;
#override
void initState() {
_presedDate = DateTime.now();
super.initState();
}
#override
void didChangeAppLifecycleState(AppLifecycleState lifeCycle) async {
var _isForeground = (lifeCycle == AppLifecycleState.resumed);
if (_isForeground) checkNumber();
super.didChangeAppLifecycleState(lifeCycle);
}
void checkNumber() {
var currenDate = DateTime.now();
var isToday = DateUtils.isSameDay(_presedDate, currenDate);
if (!isToday) {
number == 0;
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('$number'),
TextButton(
onPressed: () {
number++;
setState(() {});
checkNumber();
},
child: Text('incrementNumber')),
],
),
)));
}
}
I tried to play with boolean input and it worked really nice, but changing number input won't change the animation at all.
I made sure couple of times animation is right, state machine name is correct and input name is correct as well.
I tried changing SMIInput<num>? _hoursInput; into SMIInput<SMINumber>? _hoursInput; and than in casting integer as SMINumber like so: _hoursInput?.value = 100 as SMINumber
I tried using double instead of SMINumber. I tried assigning value with setState and without setState.
I made sure the State Machine Animations are in fact depended on the number value.
Nothing works.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:rive/rive.dart';
/// An example showing how to drive two boolean state machine inputs.
class Eldey extends StatefulWidget {
final Map data;
const Eldey({Key? key, required this.data}) : super(key: key);
#override
_EldeyState createState() => _EldeyState();
}
class _EldeyState extends State<Eldey> {
/// Tracks if the animation is playing by whether controller is running.
bool get isPlaying => _controller?.isActive ?? false;
Artboard? _riveArtboard;
StateMachineController? _controller;
SMIInput<num>? _hoursInput;
#override
void initState() {
super.initState();
// Load the animation file from the bundle, note that you could also
// download this. The RiveFile just expects a list of bytes.
rootBundle.load('assets/animations/testing_3.riv').then(
(data) async {
// Load the RiveFile from the binary data.
final file = RiveFile.import(data);
// The artboard is the root of the animation and gets drawn in the
// Rive widget.
final artboard = file.mainArtboard;
var controller = StateMachineController.fromArtboard(artboard, 'State Machine');
if (controller != null) {
artboard.addController(controller);
_hoursInput = controller.findInput('Hours');
}
setState(() => _riveArtboard = artboard);
},
);
}
#override
Widget build(BuildContext context) {
int time = int.parse(widget.data['ftime'].substring(0,2));
if(time > 9 && time < 17){
setState(() {
_hoursInput?.value = 100.0;
});
}
return Expanded(
child: Center(
child: _riveArtboard == null
? const SizedBox()
: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Rive(
artboard: _riveArtboard!,
),
),
)
);
}
}
How do I create buttons (start, loop) for two images changing?
_start() that load first image then change to second image and end at first image.
_loop() that continues to loop between 2 images.
P/S: Better if we can use time like milliseconds to adjust.
Thank you.
Fallow the code below it will change the images using timer don't forget to edit the images.
class ImageLogo extends StatefulWidget {
const ImageLogo({
Key key,
}) : super(key: key);
#override
_ImageLogoState createState() => _ImageLogoState();
}
class _ImageLogoState extends State<ImageLogo> {
Timer _timer;
int _pos = 0;
List<String> photos = [
images/image1.jpg,
images/image2.jpg
];
#override
void initState() {
_timer =
Timer.periodic(Duration(seconds: 10), (Timer t) {
setState(() {
_pos = (_pos + 1) % photos.length;
});
});
super.initState();
}
#override
void dispose() {
_timer.cancel();
_timer = null;
super.dispose();
}
#override
Widget build(BuildContext context) {
return Image(
width: 12 * SizeConfig.widthMultiplier,
height: 12 * SizeConfig.heightMultiplier,
image: AssetImage(photos[_pos]),
);
}
}
on your main widget use
ImageLogo(),
I'm using a RestartableTimer (subclass of Timer) as a countdown timer, to "kick people out" of a form after a certain duration.
I would like to display the progress of that timer, and I like the idea of a circular progress slowly filling up.
I'm not showing my code because I don't really have anything to show. I have a completely static progress indicator and a working timer, in a widget (stateful or stateless, whichever works best).
I face two issues and this is where I need help for :
I don't know how to check every x milliseconds for the timer progress. How can I do that? I don't need copy-pasta code, but more of "what object / which direction" should I go for?
The timer progress in ticks is not implemented (NotImplementedException) ; is there any way to have an equivalent somewhere else? That object works really well for me, except for that part.
Am I SOL or is there a way to make it?
There's nothing to be implemented in the getter tick, since RestartableTimer is not periodic. What you want is a much more complex thing, and RestartableTimer is not able to help you with that.
First, you need something to control the progress of the CircularProgressIndicator:
class ProgressController {
static const double smoothnessConstant = 250;
final Duration duration;
final Duration tickPeriod;
Timer _timer;
Timer _periodicTimer;
Stream<void> get progressStream => _progressController.stream;
StreamController<void> _progressController = StreamController<void>.broadcast();
Stream<void> get timeoutStream => _timeoutController.stream;
StreamController<void> _timeoutController = StreamController<void>.broadcast();
double get progress => _progress;
double _progress = 0;
ProgressController({#required this.duration})
: assert(duration != null),
tickPeriod = _calculateTickPeriod(duration);
void start() {
_timer = Timer(duration, () {
_cancelTimers();
_setProgressAndNotify(1);
_timeoutController.add(null);
});
_periodicTimer = Timer.periodic(
tickPeriod,
(Timer timer) {
double progress = _calculateProgress(timer);
_setProgressAndNotify(progress);
},
);
}
void restart() {
_cancelTimers();
start();
}
Future<void> dispose() async {
await _cancelStreams();
_cancelTimers();
}
double _calculateProgress(Timer timer) {
double progress = timer.tick / smoothnessConstant;
if (progress > 1) return 1;
if (progress < 0) return 0;
return progress;
}
void _setProgressAndNotify(double value) {
_progress = value;
_progressController.add(null);
}
Future<void> _cancelStreams() async {
if (!_progressController.isClosed) await _progressController.close();
if (!_timeoutController.isClosed) await _timeoutController.close();
}
void _cancelTimers() {
if (_timer?.isActive == true) _timer.cancel();
if (_periodicTimer?.isActive == true) _periodicTimer.cancel();
}
static Duration _calculateTickPeriod(Duration duration) {
double tickPeriodMs = duration.inMilliseconds / smoothnessConstant;
return Duration(milliseconds: tickPeriodMs.toInt());
}
}
Then you can implement a CircularProgressIndicator that listens to the Streams from ProgressController:
class RestartableCircularProgressIndicator extends StatefulWidget {
final ProgressController controller;
final VoidCallback onTimeout;
RestartableCircularProgressIndicator({
Key key,
#required this.controller,
this.onTimeout,
}) : assert(controller != null),
super(key: key);
#override
_RestartableCircularProgressIndicatorState createState() =>
_RestartableCircularProgressIndicatorState();
}
class _RestartableCircularProgressIndicatorState
extends State<RestartableCircularProgressIndicator> {
ProgressController get controller => widget.controller;
VoidCallback get onTimeout => widget.onTimeout;
#override
void initState() {
super.initState();
controller.progressStream.listen((_) => updateState());
controller.timeoutStream.listen((_) => onTimeout());
}
#override
Widget build(BuildContext context) {
return CircularProgressIndicator(
value: controller.progress,
);
}
void updateState() => setState(() {});
}
You can also pass some of the paramers of CircularProgressIndicator to RestartableCircularProgressIndicator, so you can customize it.
A usage example:
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ProgressController controller;
#override
void initState() {
super.initState();
controller = ProgressController(
duration: Duration(seconds: 5),
);
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RestartableCircularProgressIndicator(
controller: controller,
onTimeout: () => print('timeout'),
),
RaisedButton(
onPressed: controller.start,
child: Text('Start'),
),
RaisedButton(
onPressed: controller.restart,
child: Text('Restart'),
),
],
),
),
),
);
}
}
I'll convert this into a library someday, but until then I cannot provide the tests and documentation to this code, so you have to study it if you want to understand what's going on here (I'm sorry...).
I am trying to build a countdown app for special days for example 11 d 2 h 30 m 23s to the new year but I can't reload my state every second so it just shows me the second that I loaded the page I don't know how to dynamically reload the page.
import 'package:flutter/material.dart';
class RopSayac extends StatefulWidget {
_RopSayacState createState() => _RopSayacState();
}
class _RopSayacState extends State<RopSayac> {
var now = DateTime.now().second.toString();
String asd(){
setState(() {
now = DateTime.now().second.toString();
});
return now;
}
#override
Widget build(BuildContext context) {
return Container(
child: new Text(asd()),
);
}
}
This is what I got and it doesn't reload time. I am pretty new on the flutter.
As pskink and Günter mentioned, use a Timer. You can even use the periodic constructor that would fit well your scenario.
Note you don't need the asd() function. When you call setState(), the build method will be called automatically passing the new now property value.
If you want, use initState to set an initial value and, as in this example, setup the Timer.
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(title: 'Timer Periodic Demo', home: RopSayac());
}
}
class RopSayac extends StatefulWidget {
_RopSayacState createState() => _RopSayacState();
}
class _RopSayacState extends State<RopSayac> {
String _now;
Timer _everySecond;
#override
void initState() {
super.initState();
// sets first value
_now = DateTime.now().second.toString();
// defines a timer
_everySecond = Timer.periodic(Duration(seconds: 1), (Timer t) {
setState(() {
_now = DateTime.now().second.toString();
});
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: new Text(_now),
),
);
}
}
This recursive method should be enough for what you want. The seconds set as 1 will keep triggering setState each second, thus refreshing your widget tree.
void _timer() {
Future.delayed(Duration(seconds: 1)).then((_) {
setState(() {
print("1 second closer to NYE!");
// Anything else you want
});
_timer();
});
}
There's this excellent library called timer_builder. I think it'll help you out.
Example from the pub page:
import 'package:timer_builder/timer_builder.dart';
class ClockWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return TimerBuilder.periodic(Duration(seconds: 1), //updates every second
builder: (context) {
return Text("${DateTime.now()}");
}
);
}
}
Here's what I do. In my case I'm polling a webservice in _liveUpdate()
void startUpdates(AppState appState) async {
await new Future.delayed(const Duration(milliseconds: 100));
while (true) {
_liveUpdate();
appState.setState(() {});
await new Future.delayed(const Duration(seconds : 15));
}