Flutter DropDownbutton not showing selected values - flutter

The dropdown doesn't show it as the chosen one, it just continues as though nothing was selected. Please help me to solve the problem.
I created this custom dropdown widget for multiple usages...
class _AddItemWidgetState extends State<AddItemWidget> {
static const categoryTypes = [
"SL",
"KA",
];
static const subCategoryType = [
"10KG",
"20KG",
"5KG",
];
static const Type = [
"Big Tray",
"Small Tray",
];
String categorySelectedValue;
String subCategorySelectedValue;
String itemType;
Widget categoryFieldWidget(
{String name, List<String> nameList, String selectedValue}) {
return Container(
height: 49,
child: FormField<String>(
builder: (FormFieldState<String> state) {
return InputDecorator(
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 10, right: 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0))),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
icon: Icon(Icons.keyboard_arrow_down),
hint: Text(
name,
),
onChanged: (String newValue) {
setState(() {
selectedValue = newValue;
});
print(selectedValue);
},
value: selectedValue,
isDense: true,
items: nameList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
);
},
),
);
}
Usage:-
But when I use this custom dropdown widget in other widgets, the value is not showing on the Ui.
"categorySelectedValue"'s value changes...but it's not showing on the Ui...
Expanded(
child: categoryFieldWidget(
name: "Category",
nameList: categoryTypes,
selectedValue: categorySelectedValue)),

Just check out this example
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Users'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const categoryTypes = [
"SL",
"KA",
];
static const subCategoryType = [
"10KG",
"20KG",
"5KG",
];
static const itemtype = [
"Big Tray",
"Small Tray",
];
String categorySelectedValue;
String subCategorySelectedValue;
String itemType;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Container(
height: 100,
child: CustomDropDown(
callback: (value) {
print('This is the category callbackValue : $value');
},
name: 'Category',
list: categoryTypes,
selectedValue: categorySelectedValue,
),
),
Container(
height: 100,
child: CustomDropDown(
callback: (value) {
print('This is the subcategory callbackValue : $value');
},
name: 'SubCategory',
list: subCategoryType,
selectedValue: subCategorySelectedValue,
),
),
Container(
height: 100,
child: CustomDropDown(
callback: (value) {
print('This is the type callbackValue : $value');
},
name: 'Type',
list: itemtype,
selectedValue: itemType,
),
),
],
),
),
);
}
}
typedef void StringCallback(String val);
class CustomDropDown extends StatefulWidget {
final StringCallback callback;
final List<String> list;
final String name;
final String selectedValue;
const CustomDropDown(
{Key key, this.list, this.name, this.selectedValue, this.callback})
: super(key: key);
#override
_CustomDropDownState createState() => _CustomDropDownState();
}
class _CustomDropDownState extends State<CustomDropDown> {
List<String> currentList = List();
String name;
String currentSelectedValue;
#override
void initState() {
super.initState();
currentList = widget.list;
name = widget.name;
currentSelectedValue = widget.selectedValue;
}
#override
Widget build(BuildContext context) {
return Container(
height: 49,
child: FormField<String>(
builder: (FormFieldState<String> state) {
return InputDecorator(
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 10, right: 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0))),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
icon: Icon(Icons.keyboard_arrow_down),
hint: Text(
widget.name,
),
onChanged: (String newValue) {
print('This is the value on select $newValue');
setState(() {
currentSelectedValue = newValue;
});
widget.callback(currentSelectedValue);
},
value: currentSelectedValue,
isDense: true,
items: currentList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
);
},
),
);
}
}
Let me know if it works.

Related

Get two different selected values from dropdowbutton from other class _ Flutter or GetX

To organize the code in a Form, I put the "Dropdownbutton" code in a separate class, and I call this class for each dropdown list. Indeed in this case, I have two drop down lists. At the level of the onChange() function, I assign the selected value to the selectedVal variable. So my question is how to access this value and pass it through the form after clicking on the submit button. Can anyone tell me how to solve this problem using Flutter or Getx?!
Thank you in advance.
Class of Form:
class InscriptionView extends StatefulWidget {
const InscriptionView({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return InscriptionViewState();
}
}
class InscriptionViewState extends State<InscriptionView> {
GlobalKey<FormState> formstate2 = GlobalKey();
String? selectedValGender;
String? selectedDiploma;
inscription() async {
print(selectedValGender);
print(selectedDiploma);
//Code
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: const EdgeInsets.all(20),
child: Form(
key: formstate2,
child: Column(children: [
const CustomDropDownButton(
hint: "Gender",
listeItems: ["male", "female"],
icon: Icon(Icons.person),
),
const SizedBox(height: 20),
const CustomDropDownButton(
hint: "Diploma",
listeItems: ["Bachelor", "Master"],
icon: Icon(Icons.school_outlined),
),
const SizedBox(height: 20),
Center(
child: InkWell(
child: const Text("Page de connexion"),
onTap: () async {
await inscription();
},
))
]),
)));
}
}
Class of customise DropDownButton:
class CustomDropDownButton extends StatefulWidget {
final List<String>? listeItems;
final String? hint;
final Widget? icon;
String? selectedGender;
String? selectedDiploma;
const CustomDropDownButton(
{Key? key,
this.listeItems,
this.hint = '',
this.icon})
: super(key: key);
#override
State<CustomDropDownButton> createState() => _CustomDropDownButtonState();
}
class _CustomDropDownButtonState extends State<CustomDropDownButton> {
#override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(50)),
child: DropdownButton<String>(
dropdownColor: const Color.fromARGB(255, 192, 196, 220),
borderRadius: BorderRadius.circular(20),
isExpanded: true,
hint: Text(widget.hint!),
icon: widget.icon,
value: CustomDropDownButton.selectedGender,
items: widget.listeItems!
.map((e) => DropdownMenuItem(
value: e,
child: Text(e),
))
.toList(),
onChanged: (val) {
setState(() {
selectedGender = val!;
});
}),
);
}
}

Open / close filter menu

I have a code that is responsible for building a menu filter. It allows you to filter data by category and then by subcategory.
Initially, subcategories are in a closed state, but when you click on the arrow, they can be opened. Take a look
But my problem is that if I click on the arrow for any category (Country in my case), then all subcategories open at once. Take a look
It's my code
class _FilterDialogUserState extends State<FilterDialogUser> {
Map<String, List<String>?> filters = {};
bool needRefresh = false;
bool isClickedCountry = false;
#override
void initState() {
super.initState();
filters = widget.initialState;
}
List<FilterItem> children = [
FilterItem('Georgia', subitems: [
FilterItem('Tbilisi'),
FilterItem('Batumi'),
]),
FilterItem('Poland', subitems: [
FilterItem('Warsaw'),
FilterItem('Krakow'),
FilterItem('Wroclaw'),
]),
FilterItem('Armenia', subitems: [
FilterItem('Erevan'),
FilterItem('Gyumri'),
]),
];
// Building a dialog box with filters.
#override
Widget build(BuildContext context) {
return SimpleDialog(
title: const Text('Filters',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontFamily: 'SuisseIntl',
)),
contentPadding: const EdgeInsets.all(16),
// Defining parameters for filtering.
children: [
Column(
children: children.map(
(e) {
return Column(
children: [
InkWell(
onTap: () async {
setState(() {
isClickedCountry = !isClickedCountry;
});
},
child: Row(
children: [
Checkbox(
value: e.selected,
onChanged: (value) => setState(() {
e.subitems.forEach((element) =>
element.selected = value as bool);
e.selected = value as bool;
}),
),
Text(e.text),
const Spacer(),
isClickedCountry
? const Icon(Icons.arrow_circle_up)
: const Icon(Icons.arrow_circle_down)
],
),
),
if (e.subitems.isNotEmpty)
!isClickedCountry
? Container()
: Padding(
padding: const EdgeInsets.fromLTRB(30, 0, 0, 0),
child: Column(
children: e.subitems.map((e) {
return Row(children: [
Checkbox(
value: e.selected,
onChanged: (value) => setState(() {
e.selected = value as bool;
}),
),
Text(e.text),
]);
}).toList(),
),
)
],
);
},
).toList(),
),
]);
}
}
class FilterItem {
final String text;
bool selected;
List<FilterItem> subitems;
FilterItem(
this.text, {
this.selected = false,
this.subitems = const [],
});
}
Tell me, is it possible to change my code so that not all subcategories are opened, but only the one that the user clicks on?
The each main filter item must be controlled one by one.
Define List isClickedCountry variable
Save and load state from List isClickedCountry variable
import 'package:flutter/material.dart';
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> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _buildBody() {
return FilterDialogUser();
}
}
class FilterDialogUser extends StatefulWidget {
FilterDialogUser({Key key}) : super(key: key);
#override
State<FilterDialogUser> createState() => _FilterDialogUserState();
}
class _FilterDialogUserState extends State<FilterDialogUser> {
Map<String, List<String>> filters = {};
bool needRefresh = false;
List<bool> isClickedCountry = List.filled(3, false);
#override
void initState() {
super.initState();
// filters = widget.initialState;
}
List<FilterItem> children = [
FilterItem('Georgia', subitems: [
FilterItem('Tbilisi'),
FilterItem('Batumi'),
]),
FilterItem('Poland', subitems: [
FilterItem('Warsaw'),
FilterItem('Krakow'),
FilterItem('Wroclaw'),
]),
FilterItem('Armenia', subitems: [
FilterItem('Erevan'),
FilterItem('Gyumri'),
]),
];
// Building a dialog box with filters.
#override
Widget build(BuildContext context) {
return SimpleDialog(
title: const Text('Filters',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontFamily: 'SuisseIntl',
)),
contentPadding: const EdgeInsets.all(16),
// Defining parameters for filtering.
children: [
Column(
children: children.map(
(e) {
final int index = children.indexOf(e);
return Column(
children: [
InkWell(
onTap: () async {
setState(() {
isClickedCountry[index] = !isClickedCountry[index];
});
},
child: Row(
children: [
Checkbox(
value: e.selected,
onChanged: (value) => setState(() {
e.subitems.forEach((element) =>
element.selected = value as bool);
e.selected = value as bool;
}),
),
Text(e.text),
const Spacer(),
isClickedCountry[index]
? const Icon(Icons.arrow_circle_up)
: const Icon(Icons.arrow_circle_down)
],
),
),
if (e.subitems.isNotEmpty)
!isClickedCountry[index]
? Container()
: Padding(
padding: const EdgeInsets.fromLTRB(30, 0, 0, 0),
child: Column(
children: e.subitems.map((e) {
return Row(children: [
Checkbox(
value: e.selected,
onChanged: (value) => setState(() {
e.selected = value as bool;
}),
),
Text(e.text),
]);
}).toList(),
),
)
],
);
},
).toList(),
),
]);
}
}
class FilterItem {
final String text;
bool selected;
List<FilterItem> subitems;
FilterItem(
this.text, {
this.selected = false,
this.subitems = const [],
});
}

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(),

Flutter - How to implement a Dropdown List using BloC?

I'd like to add a Dropdown list containing "names" in my application instead of a TextField as I have in the code below.
How can I do this using BloC?
class PersonPage extends StatefulWidget {
PersonPage(this.person);
final Person person;
#override
_PersonPageState createState() => _PersonPageState();
}
class Names{
const Item(this.name);
final String name;
}
class _PersonPageState extends State<PersonPage> {
Item selectedUser;
List<Item> names = <Names>[
const Item('Thomas'),
const Item('John'),
const Item('Mary'),
const Item('Lukas'),
];
TextEditingController _nameController;
final _bloc = PersonBloc();
#override
void initState() {
_bloc.setPerson(widget.person);
_nameController = TextEditingController(text: widget.person.name);
super.initState();
}
#override
void dispose() {
_nameController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("MyApp"),
),
body: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
Container(
child: TextField(
decoration: InputDecoration(labelText: "Name"),
controller: _nameController,
onChanged: _bloc.setName,
),
),
Container(
height: 20,
),
RaisedButton(
child: Text("Save"),
onPressed: () {
if (_bloc.insertOrUpdate()) {
Navigator.pop(context);
}
},
)
],
),
),
),
);
}
Thanks.
I'll give to you an example and you try to apply in your code
class _PersonPageState extends State<PersonPage> {
final _bloc = PersonBloc();
#override
void initState() {
_bloc.setPerson(widget.person);
_nameController = TextEditingController(text: widget.person.name);
super.initState();
}
#override
void dispose() {
_nameController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("MyApp"),
),
body: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
StreamBuilder(
stream: bloc.outName,
builder: (context, snapshot) {
if (!snapshot.hasData)
return Container();
return DropdownButton(
hint: Text("Names"),
value: snapshot.data,
items: bloc.names.map((item) {
return DropdownMenuItem(
value: item,
child: Row(children: <Widget>[Text(item),]),
);
}).toList(),
onChanged: bloc.inName,
);
},
),
Container(
height: 20,
),
RaisedButton(
child: Text("Save"),
onPressed: () {
if (_bloc.insertOrUpdate()) {
Navigator.pop(context);
}
},
)
],
),
),
),
);
}
Change your names list to your BLoC, and create the name BehaviorSubject
PersonBloc{
List<String> names = ['Thomas', 'John', 'Mary', 'Lukas'];
final _name = BehaviorSubject<String>.seeded("");
Stream<String> get outName => _name.stream;
Function(String) get inName => _name.sink.add;
//TODO - Don't forget to dispose this _name
}
Now your _name has the selected name, and to get the name, you just need to do
Person.name = _name.stream.value;
This example can be improved, it's just a draft
this is null-safty sample with model:
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const CountryPage(),
);
}
}
class CountryPage extends StatefulWidget {
const CountryPage({Key? key}) : super(key: key);
#override
State<CountryPage> createState() => _CountryPageState();
}
class _CountryPageState extends State<CountryPage> {
final _bloc = CountryBloc();
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("MyApp"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
border: Border.all(width: 1.2, color: Colors.grey)),
child: CustomDropDown(bloc: _bloc),
),
),
);
}
}
class CustomDropDown extends StatelessWidget {
const CustomDropDown({
Key? key,
required CountryBloc bloc,
}) : _bloc = bloc,
super(key: key);
final CountryBloc _bloc;
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: _bloc.streamReference,
builder: (context, snapshot) {
if (!snapshot.hasData) return Container();
return DropdownButton(
isExpanded: true,
hint: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("${_bloc.getCountry.name}"),
),
underline: const SizedBox(),
icon: const Icon(Icons.keyboard_arrow_down, size: 32.0),
items: _bloc.countries.map((item) {
return DropdownMenuItem(
value: item,
child: Directionality(
textDirection: Directionality.of(context).index == 0
? TextDirection.rtl
: TextDirection.ltr,
child: Container(
margin: const EdgeInsets.only(bottom: 4.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
border: Border.all(width: 1.2, color: Colors.grey)),
child: Align(
alignment: AlignmentDirectional.centerStart,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: Text("${item.name}"),
)),
),
),
);
}).toList(),
onChanged: (value) {
_bloc.selectCountry(value as ObjectModel);
},
);
},
);
}
}
class CountryBloc {
List<ObjectModel> countries = [
ObjectModel(id: "0", name: 'USA'),
ObjectModel(id: "1", name: 'CHINA'),
ObjectModel(id: "2", name: 'INDIA'),
ObjectModel(id: "3", name: 'BRAZIL'),
];
final _country = BehaviorSubject<ObjectModel>.seeded(
ObjectModel(id: "-1", name: "Select Country Name.."));
Stream<ObjectModel> get streamReference => _country.stream;
Function(ObjectModel) get selectCountry => _country.sink.add;
ObjectModel get getCountry => _country.value;
void setCountry(ObjectModel country) {
_country.value = country;
}
}
class ObjectModel {
String? id;
String? name;
ObjectModel({this.id, this.name});
ObjectModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
return data;
}
}
add this dependencies to pubspec.yaml file:
flutter_bloc: ^7.1.0
rxdart: ^0.27.5