how to use 'dropdownbutton'? - flutter

There was an error when I inserted the DropdownButton code into my code.
Outside the code containing the body, they declared it as a class, and when I put the class declared in the code, an error message appeared as below.
'_AssertionError ('package:flutter/src/material/dropdown.dart': Failed assertion: line 890 pos 15: 'items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItem<T> item) {
return item.value == value;
}).length == 1': There should be exactly one item with [DropdownButton]'s value: sex.
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value)'
Below is my code.
.....
....
onChanged: (_) {
setState(() {});
}
),
SelectButton(),
],
),
),
class SelectButtonState extends State<SelectButton> {
final List<String> _valueList = ['M', 'F'];
String _selectedValue = 'sex';
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: _selectedValue,
items: _valueList.map((value) {
return DropdownMenuItem(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedValue = value!;
});
},
);
}
}
class SelectButton extends StatefulWidget {
const SelectButton ({Key? key}) : super(key: key);
#override
State<SelectButton> createState() => SelectButtonState();
}
I want to make sex select button...

Your _valueList contains ['M', 'F'] only and you are creating a DropDownButton out of it. When compiler finds initial value as "Select Sex" which is not available in the _valueList array, you get NULL error.
Solution -> Use 'Select Sex' as dropdown hint. Keep _selectedValue as null in intial declaration so that hint will be displayed.
Setting _selectedValue as null with null check:
String? _selectedValue = null;

Try this one
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: const Scaffold(
body: Center(
child: aa(),
),
),
);
}
}
class aa extends StatefulWidget {
const aa({Key? key}) : super(key: key);
#override
State<aa> createState() => _aaState();
}
class _aaState extends State<aa> {
String selectedNumber = '1';
List numberList = ['1', '2', '3', '4'];
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(8)),
child: DropdownButton(
style: const TextStyle(color: Colors.black),
dropdownColor: Colors.white,
underline: Container(),
value: selectedNumber,
onChanged: (value) {
selectedNumber = value! as String;
setState(() {});
},
items: numberList.map((itemone) {
return DropdownMenuItem(
value: itemone,
child: Center(
child: Text(
itemone,
style: const TextStyle(
color: Colors.black, fontWeight: FontWeight.w700),
),
),
);
}).toList(),
),
);
}
}

Related

How to get Value to update in Flutter DropdownButton from stream?

I'm trying to get a list from my firebase firestore and provide it as a dropdown button, but when the user selects the option it does not update on GUI.
I think the problems is where I instantiate the dropdownValue variable but I don't where else to place it.
class _LocationNameListState extends State<LocationNameList> {
#override
Widget build(BuildContext context) {
List dropdownOptions = <String>[];
String? dropdownValue;
return StreamBuilder(
stream: LocationController().getAllLocations(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text("This is something wrong");
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
for (var i = 0; i < snapshot.data!.docs.length; i++) {
dropdownOptions.add("${snapshot.data!.docs[i]['name']}");
}
print(dropdownOptions);
String dropdownValue = dropdownOptions[0];
return DropdownButton(
items: dropdownOptions
.map((e) => DropdownMenuItem(
value: e,
child: Text(e),
))
.toList(),
onChanged: (value) {
setState(() {
dropdownValue = value.toString();
print(dropdownValue);
});
},
value: dropdownValue,
);
},
);
}
}
The problem is that your dropDown value is set within your Build method:
Widget build(BuildContext context) {
List dropdownOptions = <String>[];
String? dropdown value;
return StreamBuilder(
...
So every setState it gets reset, since the build rebuilds.
To fix the error, move your value outside of the build method:
class _LocationNameListState extends State<LocationNameList> {
// --> Add this variable over here
List dropdownOptions = <String>[];
String? dropdownValue;
#override
Widget build(BuildContext context) {
...
}
I've managed to reproduce your problem with a simplified example. As you see dropdownValue will be reset, since it's within the build method:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(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: MyDropdown(),
),
),
);
}
}
class MyDropdown extends StatefulWidget {
const MyDropdown({Key? key}) : super(key: key);
#override
State<MyDropdown> createState() => _MyDropdownState();
}
class _MyDropdownState extends State<MyDropdown> {
#override
Widget build(BuildContext context) {
String dropdownValue = 'One';
return DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}
And to solve the issue:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(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: MyDropdown(),
),
),
);
}
}
class MyDropdown extends StatefulWidget {
const MyDropdown({Key? key}) : super(key: key);
#override
State<MyDropdown> createState() => _MyDropdownState();
}
class _MyDropdownState extends State<MyDropdown> {
// -->Simply set the value here
String dropdownValue = 'One';
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}
Every time setState is called, build method gets called. It means
String dropdownValue = dropdownOptions[0]; is called as well setting the value of variable to first item of the list.
You need to move dropdownValue to class level variable of your state class.
(String? dropdownValue = null)
Then replace above mentioned line with
if(dropdownValue == null) {
dropdownValue = dropdownOptions[0]
}

The type 'DropDownField' is declared with 0 type parameters, but 1 type arguments were given

Widget locationList(String airportId) {
return Container(
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection("Airports").doc(widget.airportId).collection("Locations").snapshots(),
builder: (context, snapshot) {
if(snapshot.data == null){
return Container();
} else {
List<DropdownMenuItem<String>> locationItem = [];
for(int i=0;i<snapshot.data!.docs.length;i++){
DocumentSnapshot data = snapshot.data!.docs[i];
locationItem.add(
DropdownMenuItem<String>(
child: Text(
data["Location Name"],
),
value: "${data["Location Name"]}",
)
);
}
return Form(
key: _formKey,
child: Container(
alignment: Alignment.center,
height: 55,
width: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.black,width: 2)
),
child: DropdownButtonHideUnderline(
child: DropDownField<DropdownMenuItem<String>>(
value: value,
required: true,
items: locationItem,
enabled: true,
strict: false,
itemsVisibleInDropdown: 5,
onValueChanged: (value) {
setState(() {
this.value = value!;
locationId = value;
** print(value);**
print(locationId);
});
},
),
),
),
);
}
},
),
);
}
You should use "DropdownButton" or "DropdownButtonFormField" instead of "DropDownField".
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatefulWidget(),
),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
String dropdownValue = 'One';
#override
Widget build(BuildContext context) {
return DropdownButtonHideUnderline(
child:DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),);
}
}
This question is old but probably some newbie like me can get help from this answer.
In my case I declared widget as
class CandleStickChartWidget extends StatefulWidget<CandleStikState>
instead of
class CandleStickChartWidget extends StatefulWidget
Correcting to the second line fixed it.

Failed assertion:'items == null || items.isEmpty || value == null || items.where((DropdownMenuItem<T> item) return item.value == value;}).length == 1'

class DropDown extends StatefulWidget {
const DropDown({
this.data,
this.hint,
Key key,
}) : super(key: key);
final List<String> data;
final String hint;
#override
_DropDownState createState() => _DropDownState();
}
String _chosenValue1;
class _DropDownState extends State<DropDown> {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
width: 250,
padding: const EdgeInsets.all(0.0),
child: DropdownButton<String>(
iconSize: 30,
isExpanded: true,
value: _chosenValue1,
//elevation: 5,
items: widget.data.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text(
widget.hint,
style: TextStyle(
color: Colors.black,
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
onChanged: (String value) {
setState(() {
_chosenValue1 = value;
});
},
),
),
);
}
}
DropDown(
data: [
'Non-Blanchable',
'Partial thickness skin',
'Full thickness skin loss involving damage or necrosis',
'Obscured by necrosis'
],
hint: 'Assessment',
),
DropDown(
data: [
'Indistinct, diffuse,none ',
'Distinct,outline clearly'
],
hint: 'Assessment',
),
i have been stuck on this problem for a while now, When i have the same data inside the data it works however all the dropdown would become the same, I want to be able to have different data for different dropdown , but when i do so the error is caused and i cant figure out whats wrong with it
import 'package:flutter/material.dart';
class DropDown extends StatefulWidget {
DropDown({
this.data,
this.hint,
this.initialValue,
Key? key,
}) : super(key: key);
final List<String>? data;
final String? hint;
final String? initialValue;
String chosenValue1 = "";
#override
_DropDownState createState() => _DropDownState();
}
class _DropDownState extends State<DropDown> {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
width: 250,
padding: const EdgeInsets.all(0.0),
child: DropdownButton<String>(
iconSize: 30,
isExpanded: true,
value: widget.initialValue!.isEmpty ? null : widget.initialValue!,
//elevation: 5,
items: widget.data!.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text(
widget.hint!,
style: const TextStyle(
color: Colors.black,
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
onChanged: (value) {
setState(() {
widget.chosenValue1 = value!;
});
},
),
),
);
}
}
import 'package:flutter/material.dart';
import 'dropdown.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropDown(
data: const [
'Non-Blanchable',
'Partial thickness skin',
'Full thickness skin loss involving damage or necrosis',
'Obscured by necrosis'
],
hint: 'Assessment',
initialValue: "Non-Blanchable",
),
DropDown(
data: const [
'Indistinct, diffuse,none',
'Distinct,outline clearly'
],
hint: 'Assessment',
initialValue: "",
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Use the above code it will fix ur error
I tried running your code and, after making your data and hint required params and moving the chosenValue variable inside your _DropDownState, it works perfectly fine. Can you maybe share some steps with how to reproduce the error that you're seeing, because I see two different dropdowns with values I can select independently of each other.
As per your description of how to reproduce the error, I've tried adding navigation between two screens, but it still all works as intended.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Dropdowns(),
);
}
}
class Dropdowns extends StatelessWidget {
const Dropdowns();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(40),
child: Column(
children: [
Text('This is the first screen'),
DropDown(
data: [
'Non-Blanchable',
'Partial thickness skin',
'Full thickness skin loss involving damage or necrosis',
'Obscured by necrosis'
],
hint: 'Assessment',
),
DropDown(
data: ['Indistinct, diffuse,none ', 'Distinct,outline clearly'],
hint: 'Assessment',
),
ElevatedButton(
child: Text('Go to second screen'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondScreen(),
),
);
},
),
],
),
),
);
}
}
class DropDown extends StatefulWidget {
const DropDown({
required this.data,
required this.hint,
Key? key,
}) : super(key: key);
final List<String> data;
final String hint;
#override
_DropDownState createState() => _DropDownState();
}
class _DropDownState extends State<DropDown> {
String? _chosenValue1;
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
width: 250,
padding: const EdgeInsets.all(0.0),
child: DropdownButton<String>(
iconSize: 30,
isExpanded: true,
value: _chosenValue1,
//elevation: 5,
items: widget.data.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text(
widget.hint,
style: TextStyle(
color: Colors.black,
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
onChanged: (String? value) {
setState(() {
_chosenValue1 = value;
});
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
const SecondScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SECOND SCREEN'),
),
body: Padding(
padding: EdgeInsets.all(40),
child: Column(
children: [
Text('This is the second screen'),
DropDown(
data: [
'Non-Blanchable',
'Partial thickness skin',
'Full thickness skin loss involving damage or necrosis',
'Obscured by necrosis'
],
hint: 'Assessment',
),
DropDown(
data: ['Indistinct, diffuse,none ', 'Distinct,outline clearly'],
hint: 'Assessment',
),
],
),
),
);
}
}
onChanged: (String value) {
setState(() {
_chosenValue = value;
selcat = null; use dropdown as category
_chosenValue == null
? Container()
: _chosenValue == "hi"
? _hi()
: _chosenValue == "hello"
? _hello()
: Container(),

How do I make a single DropDownButton widget be used multiple times to save space?

I have a registration form with many DropDownButton fields that take enums in the menu. Currently, I'm making a separate widget for every single button. Is there a way to just make a single widget and then using its parameters to change it?
Is there a better way to do this? Currently, I'm just copy-pasting and renaming it for every DropDownButton I want to create.
class _BloodTypeDropDownFieldState extends State<BloodTypeDropDownField> {
BloodType _currentSelectedValue;
#override
Widget build(BuildContext context) {
return DropdownButtonHideUnderline(
child: DropdownButton<BloodType>(
value: _currentSelectedValue,
hint: Text(
"Blood Group",
style: GoogleFonts.roboto(
textStyle: Theme.of(context).textTheme.headline4,
fontSize: 13,
fontWeight: FontWeight.w700,
color: Color(0xffffffff),
),
),
isDense: true,
onChanged: (BloodType newValue) {
setState(() {
_currentSelectedValue = newValue;
});
},
selectedItemBuilder: (BuildContext context) {
return BloodType.getValues().map((BloodType bloodType) {
return Text(
bloodType.toString(),
style: GoogleFonts.roboto(
textStyle: Theme.of(context).textTheme.headline4,
fontSize: 13,
fontWeight: FontWeight.w700,
color: Color(0xffffffff),
),
);
}).toList();
},
items: BloodType.getValues().map((BloodType bloodType) {
return DropdownMenuItem<BloodType>(
value: bloodType,
child: Text(
bloodType.toString(),
style: GoogleFonts.roboto(
textStyle: Theme.of(context).textTheme.headline4,
fontSize: 15,
fontWeight: FontWeight.w500,
color: Colors.black,
),
),
);
}).toList()
),
);
}
}
class BloodType {
final value;
const BloodType._internal(this.value);
toString() => '$value';
static const A_PLUS = const BloodType._internal('A+');
static const A_MINUS = const BloodType._internal('A-');
static const B_PLUS = const BloodType._internal('B+');
static const B_MINUS = const BloodType._internal('B-');
static const AB_PLUS = const BloodType._internal('AB+');
static const AB_MINUS = const BloodType._internal('AB-');
static const O_PLUS = const BloodType._internal('O+');
static const O_MINUS = const BloodType._internal('O-');
static List<BloodType> list = [
A_PLUS,
A_MINUS,
B_PLUS,
B_MINUS,
AB_PLUS,
AB_MINUS,
O_PLUS,
O_MINUS
];
static List<BloodType> getValues() => list;
}
You could define a generic class for your custom DropDown:
class MyDropDown<T> extends StatelessWidget {
final String hint;
final T value;
final List<T> values;
final ValueChanged<T> onChanged;
MyDropDown({
Key key,
this.hint,
this.value,
#required this.values,
this.onChanged,
}) : assert(values != null),
super(key: key);
#override
Widget build(BuildContext context) {
return DropdownButtonHideUnderline(
child: DropdownButton<T>(
value: value,
hint: Text(hint ?? 'Pick one'),
isDense: true,
onChanged: onChanged,
items: values.map((value) => DropdownMenuItem<T>(
value: value,
child: Text(value.toString()),
))
.toList(),
),
);
}
}
That you can easily use wherever you want:
class HomePage extends HookWidget {
#override
Widget build(BuildContext context) {
final _current = useState<BloodType>();
return Scaffold(
body: Center(
child: MyDropDown<BloodType>(
hint: 'Blood Type',
value: _current.value,
values: bloodTypes,
onChanged: (value) => _current.value = value,
),
),
);
}
}
For whatever type T. Here is an example for your BloodTypes:
enum BloodGroupEnum {
a,
b,
ab,
o,
}
extension BloodGroupEnumX on BloodGroupEnum {
String get label => describeEnum(this).toUpperCase();
}
enum RhdEnum {
positive,
negative,
}
extension RhdEnumX on RhdEnum {
String get label {
switch (this) {
case RhdEnum.positive:
return '+';
case RhdEnum.negative:
return '-';
default:
return '';
}
}
}
class BloodType {
final BloodGroupEnum group;
final RhdEnum rhd;
String toString() => '${group.label}${rhd.label}';
BloodType({
this.group,
this.rhd,
});
}
final List<BloodType> bloodTypes = BloodGroupEnum.values
.map((group) => RhdEnum.values.map((rhd) {
print('NEW');
print(BloodType(group: group, rhd: rhd).toString());
return BloodType(group: group, rhd: rhd);
}).toList())
.expand((i) => i)
.toList();
The only requirement for the class you want to use within MyDropDown is to properly implement toString() that is used as a label for the DropdownMenuItem.
Full source code for easy copy-paste:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:google_fonts/google_fonts.dart';
void main() {
runApp(AppWidget());
}
class AppWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
textTheme: GoogleFonts.robotoTextTheme(
Theme.of(context).textTheme,
),
),
home: HomePage(),
);
}
}
class HomePage extends HookWidget {
#override
Widget build(BuildContext context) {
final _current = useState<BloodType>();
return Scaffold(
body: Center(
child: MyDropDown<BloodType>(
hint: 'Blood Type',
value: _current.value,
values: bloodTypes,
onChanged: (value) => _current.value = value,
),
),
);
}
}
class MyDropDown<T> extends StatelessWidget {
final String hint;
final T value;
final List<T> values;
final ValueChanged<T> onChanged;
MyDropDown({
Key key,
this.hint,
this.value,
#required this.values,
this.onChanged,
}) : assert(values != null),
super(key: key);
#override
Widget build(BuildContext context) {
return DropdownButtonHideUnderline(
child: DropdownButton<T>(
value: value,
hint: Text(hint ?? 'Pick one'),
isDense: true,
onChanged: onChanged,
items: values
.map((value) => DropdownMenuItem<T>(
value: value,
child: Text(value.toString()),
))
.toList(),
),
);
}
}
enum BloodGroupEnum {
a,
b,
ab,
o,
}
extension BloodGroupEnumX on BloodGroupEnum {
String get label => describeEnum(this).toUpperCase();
}
enum RhdEnum {
positive,
negative,
}
extension RhdEnumX on RhdEnum {
String get label {
switch (this) {
case RhdEnum.positive:
return '+';
case RhdEnum.negative:
return '-';
default:
return '';
}
}
}
class BloodType {
final BloodGroupEnum group;
final RhdEnum rhd;
String toString() => '${group.label}${rhd.label}';
BloodType({
this.group,
this.rhd,
});
}
final List<BloodType> bloodTypes = BloodGroupEnum.values
.map((group) =>
RhdEnum.values.map((rhd) => BloodType(group: group, rhd: rhd)).toList())
.expand((i) => i)
.toList();
So I think what you are looking for is to reuse the dropdownbutton I would recommend to use a callback that will give back the type that is selected in the Widget to it's parent. We can use the ValueChanged.
class CustomDropDown extends StatelessWidget {
final ValueChanged<BloodType> onChanged;
final BloodType currentSelectedValue;
const CustomDropDown({Key key, #required this.onChanged, #required this.currentSelectedValue}) : super(key: key);
#override
Widget build(BuildContext context) {
return DropdownButtonHideUnderline(
child: DropdownButton<BloodType>(
value: currentSelectedValue,
hint: Text(
"Blood Group",
style: GoogleFonts.roboto(
textStyle: Theme.of(context).textTheme.headline4,
fontSize: 13,
fontWeight: FontWeight.w700,
color: Color(0xffffffff),
),
),
isDense: true,
onChanged: this.onChanged,
selectedItemBuilder: (BuildContext context) {
return BloodType.getValues().map((BloodType bloodType) {
return Text(
bloodType.toString(),
style: GoogleFonts.roboto(
textStyle: Theme.of(context).textTheme.headline4,
fontSize: 13,
fontWeight: FontWeight.w700,
color: Color(0xffffffff),
),
);
}).toList();
},
items: BloodType.getValues().map((BloodType bloodType) {
return DropdownMenuItem<BloodType>(
value: bloodType,
child: Text(
bloodType.toString(),
style: GoogleFonts.roboto(
textStyle: Theme.of(context).textTheme.headline4,
fontSize: 15,
fontWeight: FontWeight.w500,
color: Colors.black,
),
),
);
}).toList()
Now you can call this widget from anywhere in your app and can be easly reused.
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
BloodType currentSelectedValue;
#override
Widget build(BuildContext context) {
return CustomDropDown(
currentSelectedValue: this.currentSelectedValue,
onChanged: (bloodType){
setState((){
this.currentSelectedValue = bloodType
});
},
);
}
}

Flutter - Get checkbox feedback when modifying in another class

Guys, I created some checkboxes in another class to avoid the refrash when I modify them, but I can't get the check back. Can someone help me?
I will leave the code below ..
on my main page, I call the class containing the checkboxes like this ..
I tried every possible way and I can't get the checkbox value on my main page
**//here I call the click event on my main page**
TipoPagamento(
onChanged: (v) {
setState(() {
print(v);
});
}
),
//**this is where i set up my checkbox.**
import 'package:flutter/material.dart';
class TipoPagamento extends StatefulWidget {
#override
_TipoPagamentoState createState() => _TipoPagamentoState();
final ValueChanged<int> onChanged;
const TipoPagamento({Key key,#required this.onChanged}) : super(key: key);
}
class _TipoPagamentoState extends State<TipoPagamento> {
TextEditingController nameController = TextEditingController();
int _radioValue = 0;
#override
_handleRadioValueChange(int value) {
setState(() {
_radioValue = value;
switch (_radioValue) {
case 1:
break;
case 2:
break;
case 3:
break;
}
});
return(_radioValue);
}
#override
Widget build(BuildContext context) {
return buildTextField();
}
Widget buildTextField() {
return new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Radio(
value: 1,
groupValue: _radioValue,
onChanged: _handleRadioValueChange,
),
new Text(
'Débito',
style: new TextStyle(fontSize: 16.0),
),
new Radio(
value: 2,
groupValue: _radioValue,
onChanged: _handleRadioValueChange,
),
new Text(
'Crédito',
style: new TextStyle(
fontSize: 16.0,
),
),
new Radio(
value: 3,
groupValue: _radioValue,
onChanged: _handleRadioValueChange,
),
new Text(
'Dinheiro',
style: new TextStyle(fontSize: 16.0),
),
],
);
}
}
You can copy paste run full code below
You can call widget.onChanged(_radioValue); in _handleRadioValueChange
code snippet
_handleRadioValueChange(int value) {
setState(() {
_radioValue = value;
switch (_radioValue) {
case 1:
break;
case 2:
break;
case 3:
break;
}
});
widget.onChanged(_radioValue);
return (_radioValue);
}
working demo
output of working demo
I/flutter ( 6880): v 1
I/flutter ( 6880): v 2
full code
import 'package:flutter/material.dart';
class TipoPagamento extends StatefulWidget {
#override
_TipoPagamentoState createState() => _TipoPagamentoState();
final ValueChanged<int> onChanged;
const TipoPagamento({Key key, #required this.onChanged}) : super(key: key);
}
class _TipoPagamentoState extends State<TipoPagamento> {
TextEditingController nameController = TextEditingController();
int _radioValue = 0;
_handleRadioValueChange(int value) {
setState(() {
_radioValue = value;
switch (_radioValue) {
case 1:
break;
case 2:
break;
case 3:
break;
}
});
widget.onChanged(_radioValue);
return (_radioValue);
}
#override
Widget build(BuildContext context) {
return buildTextField();
}
Widget buildTextField() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Radio(
value: 1,
groupValue: _radioValue,
onChanged: _handleRadioValueChange,
),
Text(
'Débito',
style: TextStyle(fontSize: 16.0),
),
Radio(
value: 2,
groupValue: _radioValue,
onChanged: _handleRadioValueChange,
),
Text(
'Crédito',
style: TextStyle(
fontSize: 16.0,
),
),
Radio(
value: 3,
groupValue: _radioValue,
onChanged: _handleRadioValueChange,
),
Text(
'Dinheiro',
style: TextStyle(fontSize: 16.0),
),
],
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TipoPagamento(onChanged: (v) {
setState(() {
print("v $v");
});
}),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}