I pass a String named "sourceCity" and "destinationCity" to my DropDown widget but when the DropDownValue changed, the String value doesn't automatically changed The new value is only updated inside the DropDownWidget.
add_journey.dart:
class AddJourneyPage extends StatefulWidget {
@override
_AddJourneyPage createState() => _AddJourneyPage();
}
class _AddJourneyPage extends State {
String sourceCity = 'Source City';
String destenationCity = 'Destination City';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Dropdown(sourceCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama']),
Dropdown(destenationCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama']),
ElevatedButton(
onPressed: () {
print(sourceCity);
//it's printing: Source City
print(destenationCity);
//it's printing: Destination City
},
child: const Text('Add Journey'))
],
),
);
}
}
DropDown.dart:
class Dropdown extends StatefulWidget{
final List<String> items;
late String hint;
Color backgroundColor;
Color iconColor;
Color textColor;
double fontSize;
Dropdown(this.hint, this.backgroundColor, this.iconColor, this.textColor, this.fontSize, {super.key, required this.items});
@override
State<StatefulWidget> createState() => DropdownState();
}
class DropdownState extends State<Dropdown>{
String hint="";
@override
void initState() {
hint = widget.hint;
}
@override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
canvasColor: widget.backgroundColor,
),
child: DropdownButton<String>(
hint: Text(hint, style: TextStyle(color: widget.textColor),),
icon: Icon(Icons.arrow_drop_down, color: widget.iconColor),
elevation: 16,
style: TextStyle(color: widget.textColor),
underline: Container(
height: 2,
width: 50,
color: Colors.white,
),
onChanged: (String? newValue) {
setState(() {
hint = newValue!;
});
},
items: widget.items
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value,style: TextStyle(fontSize: widget.fontSize),),
);
}).toList(),
)
);
}
}
How Could I update the passed String when it changed?
CodePudding user response:
Because you use the widget in two different domains, to update the parent widget, you need to use the event when the values of the dropdown list change.
First, define a global function, then
Change your code to the following
typedef CallbackDropDown = void Function(
String newValue);
class AddJourneyPage extends StatefulWidget {
@override
_AddJourneyPage createState() => _AddJourneyPage();
}
class _AddJourneyPage extends State {
String sourceCity = 'Source City';
String destenationCity = 'Destination City';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Dropdown(sourceCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama'],
callbackDropDown:(newValue){
sourceCity = newValue;
}),
Dropdown(destenationCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama'],
callbackDropDown:(newValue){
destenationCity = newValue;
}),
ElevatedButton(
onPressed: () {
print(sourceCity);
//it's printing: Source City
print(destenationCity);
//it's printing: Destination City
},
child: const Text('Add Journey'))
],
),
);
}
}
class Dropdown extends StatefulWidget{
final List<String> items;
final CallbackDropDown callbackDropDown;
late String hint;
Color backgroundColor;
Color iconColor;
Color textColor;
double fontSize;
Dropdown(this.hint, this.backgroundColor, this.iconColor, this.textColor, this.fontSize, {super.key, required this.items, required this.callbackDropDown});
@override
State<StatefulWidget> createState() => DropdownState();
}
class DropdownState extends State<Dropdown>{
String hint="";
@override
void initState() {
hint = widget.hint;
}
@override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
canvasColor: widget.backgroundColor,
),
child: DropdownButton<String>(
hint: Text(hint, style: TextStyle(color: widget.textColor),),
icon: Icon(Icons.arrow_drop_down, color: widget.iconColor),
elevation: 16,
style: TextStyle(color: widget.textColor),
underline: Container(
height: 2,
width: 50,
color: Colors.white,
),
onChanged: (String? newValue) {
setState(() {
hint = newValue!;
widget.callbackDropDown(newValue!);
});
},
items: widget.items
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value,style: TextStyle(fontSize: widget.fontSize),),
);
}).toList(),
)
);
}
}
CodePudding user response:
Change Dropdown
to accept function in constructor:
class Dropdown extends StatefulWidget{
final List<String> items;
late String hint;
Color backgroundColor;
Color iconColor;
Color textColor;
double fontSize;
fined Function(String?) onChange;
Dropdown(this.hint, this.backgroundColor, this.iconColor, this.textColor, this.fontSize, {super.key, required this.items, required this.onChange});
@override
State<StatefulWidget> createState() => DropdownState();
}
and in your DropdownButton
's onChange
do this:
onChanged: (String? newValue) {
widge.onChange(newValue)
},
and finally last change in your AddJourneyPage
class:
Dropdown(sourceCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama'], onChange:(value){
setState(() {
sourceCity = value ?? '';
});
}),