Definitely you should implement a flavor of state management, both for the communication between the pages as well as to feed data to the dropdown menus, and holding on to the selected values from the dropdowns.
My suggestion would be to go with something as simple as the Provider state management strategy, and leverage the widgets that facilitate listening to changes occurring on the application. This strategy makes your app more decouples, maintains a clean separation of concerns and allows for good maintenance.
You can create a Provided service (i.e. DropdownService) that holds to the values of the dropdown menus as a list of dropdown options, as well as two properties that hold on to the selected values from the dropdowns (i.e. selectedFirstOption, selectedSecondOption). Upon triggering changes on both DropDownButton widgets, you can trigger a notification for the widget to rebuild itself, updating its selections, and holding on to the selected value.
A button will trigger the evaluation and navigation to the next page, only if both selectedFirstOption and selectedSecondOption are not null, then the next page also consumes the provided DropdownService, pulls the data persisted for both selections, add the values and displays it to the user.
I threw something together as an example to illustrate my point below:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => DropdownService()
)
],
child: MyApp()
)
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<DropdownService>(
builder: (context, dropdownService, child) {
return Container(
padding: const EdgeInsets.all(30),
child: Column(
children: [
const Text('First dropdown:'),
DropdownButton<DropdownOption>(
value: dropdownService.selectedFirstOption,
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
onChanged: (DropdownOption? newValue) {
dropdownService.selectedFirstOption = newValue!;
},
items: dropdownService.firstDropdown.map((DropdownOption option) {
return DropdownMenuItem<DropdownOption>(
value: option,
child: Text(option.text!),
);
}).toList(),
),
const SizedBox(height: 20),
const Text('Second dropdown:'),
DropdownButton<DropdownOption>(
value: dropdownService.selectedSecondOption,
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
onChanged: (DropdownOption? newValue) {
dropdownService.selectedSecondOption = newValue!;
},
items: dropdownService.secondDropdown.map((DropdownOption option) {
return DropdownMenuItem<DropdownOption>(
value: option,
child: Text(option.text!),
);
}).toList(),
),
const SizedBox(height: 20),
Material(
color: Colors.amber,
child: TextButton(
onPressed: dropdownService.selectedFirstOption != null
&& dropdownService.selectedSecondOption != null ? () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => NextPage())
);
} : null,
child: const Text('Evaluate', style: TextStyle(color: Colors.black)
)
)
)
]
)
);
}
);
}
}
class NextPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
DropdownService dropdownService = Provider.of<DropdownService>(context, listen: false);
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('The result of ${dropdownService.selectedFirstOption!.text!} and ${dropdownService.selectedSecondOption!.text!}:'),
const SizedBox(height: 20),
Text('${dropdownService.selectedFirstOption!.value! + dropdownService.selectedSecondOption!.value!}',
style: const TextStyle(fontSize: 50)
),
],
),
),
);
}
}
class DropdownService extends ChangeNotifier {
List<DropdownOption> firstDropdown = [
DropdownOption(text: 'Value (5)', value: 5),
DropdownOption(text: 'Value (6)', value: 6),
DropdownOption(text: 'Value (7)', value: 7),
];
DropdownOption? _selectedFirstOption; // = DropdownOption(text: 'Select Value', value: -1);
DropdownOption? _selectedSecondOption; // = DropdownOption(text: 'Select Value', value: -1);
DropdownOption? get selectedFirstOption => _selectedFirstOption;
DropdownOption? get selectedSecondOption => _selectedSecondOption;
set selectedFirstOption(DropdownOption? value) {
_selectedFirstOption = value;
notifyListeners();
}
set selectedSecondOption(DropdownOption? value) {
_selectedSecondOption = value;
notifyListeners();
}
List<DropdownOption> secondDropdown = [
DropdownOption(text: 'Value (1)', value: 1),
DropdownOption(text: 'Value (2)', value: 2),
DropdownOption(text: 'Value (3)', value: 3),
];
}
class DropdownOption {
String? text;
double? value;
DropdownOption({ this.text, this.value });
}
If you run this code (also provided as a Gist) through DartPad.dev, you should see the following output:
