RadioListTile is not working with setstate - flutter

What is working when i click on radio button it is not changing
class OnBoardingCheckBoxWithActionWidget extends StatefulWidget {
String label;
Function onClick;
OnBoardingCheckBoxWithActionWidget(this.label, {this.onClick});
#override
_OnBoardingCheckBoxWithActionWidgetState createState() =>
_OnBoardingCheckBoxWithActionWidgetState();
}
class _OnBoardingCheckBoxWithActionWidgetState
extends State<OnBoardingCheckBoxWithActionWidget> {
bool checked = true;
#override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: RadioListTile(
value: checked,
groupValue: checked,
toggleable: true,
title: Text("${widget.label}"),
onChanged: (val) {
if (widget.onClick != null) {
widget.onClick(val);
}
setState(() {
print("$checked");
checked = !checked;
print("$checked");
});
},
),
),
); // Card(child: Row(children: [Expanded(child: RadioListTile())],),);
}
}

You're trying to change some value from your Parent Stateful widget.
Try changing your current widget like
class OnBoardingCheckBoxWithActionWidget
extends StatelessWidget {
String label;
Function onClick;
var groupValue;
var buttonValue;
OnBoardingCheckBoxWithActionWidget(this.label, {this.onClick, this.groupValue,, this.buttonValue});
#override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: RadioListTile(
value: buttonValue,
groupValue: groupValue,
toggleable: true,
title: Text("${this.label}"),
onChanged: (val) {
if (this.onClick != null) {
this.onClick(val);
}
},
),
),
); // Card(child: Row(children: [Expanded(child: RadioListTile())],),);
}
}
And then call it like
OnBoardingCheckBoxWithActionWidget("Button1", onClick: (value){
setState((){
///Your Other Code
if(value){
groupValue = 'button1';
}
});
},
groupValue: someGroupValueVariableInState, buttonValue: 'button1')
Note that, the groupValue and buttonValue variables will always be some other variables other than booleans. When groupValue == buttonValue, the corresponding button will automatically marked as checked.

Related

Access data from custom widget created on different class in flutter

I new to Flutter and i was trying to find a solution for the below issue for several hours. I have searched and every solution provided does not work form me.
I have page where one of the widgets is the autocomplete text input. I have created this autocomplete widget on different class. I have added this widget as StatefulBuilder within my main widget. it is working fine however, i am not able to access its value so I can store it with other fields.
My code look like
class ItemDetails extends StatefulWidget {
const ItemDetails({Key? key}) : super(key: key);
static const routeName = '/item_details';
#override
State<ItemDetails> createState() => _ItemDetails();
}
class _ItemDetails extends State<ItemDetails> {
late TextEditingController labelController;
late TextEditingController valueController;
late TextEditingController notesController;
bool _submitted = false;
late var args;
String _itemLabel2 = "";
// var labelAutoComp = LabelSugg();
#override
void initState() {
super.initState();
labelController = TextEditingController();
valueController = TextEditingController();
notesController = TextEditingController();
}
#override
void dispose() {
labelController.dispose();
valueController.dispose();
notesController.dispose();
// Hive.close();
super.dispose();
}
String? _labelErrorText(context) {
final text = labelController.value.text;
if (text.isEmpty) {
// return 'Can\'t be empty';
return AppLocalizations.of(context)!.noEmpty;
}
}
String? _valueErrorText(context) {
final text = valueController.value.text;
if (text.isEmpty) {
// return 'Can\'t be empty';
return AppLocalizations.of(context)!.noEmpty;
}
}
#override
Widget build(BuildContext context) {
try {
args = ModalRoute.of(context)!.settings.arguments as Map;
} on Exception catch (e) {
// print(e);
}
// print(args);
return Scaffold(
appBar: AppBar(
title: Text(args['title']),
),
body: Container(
padding: const EdgeInsets.all(20),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(20),
child: Column(
// mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
LabelSugg(getLabelText: (String val) {
print(val);
_itemLabel2 = val;
}),
TextField(
autofocus: true,
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.label,
hintText: AppLocalizations.of(context)!.labelHint,
errorText:
_submitted ? _labelErrorText(context) : null,
),
controller: labelController,
onChanged: (_) => setState(() {}),
),
const SizedBox(height: 5),
TextField(
autofocus: false,
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.value,
hintText: AppLocalizations.of(context)!.valueHint,
errorText:
_submitted ? _valueErrorText(context) : null,
),
controller: valueController,
keyboardType: const TextInputType.numberWithOptions(
decimal: true, signed: false),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r"[0-9.]")),
TextInputFormatter.withFunction(
(oldValue, newValue) {
try {
final text = newValue.text;
if (text.isNotEmpty) double.parse(text);
return newValue;
} catch (e) {}
return oldValue;
}),
], // Only numbers can be entered
onChanged: (_) => setState(() {}),
),
const SizedBox(height: 5),
TextField(
autofocus: true,
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.notes,
hintText: AppLocalizations.of(context)!.noteHint,
),
controller: notesController,
onChanged: (_) => setState(() {}),
),
]),
// ],
),
Expanded(
child: Align(
alignment: FractionalOffset.bottomCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton.icon(
onPressed: () {
setState(() => _submitted = true);
if (_labelErrorText(context) == null &&
_valueErrorText(context) == null) {
//insert
var localLabel = labelController.value.text;
var _localValue = 0.0;
if (valueController.value.text != '') {
_localValue =
double.parse(valueController.value.text);
} else {
_localValue = 0.0;
}
var localNotes = notesController.value.text;
addItemToList(
localLabel, _localValue, localNotes);
Navigator.of(context).pop();
labelController.clear();
valueController.clear();
notesController.clear();
}
},
label: Text(AppLocalizations.of(context)!.add),
icon: const Icon(Icons.save, size: 18),
),
const SizedBox(width: 10),
ElevatedButton.icon(
onPressed: () => {Navigator.pop(context)},
label: Text(AppLocalizations.of(context)!.cancel),
icon: const Icon(Icons.cancel, size: 18),
),
],
)),
),
// )
],
)));
}
void addItemToList(String localLabel, double localValue, String localNotes) {
var _item = YearItems()..yearID = args['year'];
_item.itemLabel = localLabel;
_item.itemValue = localValue;
_item.itemNote = localNotes;
print(_itemLabel2);
final itemsBox = ItemsBoxes.getTransactions();
itemsBox.add(_item);
}
}
my labelAutoComp widget code look like
class LabelSugg extends StatefulWidget {
final ValueChanged<String> getLabelText;
const LabelSugg({Key? key, required this.getLabelText}) : super(key: key);
#override
State<LabelSugg> createState() => _LabelSugg();
}
class _LabelSugg extends State<LabelSugg> {
late TextEditingController fieldTextEditingController2;
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
getLabel() {
return widget.getLabelText(fieldTextEditingController2.text);
}
#override
Widget build(BuildContext context) {
List<LabelsAc> labelOptions = <LabelsAc>[
LabelsAc(label: AppLocalizations.of(context)!.labelClothes),
LabelsAc(label: AppLocalizations.of(context)!.labelFood),
LabelsAc(label: AppLocalizations.of(context)!.labelPerfumes),
LabelsAc(label: AppLocalizations.of(context)!.labelCapital),
];
return Autocomplete<LabelsAc>(
optionsBuilder: (TextEditingValue textEditingValue) {
return labelOptions
.where((LabelsAc _label) => _label.label
.toLowerCase()
.startsWith(textEditingValue.text.toLowerCase()))
.toList();
},
displayStringForOption: (LabelsAc option) => option.label,
fieldViewBuilder: (BuildContext context,
TextEditingController fieldTextEditingController,
// fieldTextEditingController,
FocusNode fieldFocusNode,
VoidCallback onFieldSubmitted) {
return TextField(
controller: fieldTextEditingController,
focusNode: fieldFocusNode,
style: const TextStyle(fontWeight: FontWeight.bold),
// onChanged: getLabel(),
onChanged: (String val) {
fieldTextEditingController2 = fieldTextEditingController;
getLabel();
});
},
onSelected: (LabelsAc selection) {
fieldTextEditingController2 =
TextEditingController(text: selection.label);
getLabel();
},
optionsViewBuilder: (BuildContext context,
AutocompleteOnSelected<LabelsAc> onSelected,
Iterable<LabelsAc> options) {
return Align(
alignment: Alignment.topLeft,
child: Material(
child: Container(
// width: 350,
// color: Colors.cyan,
child: ListView.builder(
padding: const EdgeInsets.all(10.0),
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final LabelsAc option = options.elementAt(index);
return GestureDetector(
onTap: () {
onSelected(option);
},
child: ListTile(
title: Text(option.label,
style: const TextStyle(color: Colors.black)),
),
);
},
),
),
),
);
},
);
// ),
// );
}
}
class LabelsAc {
LabelsAc({required this.label});
String label;
}
first is redundant when you wrap your class that extend StatefullWidget with StatefullBuilder. LabelSugg is a component Widget. you can use it like other widget.
benefit to separate widget with StatefullWidget class is, we can update the value inside the class without re-build the current page. which is good for performance. that's why developer recomend to separete with class insted compared to make local method.
as you see, when you create LabelSugg extend StatefullWidget class , we will have _LabelSugg . underscore means that: all variable only accessible on current file.
thats why we can't call getLabel() or other variable from different file.
its used for handle the State in 'LabelSugg` widget.
now how to pass the value from LabelSugg is by created variable outside the state. here you are:
class LabelSugg extends StatefulWidget {
// use this to pass any changes when we use LabelSugg
final ValueChanged<String> getLabelText;
const LabelSugg({Key? key, required this.getLabelText}) : super(key: key);
#override
State<LabelSugg> createState() => _LabelSugg();
}
then we can call the onChaged inside _LabelSugg state. because its Statefull widget, we can acces by : widget.getLabelText()
class _LabelSugg extends State<LabelSugg> {
late TextEditingController fieldTextEditingController;
.....
getLabel() {
return widget.getLabelText(fieldTextEditingController.text);
}
then in other class we call LabelSugg like common widget
import 'package:../labelsug.dart';
class ItemDetails extends StatefulWidget {
.....
return Scaffold(
appBar: AppBar(
title: Text(args['title']),
),
body: Container(
padding: const EdgeInsets.all(20),
child: Column(
children: <Widget>[
// now use it like a widget
LabelSug(
getLabelText: (String val){
print(val);
}
:)

TextField widgets lose focus (Flutter)

I am creating an app with Flutter TextField widgets:
class CategoryData {
int? id;
String name;
String description;
CategoryData({this.id, required this.name, required this.description});
}
class CategoriesEdit extends StatefulWidget {
Database? db;
CategoryData? category;
CategoriesEdit({super.key, required this.db, required this.category});
#override
State<StatefulWidget> createState() => CategoriesEditState();
}
class CategoriesEditState extends State<CategoriesEdit> {
CategoryData? category;
void saveState(BuildContext context) {
// ...
}
#override
Widget build(BuildContext context) {
if (category == null) {
setState(() {
category = widget.category ?? CategoryData(name: "", description: "");
});
}
return Scaffold(
appBar: AppBar(
leading: InkWell(
child: const Icon(Icons.arrow_circle_left),
onTap: () => Navigator.pop(context)),
title: const Text("Edit Category"),
),
body: Column(children: [
Column(key: const Key('name'), children: [
const Text("Category name:*"),
TextField(
controller: TextEditingController(text: category!.name),
onChanged: (value) {
setState(() {
category!.name = value;
});
})
]),
Column(key: const Key('description'), children: [
const Text("Description:"),
TextField(
controller: TextEditingController(text: category!.description),
onChanged: (value) {
setState(() {
category!.description = value;
});
})
]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
ElevatedButton(
onPressed: () => saveState(context), // passing false
child: const Text('OK'),
),
OutlinedButton(
onPressed: () => Navigator.pop(context, false),
// passing false
child: const Text('Cancel'),
),
]),
]));
}
}
But after I type a character in one of these two widgets, the cursor moves before the first character and the Android keyboard widget disappears. Why? And how to fix that bug?
I tried adding widget keys, but as you see it didn't help.
There is a lot of things going wrong here, not only the stuff mentioned in the other answer.
Move the setState in the builder into initState:
if (category == null) {
setState(() {
category = widget.category ?? CategoryData(name: "", description: "");
});
}
Don't use setState in the onChanged callback. Change:
onChanged: (value) {
setState(() {
category!.description = value;
});
}
to this:
onChanged: (value) {
category!.description = value;
}
Store the TextEditingControllers, because you have to dispose them once we dispose the state.
If you are already using TextEditingControllers, then you don't need the onChanged callback. Just take text from the controller like explained in the other answer.
You do not have to do
controller: TextEditingController(text: category!.name)
because the controller's text automatically changes once you connect it to TextField.
The reason is once you set some text to the controller, it re-applies the text thus moving the cursor to the front.
I have solved this for you :
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class CategoryData {
int? id;
String name;
String description;
CategoryData({this.id, required this.name, required this.description});
}
class CategoriesEdit extends StatefulWidget {
CategoryData? category;
CategoriesEdit({required this.category});
#override
State<StatefulWidget> createState() => CategoriesEditState();
}
class CategoriesEditState extends State<CategoriesEdit> {
CategoryData? category;
// Database? db;
TextEditingController nametextController = TextEditingController();
TextEditingController descriptionTextController = TextEditingController();
void saveState(BuildContext context) {
// ...
}
#override
Widget build(BuildContext context) {
if (category == null) {
setState(() {
category = widget.category ?? CategoryData(name: "", description: "");
});
}
nametextController.text = category!.name??"";
descriptionTextController.text = category!.description??"";
return Scaffold(
appBar: AppBar(
leading: InkWell(
child: const Icon(Icons.arrow_circle_left),
onTap: () => Navigator.pop(context)),
title: const Text("Edit Category"),
),
body: Column(children: [
Column(key: const Key('name'), children: [
const Text("Category name:*"),
TextField(
controller: nametextController,
onChanged: (value) {
setState(() {
category!.name = value;
});
})
]),
Column(key: const Key('description'), children: [
const Text("Description:"),
TextField(
controller: descriptionTextController,
onChanged: (value) {
setState(() {
category!.description = value;
});
})
]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
ElevatedButton(
onPressed: () => saveState(context), // passing false
child: const Text('OK'),
),
OutlinedButton(
onPressed: () => Navigator.pop(context, false),
// passing false
child: const Text('Cancel'),
),
]),
]));
}
}
I have tested this code and it is working fine, let me know if you have any doubt. Hope this helps you.

"onSaved()" function in TextFormField not being reached (dart/flutter)

I have built a very simple form in flutter and I am trying to save the value of whatever is typed in the form fields to variables. This way, I can push these variables to firebase. However, nothing in the onSaved() block of the TextFormFields is being run. I have called save() on the current state of the form, but it still doesn't seem to work. Any ideas?
I have attached the code for the page below:
import 'package:flutter/material.dart';
class AddJobPage extends StatefulWidget {
const AddJobPage({Key? key}) : super(key: key);
static Future<void> show(BuildContext context) async {
await Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const AddJobPage(),
fullscreenDialog: true
));
}
#override
_AddJobPageState createState() => _AddJobPageState();
}
class _AddJobPageState extends State<AddJobPage> {
final _formKey = GlobalKey<FormState>();
//These two variables are where we will store the values of the text form fields
//before we push to firestore.
String? _name = '';
int _ratePerHour = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 2,
title: const Text("New Job"),
backgroundColor: Colors.teal.shade700,
actions: [
TextButton(
onPressed: _submit,
child: const Text(
'Save',
style: TextStyle(fontSize: 18, color: Colors.white),
)
)
],
),
body: _buildContents(),
backgroundColor: Colors.grey.shade200,
);
}
void _submit() {
if(_validateAndSave()) {
print("form saved, name: $_name, ratePerHour: $_ratePerHour");
}
}
bool _validateAndSave() {
final form = _formKey.currentState;
if(form!.validate()) {
print("the form was saved here");
form.save;
return true;
}
return false;
}
Widget _buildContents() {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: _buildForm(),
),
),
),
);
}
Widget _buildForm() {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _buildFormChildren(),
)
);
}
List<Widget> _buildFormChildren() {
return [
TextFormField(
decoration: const InputDecoration(labelText: 'Job name'),
onSaved: (value) {
print("code doesn't reach here");
_name = value; //save the value of the text field to _name
}
),
TextFormField(
decoration: const InputDecoration(labelText: 'Rate Per Hour'),
keyboardType: const TextInputType.numberWithOptions(
signed: false,
decimal: false
),
onSaved: (value) {
_ratePerHour = int.tryParse(value!) ?? 0;
}
),
];
}
}
You need to call the save function.
So replace form.save; in your code with form.save();
replace form.save with form.save() and you're done. No need to worry about text controllers since you're using a text form field
you need to add a TextEditingController to get the text from a TextFormField. Then you need to call setstate inside OnChanged, not on Onsaved so you can transfer the text to a variable. This is what your code should look like:
First you initialize a controller like this
final TextEditingController textController = TextEditingController();
String _name = "not set";
then you add the controller to your textformfield like this
TextFormField(
controller: textController ,
onChanged:(value)
{
setState(() {
_name = textController.text;
});
} ,
)
This is a complete example:
class TextFormFieldExample extends StatefulWidget {
const TextFormFieldExample({Key? key}) : super(key: key);
#override
_TextFormFieldExampleState createState() => _TextFormFieldExampleState();
}
class _TextFormFieldExampleState extends State<TextFormFieldExample> {
//Create the controller here
final TextEditingController textController = TextEditingController();
String _name = "not set";
#override
Widget build(BuildContext context) {
print(_name);
return Scaffold(
body: Material(
child: Container(
color: Colors.white,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child:TextFormField(
controller: textController ,//Attach the controller to the text form here
onChanged:(value)
{
setState(() {
_name = textController.text;//Save the text from the controller to a variable
});
} ,
),
),
),
);
}
}

in flutter I can not change value from dropdown button

below the StatefulWidget class Customdropdownbutton where I defined the dropdown button
class Customdropdownbutton extends StatefulWidget {
Customdropdownbutton({#required this.defaultValue, #required this.listValue, this.enable});
String defaultValue;
List<String> listValue;
bool enable;
#override
_CustomdropdownbuttonState createState() => _CustomdropdownbuttonState();
}
class _CustomdropdownbuttonState extends State<Customdropdownbutton> {
#override
Widget build(BuildContext context) {
String _valore;
return DropdownButton<String>(
value: widget.defaultValue.isEmpty ? widget.listValue[0] : _valore,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: widget.enable ? (String newValue) {
setState(() {
_valore = newValue;
});
} : null,
items: widget.listValue.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}
below I try to instantiate the class Customdropdownbutton and in UI I see the dropdown button but I can not change the value (the text selected is alwais the widget.listValue[0])
class MyMain extends StatefulWidget {
#override
Widget build(BuildContext context) {
final auth = Provider.of<AuthBase>(context, listen: false);
final String emailMy = auth.currentUser.email;
return scaffold(
.....
body: _buildFormChildren(emailMy),
}
List<Widget> _buildFormChildren(String emailMy) {
List<String> listValue = ['1a', '2b'];
String defaultValue = '1a';
bool enable = true;
return [
**Customdropdownbutton(defaultValue: '', listValue : listValue, enable: true, ),**
],
....
}
}
In the build method of your _CustomdropdownbuttonState, you check if widget.defaultValue is empty (which always is since you're not changing it) and it evaluates widget.listValue[0]. Even if you change _valore, the condition will keep checking if widget.defaultValue is empty. You can do the following:
class _CustomdropdownbuttonState extends State<Customdropdownbutton> {
// Use _valore as a property instead of a local variable
String _valore;
#override
void initState() {
super.initState();
// Use _valore to store the default value
_valore = widget.defaultValue;
}
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
// Check _valore instead of widget.defaultValue
value: _valore.isEmpty ? widget.listValue[0] : _valore,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: widget.enable ? (String newValue) {
setState(() {
_valore = newValue;
});
} : null,
items: widget.listValue.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}

Is it possible in a dropdown button the displayed value to not be in the menu?

I tried to do it but I get an error. I was wondering if there is some kind of loophole.
Also, is there a way for the menu to open below the displayed value?
Here is the code:
import 'package:flutter/material.dart';
import './grile_view.dart';
class Grile extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return GrileState();
}
}
class GrileState extends State<Grile> {
var _bGrile = ['bgrila 1', 'bgrila 2'];
var _bio = 'bgrila 1';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.only(top: 15.0, left: 10.0, right: 10.0),
child: ListView(
children: <Widget>[
// DropdownButton
DropdownButton<String>(
items: _bGrile.map((String dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem)
);
}).toList(),
onChanged: (value){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
GView()));
},
value: _bio
),
// DropdownButton End
]
)
)
);
} // build
} // GrileState
I am new at programming so excuse anything dumb I wrote in the code.
The DropdownButton class contains a very handy hint property. According to the DropdownButton documentation:
If [value] is null and [hint] is non-null, the [hint] widget is
displayed as a placeholder for the dropdown button's value.
What does this mean for you?
All you have to do is add a hint widget to your DropdownButton and then remove the assignment from your dynamic value.
Here's a brief example of a DropdownButton with a hint property:
class DropDownPage extends StatefulWidget {
#override
_DropDownPageState createState() => _DropDownPageState();
}
class _DropDownPageState extends State<DropDownPage> {
int dropdownValue; // Notice how this isn't assigned a value.
#override
Widget build(BuildContext context) {
return Center(
child: DropdownButton(
// Here's the hint property. I used a Text widget,
// but you can use any widget you like
hint: Text("Pick a Widget"),
value: dropdownValue,
items: [
DropdownMenuItem(child: Text("FlatButton"), value: 0),
DropdownMenuItem(child: Text("Container"), value: 1),
DropdownMenuItem(child: Text("Scaffold"), value: 2),
DropdownMenuItem(child: Text("GestureDetector"), value: 3),
],
onChanged: (value) {
setState(() {
dropdownValue = value;
});
},
));
}
}
This is the result:
So in your code, here's what you have to do in your own code.
Edit this: var _bio = 'bgrila 1';
And change it to this: var _bio;
Then add a hint property to your DropdownButton:
DropdownButton<String>(
hint: Text("Pick a *****"), // Replace with your hint widget
items: _bGrile.map((String dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem)
);
}).toList(),
onChanged: (value){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
GView()));
},
value: _bio
),
So that your entire code looks like this:
class Grile extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return GrileState();
}
}
class GrileState extends State<Grile> {
var _bGrile = ['bgrila 1', 'bgrila 2'];
var _bio;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.only(top: 15.0, left: 10.0, right: 10.0),
child: ListView(
children: <Widget>[
// DropdownButton
DropdownButton<String>(
hint: Text("Pick a *******"),
items: _bGrile.map((String dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem)
);
}).toList(),
onChanged: (value){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
GView()));
},
value: _bio
),
// DropdownButton End
]
)
)
);
} // build
} // GrileState