I'm creating a timer, and it has a play and pause button that changes the text inside the timer, I press "Play" and the timer starts counting, but when I pause, the text on the button and the text inside the timer doesn't change, does anyone know why?
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child: FloatingActionButton.extended(
backgroundColor: Colors.grey[50],
onPressed: () {
if (controller.isAnimating){
controller.stop();
}
else {
controller.reverse(
from: controller.value == 0.0
? 1.0
: controller.value);
}
},
icon: Icon(controller.isAnimating
? Icons.pause
: Icons.play_arrow),
label: Text(
controller.isAnimating ? "Pause" : "Play")),
);
}),
Normal
Couting
Paused
Try call controller.stop(); into a setState
like this:
setState(() {
controller.stop();
});
Related
I have a screen that I'd put all body in an Obx . I have a Row like bellow
Row(
mainAxisSize: MainAxisSize.min,
children: [
Visibility(
visible: !lastController.posts[i].isDownloaded,
child: GestureDetector(
onTap: () async {
lastController.isDownloading.value = true;
await lastController.setPostIsDownloading(i);
await lastController.Download(i);
await lastController.setPostIsDownloading(i);
lastController.isDownloading.value = false;
},
child: lastController.isDownloading.value?
lastController.posts[i].isDownloading?
SizedBox(
height: 22,
width: 22,
child: CircularProgressIndicator(
backgroundColor: Colors.white,
value:lastController.percentage.value,
),
)
: const Icon(
FontAwesome.download,
color: Colors.white,
)
: const Icon(
FontAwesome.download,
color: Colors.white,
),
),
),
const SizedBox(
width: 10.0,
),
Visibility(
.....
),
],
)
and my Controller is like bellow
class LastMonasebatController extends GetxController {
RxList<Posts> posts = <Posts>[].obs;
Future<void> setPostIsDownloading(int id) async {
posts[id].isDownloading = !posts[id].isDownloading;
posts.refresh();
}
Future<void> Download(int id) async {
........
posts[id].isDownloaded = true;
posts.refresh();
}
}
When I tap on GestureDetector the post downloading until end but the icon does not change and after downloading complete when I hot reload the controller icon disappeared because post.isDownloaded is false . This is not change UI Automatically . What is the problem ?
I want Getx to change the UI automatically
RxList needs a manual update when its elements changes, so it updates on Obx, you need to call refresh() on it like this:
Future<void> Download(int id) async {
........
posts[id].isDownloaded = true;
shabs.refresh();
posts.refresh(); // add this
}
this will tell Obx that the RxList is the same object, but its inside elements did change to update.
and this is an assume, but in your code, there are two checks over isDownloading,
// ...
child: lastController.isDownloading.value?
lastController.posts[i].isDownloading?
// ...
maybe you need to check only over the ones that belongs to the posts[i]:
// ...
child: lastController.posts[i].isDownloading?
// ...
I have a list of images, and a function that picks an image from that list randomly:
AssetImage imagePicker() {
Random randomNumberGen = Random();
int index = randomNumberGen.nextInt(bgImgList.length);
return AssetImage(bgImgList[index]);
}
And I want a button that when clicking it will call this function and refresh the screen.
floatingActionButton: FloatingActionButton(
onPressed: () { imagePicker(); },
child: const Text(
'change picture' ,
textAlign: TextAlign.center,
),
The issue is the function is called, but the widget i have is not refreshing so the picture doesn't change
this is the widget code:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Israel Geography'),
centerTitle: true,
backgroundColor: Colors.blue[900],
),
body: Center(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: imagePicker(),
fit: BoxFit.cover
),
),
)
),
floatingActionButton: FloatingActionButton(
onPressed: () { imagePicker(); },
child: const Text(
'change picture' ,
textAlign: TextAlign.center,
),
),
);
}
Technically, you are calling the imagePicker() method twice, and there is also no state that is holding the final picked image.
Also, this makes the screen not static anymore. The displayed image is changing on each button click, so there is dynamic information in your UI now, so you need to convert your Stateless widget into a Stateful one so you can do setState() whenever the visible information changes.
So after converting to Stateful,
your State class should have a variable like
AssetImage pickedImage = AssetImage(...); // a default image
And in your imagePicker() method, you can assign the pickedImage var with the chosen image instead of returning it.
AssetImage imagePicker() {
Random randomNumberGen = Random();
int index = randomNumberGen.nextInt(bgImgList.length);
// this will rebuild your UI
setState(() {
pickedImage = AssetImage(bgImgList[index]);
});
}
And in your widget, instead of this:
image: imagePicker(),
Do this:
image: pickedImage,
And every time on button click, you pick a new image, rebuild the UI because of setState and now pickedImage will be pointing to another image.
You need the state for a random image. StatefulWidget is one way to accomplish that.
class ImagePicker {
static Image random() {
return Image.network('https://picsum.photos/500/300?andom=${DateTime.now().millisecondsSinceEpoch}');
}
}
class ImagePickerWidget extends StatefulWidget {
const ImagePickerWidget();
#override
State<ImagePickerWidget> createState() => _ImagePickerWidgetState();
}
class _ImagePickerWidgetState extends State<ImagePickerWidget> {
Image _random = ImagePicker.random();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: _random),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _random = ImagePicker.random()),
child: const Icon(Icons.refresh),
),
);
}
}
If you want to keep a widget stateless, provider is one way to that. See Simple app state management for details.
In my app/game I have this fan, it turnes around when you click on it, and then keeps going untill you click again. It works fine, with curves.easein etc.
But when ever you try to run it a second time (or any number above 1 for that matter) it skipes the initial start with a curve, and first begins when I run repeat after 2 seconds (so it starts without the desired curve)
Button code:
GestureDetector(
onTap: () {
Duration startStopTime = Duration(seconds: 3);
if(_animating) {
_rotationAnimationController.animateBack(1, duration: startStopTime, curve: Curves.easeOut);
setState(() {});
} else {
_rotationAnimationController.animateTo(1, duration: startStopTime, curve: Curves.easeInCubic);
Future.delayed(startStopTime, () {
_rotationAnimationController.repeat();
});
}
setState(() {
_animating = !_animating;
});
},
child: Padding(
padding: const EdgeInsets.only(top: 70),
child: Container(
color: Colors.blue[300],
width: MediaQuery.of(context).size.width/6*5,
height: MediaQuery.of(context).size.width/6*5,
),
),
),
The fan widget:
IgnorePointer(
child: Container(
child: Transform.rotate(
angle: _animation.value,
child: Image.asset('assets/FanArms.png')
),
),
),
The animation:
var _animating = false;
AnimationController _rotationAnimationController;
Animation<double> _animation;
#override
void initState() {
super.initState();
_rotationAnimationController = AnimationController(
duration: Duration(milliseconds: 2000),
vsync: this,
);
_animation =
Tween<double>(begin: 0, end: 4 * pi ).animate(_rotationAnimationController)
..addListener(() {
setState(() {});
});
}
#override
void dispose() {
_rotationAnimationController.dispose();
super.dispose();
}
Here is a video of my the fan in my app
https://imgur.com/a/wtxFNvL
Right when the fan stoppes, I click on it again, and it takes like 3 seconds before it starts (and that's without the smooth curve)
And yea, my app is wierd, I know :)
Thaks allready :)
I am working on a login system, where i authenticate user by OTP ,Here i want to disable the Resend OTP button for 30 seconds every time the user clicks it and show the time remaining
if you want to have a live counter for showing the user the seconds past you should use stream builder
StreamBuilder(
stream: _timerStream.stream,
builder: (BuildContext ctx,
AsyncSnapshot snapshot) {
return SizedBox(
width: 300,
height: 30,
child:RaisedButton(
textColor: Theme.of(context)
.accentColor,
child: Center(
child:
snapshot.data == 0 ?
Text('send code again')
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(' button will be enable after ${snapshot.hasData ? snapshot.data.toString() : 30} seconds '),
],)
),
onPressed: snapshot.data == 0 ? () {
// your sending code method
_timerStream.sink.add(30);
activeCounter();
} : null,
)
);
},
)
you can find complete code on dartpad.dev with this link
Declare boolean onPressedValue variable with true,
Add Condition in onPressed Parameter.
bool onPressedValue=true;
RaisedButton(
child: Text('OTP'),
onPressed: onPressedValue==true?(){
setState((){
onPressedValue=false;
});
Timer(Duration(seconds: 30),(){
setState((){
onPressedValue=true;
});
});
}:null)
You can try this
Declare a variable call like this globally
bool shouldButtonEnabled=true;
then on click of send OTP button call this method while you other stuff like sending OTP call this method after it
_disabledButton(){
shouldButtonEnabled=false;
Timer(
Duration(seconds: 30),
() => shouldButtonEnabled=true);
}
and when check this bool on resend OTP button like this
onPressed: () {
if(shouldButtonEnabled){
//do your work here
}
}
I have two radio button with value 50 and 100. What I want to do is display the value of active radio button every time I pressed the proceed button.
int selectedRadio;
#override
void initState(){
super.initState();
selectedRadio = 0;
}
void setSelectedRadio(int val){
setState(() {
selectedRadio = val;
});
}
void buttonpressed(){
print(selectedRadio);
}
children: <Widget>[
Text("4 Wheels(100)"),
Radio(
value: 100,
groupValue: selectedRadio,
activeColor: Colors.blue,
onChanged:(val) {
setSelectedRadio(val);
},
),
Text("2 Wheels(50)"),
Radio(
value: 50,
groupValue: selectedRadio,
activeColor: Colors.blue,
onChanged:(val) {
setSelectedRadio(val);
},
),
RaisedButton(
onPressed: buttonpressed,
child: new Text(
"print radio button value",
),
),
]
The code you posted works fine.
To solve your problem try to do these things:
Check if you're not setting some value to selectedRadio inside
build()
In your project directory try running flutter clean
Instead of using hot-reload restart / reinstall the app