flutter change image onPressed - flutter

I'am trying to change an icon image onPressed here is my code. and based on the selected value before and after onPressed it should be working
Thanks for your help.
IconButton(
onPressed: () {
print(selected);
setState(() {
selected = true;
});
print(selected);
},
icon: CircleAvatar(
backgroundImage: NetworkImage(
'https://lh3.googleusercontent.com/zrvgBfLZl94O6yJ_BlEInCIopvsokkrrrpBmVcByKwLSmacEV6B1P-SJA6eKP84ibOjFpA=s26'),
child: selected == false
? Image.asset(
'assets/images/Icon ionic-ios-heart-empty.png')
: Image.asset(
'assets/images/Icon ionic-ios-heart.png'),
),
),
),

Make sure that your selected boolean is defined outside the Widget build method. Because it seems that it's not changing.
Also try changing selected =true => selected=!selected.
If the print statement is working, then it's most likely that you defined selected under Widget build.
Don't do this:
Widget build(BuildContext context) {
bool selected =false;
return IconButton(...etc
Do this:
bool selected =false;
Widget build(BuildContext context) {
return IconButton(...etc

Related

How to remove ElevatedButton?

I have a question, how do I completely remove the button from the screen? I know that it is possible to disable it using Null, but this does not suit me, because it will still be displayed, albeit in the off state. I would like the button to be completely removed after a few clicks on it, how can I do this?
ElevatedButton(
onPressed: () {
setState(() {
_clickBloc.add(ClickUpdate());
});
},
),
You can wrap ElevatedButton with Visible Widget. And make Visible widget property to false after few clicks.
bool visibleVar = true;
Visibility(
child: ElevatedButton(
onPressed: () {
setState(() {
_clickBloc.add(ClickUpdate());
visibleVar();
});
},
),
visible: visibleVar,
),
void changeVisibility(){
visibleVar = ! visibleVar;
}
You can also use conditional if with a bool like bool showThisWidget = true
if (showThisWidget) ElevatedButton(....)
If it is on child , most child accept null.
child: showThisWidget? ElevatedButton(....) :null
You can use the Visibility Widget to remove the button from the screen like:
bool visible = true;
void makeItUnvisible() {
setState(() {
visible = false;
});
}
Visibility(
visible: visible,
child: ElevatedButton(
onPressed: makeItUnvisible,
child: const Text('Button Text'),
),
),

How can i build a form with one textfield at the time?

I was trying to make a form that shows one field at the time that acomplishes the next things:
When pressing a "next" button, it validates the field and let the user go to the next field if everything is ok.
When the user presses the next button in the keyboard it should do the same.
If possible, a sliding animation between fields.
What i came up with was something like this:
List<Widget> questions = [List of textFieldForm]
int pageCount = 0;
GlobalKey _formKey = GlobalKey<FormState>();
pickSection(pageCount) {
return questions[pageCount];
}
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
pickSection(widget.pageCount),
Container(
child: Row(children: [
Container(
width: screenWidth * 0.4,
child: TextButton(
onPressed: widget.pageCount == 0
? null
: () {
setState(() {
widget.pageCount--;
}),
child: Text("BACK"),
),
),
Container(
width: screenWidth * 0.4,
child: TextButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
if (widget.pageCount == questions.length - 1) {
print("FORM ENDS");
} else {
setState(() {
widget.pageCount++;
});
}
}
},
child: Text("NEXT"),
),
),
])
),
]),
),
}
This way i validate every field when it's index is called since i treat every widget as it's own form, but i couldn't think of a way to implement an animation, or make the field advance using the next button on the keyboard(again, because this treats every field as it's own form).
Please help me figure out how to implement this. Animation is not important but using the next button to advance fields is crucial.
Thanks in advance.
You can achieve this using Visibility widget(which is used to show a widget on condition) and maintaining flags.
bool goToNextField = false;
TextButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
goToNextField = true;
if (widget.pageCount == questions.length - 1) {
print("FORM ENDS");
} else {
setState(() {
widget.pageCount++;
});
}
}
},
And in the next widget use a Visibility widget
Widget nextField () {
return Visibility(
visible: goToNextField,
child :
// what you want to show when next button is pressed
);
}

how to rebuild dialog Widget on changing bool variable state?

im trying to submit form on Dialog and i have a DateTimePicker button and need to make a validation on it also before submitting , what i want to do is showing a text error in case no date picked by changing my own variable "isValid" to false but the UI is not updating , i have to close the dialog and reopen it to see the error text even though i wrapped my column with a StatefulBuilder
my dialog photo here
here is my code
StatefulBuilder(builder: (context, StateSetter setState) {
return isValid == false
? Column(
children: [
ElevatedButton(
onPressed: () {
DateTimePicker(context)
.then((value) => setState(() {
_appointmentDateTime = value;
}));
},
child: Text(getTimeDate())),
Text(
'error',
style: TextStyle(
color: Colors.red, fontSize: 10),
),
],
)
: Column(
children: [
ElevatedButton(
onPressed: () {
DateTimePicker(context)
.then((value) => setState(() {
_appointmentDateTime = value;
}));
},
child: Text(getTimeDate())),
],
);
})
Validating form + toggling the isValid Value is working fine
OutlinedButton(
onPressed: () async {
if (_formKey.currentState.validate() &&
_appointmentDateTime != null) {
String date = DateFormat('yyyy-MM-dd hh:mm')
.format(_appointmentDateTime);
var appointment = Appointment(
patientName: widget.patient.name,
date: date,
hospital: _hospitalController.text,
await FirebaseApi.addPatientAppointment(
widget.patient.id, appointment);
print('Appointment Created ');
_formKey.currentState.reset();
setState(() {
translator = null;
_appointmentDateTime = null;
});
Navigator.pop(context);
}
else {
setState(() {
isValid = !isValid;
});
}
},
child: Text('Add Appointment')),
It can get confusing when writing the code like this when dealing with Dialogs. The setState you are using in the OutlinedButton is not the same as the setState used in the StatefulBuilder. You need to enclose your OutlinedButton inside the StatefulBuilder too. If you ever use a StatefulBuilder inside a stateful widget, it is better to use a different name like e.g setDialogState.
It is even better to create a separate stateful widget class just for your Dialog contents and pass the formKey and anything else than using a StatefulBuilder in this case to avoid confusion.

If statement for checking icon data in Flutter

I am wanting an action to happen when a specific icon is pressed. I am currently trying to do it by getting the icon data information and using an if statement:
child: new CircleButton(
onTap: () {
if(IconData==Icons.control_point){
print("hello");
}
},
iconData: _iconsDaily[index]
),
And I am declaring my icons:
#override
Widget build(BuildContext context) {
List<IconData> _iconsDaily = [
Icons.shopping_cart,
Icons.cake_rounded,
Icons.card_giftcard,
Icons.control_point,
];
However IconData==Icons.control_point are unrelated types and so I am unsure how to compare these. Any help would be appreciated thanks.
If you're trying to check the iconData that belongs to the CircleButton, you should do it like this
child: new CircleButton(
onTap: () {
if( _iconsDaily[index] == Icons.control_point){
print("hello");
}
},
iconData: _iconsDaily[index]
)

Can I use Dismissible without actually dismissing the widget?

I'm trying to make a widget that can be swiped to change the currently playing song in a playlist. I'm trying to mimic how other apps do it by letting the user swipe away the current track and the next one coming in. Dismissible is so close to what I actually want. It has a nice animation and I can easily use the onDismissed function to handle the logic. My issue is that Dismissible actually wants to remove the widget from the tree, which I don't want.
The widget I'm swiping gets updated with a StreamBuilder when the song changes, so being able to swipe away the widget to a new one would be perfect. Can I do this or is there a better widget for my needs?
Here's the widget I'm working on:
class NowPlayingBar extends StatelessWidget {
const NowPlayingBar({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder<ScreenState>(
stream: _screenStateStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
final screenState = snapshot.data;
final queue = screenState.queue;
final mediaItem = screenState.mediaItem;
final state = screenState.playbackState;
final processingState =
state?.processingState ?? AudioProcessingState.none;
final playing = state?.playing ?? false;
if (mediaItem != null) {
return Container(
width: MediaQuery.of(context).size.width,
child: Dismissible(
key: Key("NowPlayingBar"),
onDismissed: (direction) {
switch (direction) {
case DismissDirection.startToEnd:
AudioService.skipToNext();
break;
case DismissDirection.endToStart:
AudioService.skipToPrevious();
break;
default:
throw ("Unsupported swipe direction ${direction.toString()} on NowPlayingBar!");
}
},
child: ListTile(
leading: AlbumImage(itemId: mediaItem.id),
title: mediaItem == null ? null : Text(mediaItem.title),
subtitle: mediaItem == null ? null : Text(mediaItem.album),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (playing)
IconButton(
onPressed: () => AudioService.pause(),
icon: Icon(Icons.pause))
else
IconButton(
onPressed: () => AudioService.play(),
icon: Icon(Icons.play_arrow)),
],
),
),
),
);
} else {
return Container(
width: MediaQuery.of(context).size.width,
child: ListTile(
title: Text("Nothing playing..."),
));
}
} else {
return Container(
width: MediaQuery.of(context).size.width,
// The child below looks pretty stupid but it's actually genius.
// I wanted the NowPlayingBar to stay the same length when it doesn't have data
// but I didn't want to actually use a ListTile to tell the user that.
// I use a ListTile to create a box with the right height, and put whatever I want on top.
// I could just make a container with the length of a ListTile, but that value could change in the future.
child: Stack(
alignment: Alignment.center,
children: [
ListTile(),
Text(
"Nothing Playing...",
style: TextStyle(color: Colors.grey, fontSize: 18),
)
],
));
}
},
);
}
}
Here's the effect that I'm going for (although I want the whole ListTile to get swiped, not just the song name): https://i.imgur.com/ZapzpJS.mp4
This can be done by using the confirmDismiss callback instead of the onDismiss callback. To make sure that the widget never actually gets dismissed, you need to return false at the end of the function.
Dismissible(
confirmDismiss: (direction) {
...
return false;
}
)