Listview Builder Navigate to page when onTab - flutter

Using listview builder, I wanted to pass a string variable (userlist[index].page) to each list so that when onTap is pressed it it navigate to that page.
can someone help to fix the code?
this is the code
child: ListTile(
title: Text(
userlist[index].title,
),
trailing: IconButton(
icon: Icon(
alreadySaved ? Icons.star : Icons.star_border,
color: alreadySaved ? Colors.blue : Colors.blue,
),
onPressed: () {
setState(() {
if (alreadySaved) {
usersavedlist.remove(userlist[index]);
} else {
usersavedlist.add(userlist[index]);
}
});
},
), //subtitle: Text(subtitle),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => (userlist[index].page())));
}),

You need to create a page to navigate and pass the item list as a parameter. By example:
class UserDetail extends StatelessWidget {
final User user;
//constructor
UserDetail(this.user);
Widget build(BuildContext context) {
// Return the widget with the user info or whatever you want
return ...
}
}
And in your navitgator you pass like this:
onTap: () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) => UserDetail(userlist[index])));
}),

Related

How to dismiss an AlertDialog in Flutter?

I have a utility class that shows an alert dialog to which I'm passing a VoidCallback which usually contains Navigator.of(context).pop() to dismiss the alert dialog. However it throws a _CastError (Null check operator used on a null value) on button press.
class CustomAlertDialog {
static void show(
BuildContext context, {
Key? key,
required VoidCallback onPress,
}) {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: ElevatedButton(
onPressed: onPress,
child: const Text(
"test",
),
),
),
);
}
}
If I explicitly pass Navigator.pop(context,true) to the onPress method it works just fine, however I need this to be a reusable static method with different onPress functionalities that does more than just pop the dialog.
class CustomAlertDialog {
static void show(
BuildContext context, {
Key? key,
required VoidCallback onPress,
}) {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: ElevatedButton(
onPressed: () {
return Navigator.pop(context, true);
},
child: const Text(
"test",
),
),
),
);
}
}
Your Parent Context does not contain the CustomAlertDialog.
You should pass the context provide by the builder into the onPress function and call navigator.pop with the context provided in the builder function in showDialog.
class CustomAlertDialog {
static void show(
BuildContext context, {
Key? key,
required void Function(BuildContext context) onPress,
}) {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: ElevatedButton(
onPressed: (){ onPress(context) },
child: const Text(
"test",
),
),
),
);
}
}
you can try this :
void show(BuildContext context, String title, {Function callback})
onPressed: () {
if (callback != null) {
Navigator.pop(context, true);
callback();
} else {
Navigator.pop(context, true);
}
},

In flutter, how do I dynamically update an alert dialog's action list?

I am trying to dynamically update an alert dialog's action list when something takes place in the alert dialog. Essentially, by default the dialog has a "Cancel" action button. But once the user does something in the dialog, I want it to have a "Cancel" and an "Accept" button. I have tried using a StatefulBuilder, which is how I am getting the rest of the dialog to update state. However, it is not working with the action buttons.
I've tried conditionally rendering the button, as well as generating a list to use for the dialog actions, and using setState to add to the list when an action takes place. Neither works, although other state updates within the dialog's content work with the StatefulBuilder. The dialog opens with only the "Cancel" action, and will not update to include the "Accept" action as well.
await showDialog<void>(
context: context,
builder: (BuildContext context) {
int? selectedRadio = 0;
return AlertDialog(
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(4, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int? value) {
setState(() => selectedRadio = value);
},
);
}),
actions: <Widget>[
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
selectedRadio == 1 ? TextButton(
child: Text('Accept'),
onPressed: () {
Navigator.of(context).pop();
},
) : SizedBox.Shrink(),
],
);
},
),
);
},
);
Try putting the AlertDialog inside the StatefulBuilder
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
Create a StatefulWidget to display your AlertDialog, and manage selectedRadio there. Also take advantage of Dart's collection if to handle the conditional button:
class MyDialog extends StatefulWidget {
const MyDialog({Key? key}) : super(key: key);
#override
State<MyDialog> createState() => _MyDialogState();
}
class _MyDialogState extends State<MyDialog> {
int selectedRadio = 0;
#override
Widget build(BuildContext context) {
return AlertDialog(
actions: <Widget>[
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
if (selectedRadio == 1)
TextButton(
child: Text('Accept'),
onPressed: () {
Navigator.of(context).pop();
},
)
],
content: Column(
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(4, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int? value) {
setState(() => selectedRadio = value!);
},
);
}),
));
}
}
After this, you can display your dialog for example like this:
TextButton(
child: Text('Pressme'),
onPressed: () async => await showDialog<void>(
context: context,
builder: (BuildContext context) {
return const MyDialog();
},
))

How can I use "showDialog" in order to propagate data backwards in Flutter?

Future<bool> show(BuildContext context) async {
return Platform.isIOS
? await showCupertinoDialog<bool>
(context: context, builder: (context)=>this)
:await showDialog<bool>(
context: context,
builder: (context) => this,
);
}
Can anyone help me to understand the term 'this',what does 'this' refer to and how does showDialog works that it returns Future.I tried to read documentation but still couldn't understand it?Is it the same as AlertDialog widget?
well, it's pretty much what the documentation said, it shows a material dialog above the current content of your app, as for this it passes the current widget as child for the dialog, as for the returned value is just like normal page navigation that when you call pop(context, {value}) method you can also return a value, so that value that inside pop will be returned from the dialog.
here is an example below:
class DialogTest extends StatefulWidget {
#override
_DialogTestState createState() => _DialogTestState();
}
class _DialogTestState extends State<DialogTest> {
// the value that will be typed to the dialog
String dialogText;
// the value that will be returned from the dialog
String returnedFromDialog;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Sample Code'),
),
body: Center(
child:
Text('You got this value from the dialog => $returnedFromDialog'),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
returnedFromDialog = await showDialog<String>(
context: context,
builder: (context) {
return AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
onChanged: (value) => dialogText = value,
),
FlatButton(
onPressed: () {
setState(() => Navigator.pop(context, dialogText));
},
child: Text(
'Close dialog',
style: TextStyle(color: Colors.red),
),
)
],
),
);
});
},
child: Icon(Icons.open_in_browser),
),
);
}
}

close Simple Dialog in flutter when setState needs to called

I'm having a problem calling Navigator.of(context).pop() on my onPressed property in SimpleDialogOption widget. I need to set the state and dismiss the dialog. But calling setState is preventing my dialog to close. Without setState the dialog closes. Here is my dialog
WidgetsBinding.instance.addPostFrameCallback((_) {
showDialog(
builder: (BuildContext context) {
return SimpleDialog(
children: _children(suburbs),
backgroundColor: Colors.white,
title: Text('Pick your suburb'),
);
},
context: context);
});
and the method I use for the list of the Dialog:
List<Widget> _children(List<Suburb> suburbs) {
return suburbs
.map((suburb) => SimpleDialogOption(
onPressed: () {
print('#####################');
setState(() {
postcode = suburb.name;
});
Navigator.of(context).pop();
},
child: Text(suburb.name)))
.toList();
}
you can await until the return value comes from the navigator.pop,
and then call a setState
WidgetsBinding.instance.addPostFrameCallback((_) async {
postcode = await showDialog(
builder: (BuildContext context) {
return SimpleDialog(
children: _children(suburbs),
backgroundColor: Colors.white,
title: Text('Pick your suburb'),
);
},
context: context);
setState(() {
postcode;
});
});
List<Widget> _children(List<Suburb> suburbs) {
return suburbs
.map((suburb) => SimpleDialogOption(
onPressed: () {
print('#####################');
Navigator.of(context).pop(suburb.name);
},
child: Text(suburb.name)))
.toList();
}

how to change icon color immediately after pressed in flutter?

I would like to change the color of an icon after pressing it, but it seems the following code doesn't work.
void actionClickRow(String key) {
Navigator.of(context).push(
new MaterialPageRoute(builder: (context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(key),
actions: <Widget>[
new IconButton(
icon: new Icon(
Icons.favorite,
color: isSaved(key) ? Colors.red : null, //<--- if key is already saved, then set it to red
),
onPressed: ()
{
setState(() //<--whenever icon is pressed, force redraw the widget
{
pressFavorite(key);
});
}
),
],
),
backgroundColor: Colors.teal,
body: _showContent(key));
}),
);
}
void pressFavorite(String key)
{
if (isSaved(key))
saved_.remove(key);
else
saved_.add(key);
}
bool isSaved(String key) {
return saved_.contains(key);
}
Currently, if I press the icon, its color will not change, I have to go back to its parent, then re-enter.
I am wondering how to change its color immediately, Thanks.
update:
class MainPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new MainPageState();
}
}
class MainPageState extends State<MainPage> {
bool _alreadySaved;
void actionRowLevel2(String key) {
_alreadySaved = isSaved(key);
Navigator.of(context).push(
new MaterialPageRoute(builder: (context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(key),
actions: <Widget>[
new IconButton(
icon: new Icon(
_alreadySaved ? Icons.favorite : Icons.favorite_border,
color: _alreadySaved ? Colors.red : null,
),
onPressed: ()
{
setState(()
{
pressFavorite(key);
_alreadySaved = isSaved(key); //<--update alreadSaved
});
}
),
],
),
backgroundColor: Colors.teal,
body: _showScript(key));
}),
);
}
You can simply put a condition for each color :
color:(isPressed) ? Color(0xff007397)
: Color(0xff9A9A9A))
and in the onPressed function :
onPressed: ()
{
setState(()
{
isPressed= true;
});
}
You need to use setState() function. Wherever you are updating your variable values.
For example, I want to update my _newVar value to newValue and this should be updated into the view then instead of writing
_newVar = newValue;
it should be:
setState(() {
_newVar = newValue;
});