How to customize a DropDownButton - flutter

How to customize the appearance of a DropDownButton?
I would like to do a few things to make the drop down looks like a Text Entry:
remove the bottom line inside the yellow box
indent "Use Email" so it left aligns with "Email Address"
make the drop down the same size as the text box (default size)
put the down arrow close to the right hand side of the drop down
add borders
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.yellow[600],
borderRadius: BorderRadius.circular(4),
),
child: DropdownButton(
value: DropDownValue,
icon: const Icon(Icons.keyboard_arrow_down),
items: DropDownItems.map((String DropDownItems) {
return DropdownMenuItem(
value: DropDownItems,
child: Text(DropDownItems),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
DropDownValue = newValue!;
if (DropDownValue == 'Use Email') {
RegisterType = 'Email';
} else {
RegisterType = 'Mobile';
}
});
},
),
),
SizedBox(height: 10),
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(), labelText: RegisterType),
controller: _EmailAddressController,
),

Try this code:
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.yellow[600],
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(4),
),
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton(
value: DropDownValue,
icon: const Icon(Icons.keyboard_arrow_down),
items: DropDownItems.map((String DropDownItems) {
return DropdownMenuItem(
value: DropDownItems,
child: Text(DropDownItems),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
DropDownValue = newValue!;
if (DropDownValue == 'Use Email') {
RegisterType = 'Email';
} else {
RegisterType = 'Mobile';
}
});
},
),
),
),
),
SizedBox(height: 10),
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(), labelText: RegisterType),
controller: _EmailAddressController,
),

Related

Conditional statement for DropdownButtonFormFields in registeration form

Still a newbie with flutter and was wondering if someone could help me with a problem I'm having. I am trying to create a registeration form with email, password, password confirmation, a county and a zip code. (County and zip code forms are the drop down button form fields) I have successfully coded all else except for the zip code drop down. I would need it to be conditional on the county selection. (In a way that if I select a specific county in cali, it would only display that selected county's zip codes and nothing else). Also if someone would know a quick fix to make the dropdown button form fields empty unless clicked on. My current adaptation on it isn't very functional, since you can just leave the option unanswered, when it's supposed to be mandatory. Thank you in advance :)
Existing code below
(I only have the string for one county zip codes) (Also deleted the irrelevant firebase related code for this post)
class RegisterPage extends StatefulWidget {
const RegisterPage({Key? key}) : super(key: key);
#override
State<RegisterPage> createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
// dropdown area
_MyFormStateArea(){
selectedArea = dropdownListArea[0];
}
var selectedArea = '';
final dropdownListArea = <String>['', 'LA', 'San Francisco'...'Santa Barbara'];
// dropdown zipcode
_MyFormStateZip(){
selectedZip = dropdownListZip[0];
}
var selectedZip = '';
final dropdownListZip = <String>['', '90001', '90002', '90003',..., '91609'];
// editing Controller
final emailEditingController = new TextEditingController();
final passwordEditingController = new TextEditingController();
final confirmPasswordEditingController = new TextEditingController();
#override
Widget build(BuildContext context) {
// email field
final emailField = TextFormField(
autofocus: false,
controller: emailEditingController,
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value!.isEmpty) {
return ("Please enter email.");
}
// reg expression for email validation
if (!RegExp("^[a-zA-Z0-9+_.-]+#[a-zA-Z0-9.-]+.[a-z]")
.hasMatch(value)) {
return ("Please enter a working email.");
}
return null;
},
onSaved: (value) {
emailEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.mail_outline_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Email",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
);
// password field
final passwordField = TextFormField(
autofocus: false,
controller: passwordEditingController,
obscureText: true,
validator: (value) {
RegExp regex = new RegExp(r'^.{6,}$');
if (value!.isEmpty) {
return ("A password required.");
}
if(!regex.hasMatch(value)) {
return ("Please enter other password (Min. 6 characters)");
}
},
onSaved: (value) {
passwordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
));
// confirm password field
final confirmPasswordField = TextFormField(
autofocus: false,
controller: confirmPasswordEditingController,
obscureText: true,
validator: (value)
{
if(confirmPasswordEditingController.text != passwordEditingController.text)
{
return "Passwords don't match";
}
return null;
},
onSaved: (value) {
confirmPasswordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password again",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
);
// area dropdown
final areaField = DropdownButtonFormField(
value: selectedArea,
items: dropdownListArea.map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedArea = value;
}
});
},
decoration: InputDecoration(
labelText: 'County',
prefixIcon: Icon(Icons.location_city_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);
// zip code field
final zipCodeField = DropdownButtonFormField(
value: selectedZip,
items: dropdownListZip.map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedZip = value;
}
});
},
decoration: InputDecoration(
labelText: 'Zip Code',
prefixIcon: Icon(Icons.location_on_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);
// sign up button
final signUpButton = Material(
elevation: 5,
borderRadius: BorderRadius.circular(30),
color: Colors.white,
child: MaterialButton(
padding: EdgeInsets.fromLTRB(20, 15, 20, 15),
minWidth: MediaQuery.of(context).size.width,
onPressed: () {
signUp(emailEditingController.text, passwordEditingController.text);
},
child: Text("Sign Up", textAlign: TextAlign.center,
style: TextStyle(fontSize: 20,
color: Colors.lightBlue[900],
fontWeight: FontWeight.bold)
),
),
);
return Scaffold(
backgroundColor: Color(0xFFAED8E6),
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => FrontPage()));
},
icon: Icon(Icons.arrow_back),
color: Colors.lightBlue[900],
),
),
body: Center(
child: SingleChildScrollView(
child: Container(
color: Color(0xFFAED8E6),
child: Padding(
padding: const EdgeInsets.fromLTRB(36, 20, 36, 30),
child: Form(
key: _formKey,
child:
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 170,
child: Image.asset("assets/AR_logoBold.png",
fit: BoxFit.contain
)),
SizedBox(height: 40,),
emailField,
SizedBox(height: 25,),
passwordField,
SizedBox(height: 25,),
confirmPasswordField,
SizedBox(height: 25,),
areaField,
SizedBox(height: 25,),
zipCodeField,
SizedBox(height: 35,),
signUpButton,
SizedBox(height: 15,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("You already own an account? "),
GestureDetector(onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => LoginPage()));
},
child: Text("Login",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Colors.lightBlue[900])
),)
],
)
],
)),
),
),
),
),
);
}
}
First you should initalize the selectedArea and selectedZip with the first Entry of your List: = dropdownListZip.first and the first entry should not be an empty String
To get only zips that belong to the choosen area you need to know them. At the moment you have two independent lists.
Better you use a map like:
Map<String, List<String>> zipmap = Map('LA': ['9000','9001','9002], 'San Francisco': ['9003', '9004']);
Than you can only display zips that belong to the area quite easy.
Take a look at: Flutter Documentation for Map
Map<String, List<String>> zipmap = Map('LA': ['9000','9001','9002], 'San Francisco': ['9003', '9004']);
final areaField = DropdownButtonFormField(
value: selectedArea,
items: zipmap.keys.toList().map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedArea = value;
}
});
},
decoration: InputDecoration(
labelText: 'County',
prefixIcon: Icon(Icons.location_city_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);
// zip code field
final zipCodeField = DropdownButtonFormField(
value: selectedZip,
items: zipmap[selectedArea].map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedZip = value;
}
});
},
decoration: InputDecoration(
labelText: 'Zip Code',
prefixIcon: Icon(Icons.location_on_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);

Dropdown not showing selected value

DropdownButton(
hint: Text('Select Priority Level', style: GoogleFonts.dosis() ,),
dropdownColor: Colors.blueGrey,
value: selectedValue,
onChanged: (newValue){
setState(() {
selectedValue = newValue;
priority = selectedValue;
});
},
items: listPriority.map((valueItem){
return DropdownMenuItem<String>(
value: valueItem,
child: Text(valueItem),
);
}).toList(),
)
The value selected is stored however when I select an item it does not show in the drop-down field. How can I fix this?
Here is sample code i did
initialize variable
int _selectedjobcategory;
Code
Flexible(
flex: 0,
child: Padding(
padding: EdgeInsets.only(left: 10, right: 10, top: 15),
child: Container(
width: double.infinity,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
border: Border.all(color: Colors.blueGrey)),
child: DropdownButtonFormField(
isExpanded: true,
itemHeight: 50,
icon: Icon(Icons.arrow_drop_down),
iconSize: 40,
// underline: SizedBox(),
hint: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Select Enquiry Type",
style: TextStyle(fontSize: 15, color: Colors.black),
),
),
value: _selectedjobcategory,
onChanged: (newValues) {
setState(() {
_selectedjobcategory = newValues;
});
},
items: jobcategory.map((jobs) {
return DropdownMenuItem(
child: Padding(
padding: const EdgeInsets.all(8.0),
child:
Text(jobs.name, style: TextStyle(fontSize: 15)),
),
value: jobs.id,
);
}).toList(),
),
),
),
),
here's a custom class of dropdown you can call it anywhere
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class DropDownClass extends StatelessWidget {
var _hint;
var _val;
List _list = new List();
bool _border;
Color _underLineColor, _dropDownColor;
List get list => _list;
dynamic Function(dynamic) _listener;
DropDownClass({List list,
var hint,
Color underLineColor,
Color dropDownColor,
Color textColor,
double fontSize,
bool icon,
var val,
int type,
bool border = true,
dynamic Function(dynamic) listener,})
: _list = list,
_hint = hint,
_underLineColor = underLineColor,
_dropDownColor = dropDownColor,
_val = val,
_border = border,
_listener = listener;
#override
Widget build(BuildContext context) {
return DropdownButtonHideUnderline(
child: DropdownButtonFormField<String>(
value: _val,
dropdownColor: _dropDownColor ?? Colors.white,
decoration:_border == true? InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: _underLineColor ?? Theme
.of(context)
.hintColor,
width: 1.0,
),
)
):InputDecoration(
border: InputBorder.none,
fillColor: Colors.grey[400],
filled: true),
isExpanded: true,
hint: Text(_hint),
items: list.map((item) {
return DropdownMenuItem<String>(
value: item,
child: new Text(item,),
);
}).toList(),
onChanged: (value) {
_val = value;
if (_listener != null) _listener.call(value);
// return val;
},
),
);
}
}

How to set initial default value in drop down flutter

I've one drop down and there some value inside the drop-down button and I need to by default selected value. you can seel below piece of snippet where you can find the drop-down value. I need it always there is by default selected value Normal. hope you understand the question.
FormBuilder(
autovalidate: autovalidate,
child: FormBuilderCustomField(
attribute: "Select Address",
validators: [
FormBuilderValidators.required(),
],
formField: FormField(
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
errorText: field.errorText,
filled: false,
isDense: true,
border: InputBorder.none,
icon: Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: colorStyles['primary_light'],
),
child: Icon(
Icons.business_center,
color: colorStyles['primary'],
),
),
),
isEmpty: _typeValue == [],
child: new DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text("Service Type"),
isExpanded: true,
items: [
"normal",
"urgent",
"emergency",
].map((option) {
return DropdownMenuItem(
child: Text("$option"),
value: option,
);
}).toList(),
value: field.value,
onChanged: (value) {
field.didChange(value);
_serviceType = value;
},
),
),
);
},
)),
);
Just Asign on initState()
selectedDropDownValue = "normal";
In DropDown, asign selectedDropDownValue to value, and update on onChanged callback
new DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text("Service Type"),
isExpanded: true,
items: [
"normal",
"urgent",
"emergency",
].map((option) {
return DropdownMenuItem(
child: Text("$option"),
value: option,
);
}).toList(),
value: selectedDropDownValue, //asign the selected value
onChanged: (value) {
setState((){
selectedDropDownValue = value; //on selection, selectedDropDownValue i sUpdated
});
},
),
),
);

Flutter DropdownButton show label when option is selected

Can a Dropdown Button:
return DropdownButton<String>(
items: <String>['Foo', 'Bar'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (_) {},
);
have something similar to a decoration user in a TextFormField:
TextFormField(
controller: _titleController,
decoration: InputDecoration(labelText: 'Input'),
validator: (String value) {
if (value != null && value.isEmpty) {
return 'Please enter some text';
}
},
style: Theme.of(context).textTheme.title,
),
When something is written in the above TextFormField the word Input shows. Like this:
Replace DropdownButton with DropdownButtonFormField:
https://api.flutter.dev/flutter/material/DropdownButtonFormField-class.html
Change DropdownButton to DropdownButtonFormField and add this decoration....
decoration: InputDecoration(
filled: true,
fillColor: Hexcolor('#ecedec'),
labelText: 'Occupation',
border: new CustomBorderTextFieldSkin().getSkin(),
),
Copy Paste and see magic
I have done flutter dropdown with material design
Padding(
padding: const EdgeInsets.all(9.0),
child: InputDecorator(
decoration: InputDecoration(
labelText: 'Priority',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0)),
contentPadding: EdgeInsets.all(10),
),
child: ButtonTheme(
materialTapTargetSize: MaterialTapTargetSize.padded,
child: DropdownButton<String>(
hint: const Text("Priority"),
isExpanded: true,
value: dropdownValue,
elevation: 16,
underline: DropdownButtonHideUnderline(
child: Container(),
),
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(),
),
),
),
),

Catch tap event on TextFormField

I am trying to catch the tap event on TextFormField into a flutter Form.
I use a GestureDetector to do that with the TextFormField as child but nothing is firing when a click on it :
#override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(title: const Text('Recherche de sorties')),
body: new DropdownButtonHideUnderline(
child: new Form(
key: _formKey,
autovalidate: _autovalidate,
child: new ListView(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
children: <Widget>[
new DatePicker(
labelText: 'Date',
selectedDate: widget.request.dateDebut,
initialDate: widget.request.dateDebut,
firstDate: new DateTime.now().add(new Duration(days: -1)),
lastDate: new DateTime.now().add(new Duration(days: 365 * 4)),
selectDate: (DateTime value) {
setState(() {
widget.request.dateDebut = value;
});
},
datePickerMode: DatePickerMode.day,
icon: const Icon(Icons.date_range),
),
new InputDecorator(
decoration: const InputDecoration(
labelText: 'Rayon',
hintText: '-- Choisissez un rayon --',
icon: const Icon(Icons.settings_backup_restore),
),
isEmpty: widget.request.rayon == null,
child: new DropdownButton<String>(
value: widget.request.rayon.toString(),
isDense: true,
onChanged: (String newValue) {
setState(() {
widget.request.rayon = int.parse(newValue);
});
},
items: _rayons.keys.map((int key) {
return new DropdownMenuItem<String>(
value: key.toString(),
child: new Text(_rayons[key]),
);
}).toList(),
),
),
new GestureDetector(
onTap: () async {
print("Container clicked");
Prediction p = await showGooglePlacesAutocomplete(
context: context,
apiKey: Consts.googlePlacesApiKey,
mode: Mode.fullscreen,
language: "fr",
components: [new Component(Component.country, "fr")]);
if (p != null) {
(_scaffoldKey.currentState).showSnackBar(
new SnackBar(content: new Text(p.description)));
}
},
child: new TextFormField(
// controller: controller,
decoration: const InputDecoration(
icon: const Icon(Icons.room),
hintText: 'Où êtes vous ?',
labelText: 'Localisation',
),
),
),
new Container(
padding: const EdgeInsets.all(20.0),
alignment: Alignment.center,
child: new Align(
alignment: const Alignment(0.0, -0.2),
child: new ButtonBar(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new RaisedButton(
child: const Text('ANNULER'),
onPressed: _fermerCritereRecherche,
),
new RaisedButton(
child: const Text('VALIDER'),
onPressed: _valider,
),
],
),
)),
]),
),
),
);
}
If i replace :
new GestureDetector(
onTap: () async {
print("Container clicked");
Prediction p = await showGooglePlacesAutocomplete(
context: context,
apiKey: Consts.googlePlacesApiKey,
mode: Mode.fullscreen,
language: "fr",
components: [new Component(Component.country, "fr")]);
if (p != null) {
(_scaffoldKey.currentState).showSnackBar(
new SnackBar(content: new Text(p.description)));
}
},
child: new TextFormField(
// controller: controller,
decoration: const InputDecoration(
icon: const Icon(Icons.room),
hintText: 'Où êtes vous ?',
labelText: 'Localisation',
),
),
),
By a simple Container it is working :
new GestureDetector(
onTap: () async {
print("Container clicked");
Prediction p = await showGooglePlacesAutocomplete(
context: context,
apiKey: Consts.googlePlacesApiKey,
mode: Mode.fullscreen,
language: "fr",
components: [new Component(Component.country, "fr")]);
if (p != null) {
(_scaffoldKey.currentState).showSnackBar(
new SnackBar(content: new Text(p.description)));
}
},
child: new Container(
width: 80.0,
height: 80.0,
margin: new EdgeInsets.all(10.0),
color: Colors.black),
),
Do you have any ideas how to make GestureDetector work with TextFormField ? Maybe with a controller but i have tried without any success
Thanks in advance
Simply use onTap Method of TextFormField:
TextFormField(
onTap: () {
print("I'm here!!!");
}
)
Wrap TextFormField widget With AbsorbPointer widget , then OnTap() works definitely
here is an example:-
GestureDetector(
onTap: () => dialog(),
child: AbsorbPointer(
child: TextFormField(
textInputAction: TextInputAction.newline,
decoration: new InputDecoration(
fillColor: Colors.grey,
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(6.0)),
borderSide:
BorderSide(color: Colors.grey[100]),
gapPadding: 4),
labelText: "Enter your mood",
labelStyle: TextStyle(
letterSpacing: 1,
color: Colors.grey,
fontSize: 13),
hintMaxLines: 1),
validator: (val) {
if (val == "") return "Field can't be empty";
},
keyboardType: TextInputType.text,
enabled: true,
textAlign: TextAlign.justify,
minLines: 3,
autofocus: false,
style: new TextStyle(
fontSize: 16.0,
color: Colors.black,
),
maxLines: 10,
),
),
),
Wrap AbsorbPointer Widget with Gesture Detector, and then work in onTap(). it will work fine.
I have found a solution by using the InputDecorator (from the flutter gallery) :
child: new InputDecorator(
decoration: const InputDecoration(
labelText: 'Localisation',
icon: const Icon(Icons.room),
),
child: widget.request.localisationLibelle != null
? new Text(widget.request.localisationLibelle)
: new Text("-- Choisissez un lieu --"),
),
Instead of using a TextFormField that catch the tap at the place of the GestureDetector I use a simple child Text of the InputDecorator widget.
I just solved this myself using Flutter 0.6.0.
The GestureDetector object takes in a behavior property from this enum to determine how to defer actions.
Small snippet of the GestureDetector taking priority over a TextFormField:
new GestureDetector(
onTap: onTap,
behavior: HitTestBehavior.opaque,
child: new TextFormField(
enabled: onTap == null,
*other stuff here*
),
)
The onTap object is a Function object I declare outside of this. I also set the enabled property based on my onTap object, so I can ensure that if I want to capture a tap, the text form field is disabled.
onTap function is working but if you use it with InputDecoration { enabled: false }, it will not working.
decoration: InputDecoration(
enabled: false, // not working when on tap
isDense: true,
filled: true,
fillColor: _listRadioItemPosition.isEmpty ? Colors.grey[100] : Colors.white,
border: UnderlineInputBorder(borderSide: BorderSide(color: Color(0xFFC4C4C4), width: 1)),
),
onTap: (){
displayBottomSheetPosition(context);
},