I need help here with my code. After extracting the EditButton Widget, the page does not update the edit icon value. Everything is fine without extracting the widget.
Also, is there a Visual Studio Code plugin, or any other simple and easy way to extract the widgets with setstates, listview builders, etc.?
class HomeScreen extends StatefulWidget {
const HomeScreen({
super.key,
});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
late TextEditingController textInputTitle;
late TextEditingController textInputContent;
late TextEditingController textInputAuthor;
@override
void initState() {
textInputTitle = TextEditingController();
textInputContent = TextEditingController();
textInputAuthor = TextEditingController();
super.initState();
}
@override
void dispose() {
textInputTitle.dispose();
textInputContent.dispose();
textInputAuthor.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount: question.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(question[index].animalTitle),
subtitle: Text(question[index].AnimalDetails),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(onPressed: () {}, icon: Icon(Icons.add)),
EditButton(
index: index,
textInputTitle: textInputTitle,
textInputContent: textInputContent),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return AnimalDetails(
questionDetails: question[index],
);
},
),
);
},
);
},
),
],
),
);
}
}
class EditButton extends StatefulWidget {
final int index;
const EditButton({
super.key,
required this.textInputTitle,
required this.textInputContent,
required this.index,
});
final TextEditingController textInputTitle;
final TextEditingController textInputContent;
@override
State<EditButton> createState() => _EditButtonState();
}
class _EditButtonState extends State<EditButton> {
@override
Widget build(BuildContext context) {
return IconButton(
onPressed: () {
showDialog<String>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('AlertDialog Title'),
content: Column(
children: [
TextField(
controller: widget.textInputTitle,
decoration: InputDecoration(
label: Text(question[widget.index].animalTitle)),
),
TextField(
controller: widget.textInputContent,
decoration: InputDecoration(
label: Text(question[widget.index].AnimalDetails)),
),
],
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context, 'Cancel');
},
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
setState(
() {
question[widget.index].animalTitle =
widget.textInputTitle.text;
question[widget.index].AnimalDetails =
widget.textInputContent.text;
},
);
Navigator.pop(context, 'OK');
},
child: const Text('OK'),
),
],
);
},
);
},
icon: Icon(Icons.edit),
);
}
}
I need help here with my code. After extracting the EditButton Widget, the page does not update the edit icon value. Everything is fine without extracting the widget.
Also, is there a Visual Studio Code plugin, or any other simple and easy way to extract the widgets with setstates, listview builders, etc.?
class HomeScreen extends StatefulWidget {
const HomeScreen({
super.key,
});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
late TextEditingController textInputTitle;
late TextEditingController textInputContent;
late TextEditingController textInputAuthor;
@override
void initState() {
textInputTitle = TextEditingController();
textInputContent = TextEditingController();
textInputAuthor = TextEditingController();
super.initState();
}
@override
void dispose() {
textInputTitle.dispose();
textInputContent.dispose();
textInputAuthor.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount: question.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(question[index].animalTitle),
subtitle: Text(question[index].AnimalDetails),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(onPressed: () {}, icon: Icon(Icons.add)),
EditButton(
index: index,
textInputTitle: textInputTitle,
textInputContent: textInputContent),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return AnimalDetails(
questionDetails: question[index],
);
},
),
);
},
);
},
),
],
),
);
}
}
class EditButton extends StatefulWidget {
final int index;
const EditButton({
super.key,
required this.textInputTitle,
required this.textInputContent,
required this.index,
});
final TextEditingController textInputTitle;
final TextEditingController textInputContent;
@override
State<EditButton> createState() => _EditButtonState();
}
class _EditButtonState extends State<EditButton> {
@override
Widget build(BuildContext context) {
return IconButton(
onPressed: () {
showDialog<String>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('AlertDialog Title'),
content: Column(
children: [
TextField(
controller: widget.textInputTitle,
decoration: InputDecoration(
label: Text(question[widget.index].animalTitle)),
),
TextField(
controller: widget.textInputContent,
decoration: InputDecoration(
label: Text(question[widget.index].AnimalDetails)),
),
],
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context, 'Cancel');
},
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
setState(
() {
question[widget.index].animalTitle =
widget.textInputTitle.text;
question[widget.index].AnimalDetails =
widget.textInputContent.text;
},
);
Navigator.pop(context, 'OK');
},
child: const Text('OK'),
),
],
);
},
);
},
icon: Icon(Icons.edit),
);
}
}
The problem is that the HomeScreen
never gets a setState
after the questions are changed. One way to do it is to give the EditButton
the setState
function of the parent. You could do that like this for example
class EditButton extends StatefulWidget {
final int index;
const EditButton({
super.key,
required this.textInputTitle,
required this.textInputContent,
required this.index,
required this.parentSetState,
});
final TextEditingController textInputTitle;
final TextEditingController textInputContent;
final Function (VoidCallback) parentSetState;
@override
State<EditButton> createState() => _EditButtonState();
}
class _EditButtonState extends State<EditButton> {
@override
Widget build(BuildContext context) {
return IconButton(
onPressed: () {
showDialog<String>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('AlertDialog Title'),
content: Column(
children: [
TextField(
controller: widget.textInputTitle,
decoration: InputDecoration(
label: Text(question[widget.index].animalTitle)),
),
TextField(
controller: widget.textInputContent,
decoration: InputDecoration(
label: Text(question[widget.index].AnimalDetails)),
),
],
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context, 'Cancel');
},
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
widget.parentSetState(
() {
question[widget.index].animalTitle =
widget.textInputTitle.text;
question[widget.index].AnimalDetails =
widget.textInputContent.text;
},
);
Navigator.pop(context, 'OK');
},
child: const Text('OK'),
),
],
);
},
);
},
icon: Icon(Icons.edit),
);
}
}
and then where you add the button
EditButton(
index: index,
textInputTitle: textInputTitle,
textInputContent: textInputContent,
parentSetState: setState),
It's probably not the best way to do it, but it should work regardless. Ideally you want to use some state management methods like Provider
. It also seems that question
is a static variable which also isn't the best code practice. But it isn't that easy to simply explain in an answer so you might want to research that by yourself. In any case for a simple application my answer is maybe good enough.