I am still new to Flutter. Is there an example of a material dropdown list text field? I saw the example on Material Text Field but I didn't find anywhere in the documentation on how to implement this. Thanks for your help on this.
UPDATED :
Text form field with a dropdown
var _currencies = [
"Food",
"Transport",
"Personal",
"Shopping",
"Medical",
"Rent",
"Movie",
"Salary"
];
FormField<String>(
builder: (FormFieldState<String> state) {
return InputDecorator(
decoration: InputDecoration(
labelStyle: textStyle,
errorStyle: TextStyle(color: Colors.redAccent, fontSize: 16.0),
hintText: 'Please select expense',
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5.0))),
isEmpty: _currentSelectedValue == '',
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: _currentSelectedValue,
isDense: true,
onChanged: (String newValue) {
setState(() {
_currentSelectedValue = newValue;
state.didChange(newValue);
});
},
items: _currencies.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
);
},
)
Hope this helps!
_currencies
variable as well. –
Mendicity You want the DropdownButton or DropdownButtonFormField https://api.flutter.dev/flutter/material/DropdownButton-class.html
and the DropdownMenuItem https://api.flutter.dev/flutter/material/DropdownMenuItem-class.html
return DropdownButtonFormField(
items: categories.map((String category) {
return new DropdownMenuItem(
value: category,
child: Row(
children: <Widget>[
Icon(Icons.star),
Text(category),
],
)
);
}).toList(),
onChanged: (newValue) {
// do other stuff with _category
setState(() => _category = newValue);
},
value: _category,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(10, 20, 10, 20),
filled: true,
fillColor: Colors.grey[200],
hintText: Localization.of(context).category,
errorText: errorSnapshot.data == 0 ? Localization.of(context).categoryEmpty : null),
);
Other answers have fully described what you need, but here is an example that puts it all together, this is a reusable dropdown textfield widget that allows you to specify a list of options of any type (without losing dart's beautiful type system).
class AppDropdownInput<T> extends StatelessWidget {
final String hintText;
final List<T> options;
final T value;
final String Function(T) getLabel;
final void Function(T) onChanged;
AppDropdownInput({
this.hintText = 'Please select an Option',
this.options = const [],
this.getLabel,
this.value,
this.onChanged,
});
@override
Widget build(BuildContext context) {
return FormField<T>(
builder: (FormFieldState<T> state) {
return InputDecorator(
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
horizontal: 20.0, vertical: 15.0),
labelText: hintText,
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(5.0)),
),
isEmpty: value == null || value == '',
child: DropdownButtonHideUnderline(
child: DropdownButton<T>(
value: value,
isDense: true,
onChanged: onChanged,
items: options.map((T value) {
return DropdownMenuItem<T>(
value: value,
child: Text(getLabel(value)),
);
}).toList(),
),
),
);
},
);
}
}
And you may use it like this:
AppDropdownInput(
hintText: "Gender",
options: ["Male", "Female"],
value: gender,
onChanged: (String value) {
setState(() {
gender = value;
// state.didChange(newValue);
});
},
getLabel: (String value) => value,
)
TextEditingController
). That's why I'd recommend to re-write the widget to "Stateful", and update its internal value in onChanged()
property: onChanged: (t) {widget.onChanged(t); setState(() {value = t;});}
–
According Following Jeff Frazier's answer, You can have more customization by using DropdownButton2 or DropdownButtonFormField2 from DropdownButton2 package. It's based on Flutter's core DropdownButton with more options you can customize to your needs.
This answer provide a example using a DropdownButtonFormField
a convenience widget that wraps a DropdownButton widget in a FormField.
Ideal if you are using a Material FormField
I suppose you want a dropdown button wich is also a text field. So I found this video. It explains how to implement this kind of field using this package.
I guess what you are asking as I was searching for the same and came up with this solution.
Take a look at screenshots.
Text Field when focused dropdown appears
Selected item updated in TextField
Here I'm attaching my code:
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:paperbook/Constants/size_config.dart';
import 'package:paperbook/Constants/size_constant.dart';
import '../../../Constants/text_constants.dart';
class CourseDropdownTextField extends StatefulWidget {
const CourseDropdownTextField({super.key, required this.courseController});
final TextEditingController courseController;
@override
State<CourseDropdownTextField> createState() => CourseDropdownTextFieldState();
}
class CourseDropdownTextFieldState extends State<CourseDropdownTextField> {
late TextEditingController courseName;
List<String> dropdownList = <String>[
'One',
'Two',
'Three',
'Four',
'Five',
'Six',
'Seven',
'Eight',
'Nine',
'Ten'
];
final FocusNode _focusNode = FocusNode();
bool _isFocused = false;
void _onFocusChange() {
setState(() {
_isFocused = _focusNode.hasFocus;
});
// Perform your function when the TextField gains focus
if (_isFocused) {
showOverlay();
} else {
hideOverlay();
}
}
OverlayEntry? entry;
final layerLink = LayerLink();
void showOverlay() {
final overlay = Overlay.of(context);
final renderBox = context.findRenderObject() as RenderBox;
final size = renderBox.size;
entry = OverlayEntry(
builder: (context) => Positioned(
width: size.width ,
child: CompositedTransformFollower(
link: layerLink,
showWhenUnlinked: false,
offset: Offset(0, size.height + 10),
child: buildOverlay())
),
);
overlay.insert(entry!);
}
void hideOverlay() {
entry?.remove();
entry = null;
}
Widget buildOverlay() => NotificationListener<OverscrollIndicatorNotification>(
onNotification: (OverscrollIndicatorNotification? notification){
notification!.disallowIndicator();
return true;
},
child: Container(
clipBehavior: Clip.hardEdge,
height: SizeConfig.safeBlockVertical!* 42,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondary,
borderRadius: BorderRadius.circular(15),
),
child: ListView.separated(
padding: const EdgeInsets.all(0),
itemBuilder: (context, index){
return GestureDetector(
onTap: () {
courseName.text = dropdownList[index];
hideOverlay();
_focusNode.unfocus();
},
child: Container(
padding: EdgeInsets.all(mainpadding),
child: DefaultTextStyle(
style: const TextStyle(),
child: Text(
dropdownList[index],
style: GoogleFonts.robotoCondensed(
textStyle: const TextStyle(letterSpacing: 0.4),
fontSize: SizeConfig.safeBlockVertical! * 2.2,
fontWeight: FontWeight.w500,
fontStyle: FontStyle.normal,
color: Colors.grey
),
),
)
),
);
},
separatorBuilder: (context, index) {
return const Divider(
height: 0,
thickness: 3,
);
},
itemCount: dropdownList.length)
),
);
@override
void initState(){
super.initState();
courseName = TextEditingController();
_focusNode.addListener(_onFocusChange);
}
@override
void dispose(){
super.dispose();
courseName.dispose();
_focusNode.removeListener(_onFocusChange);
_focusNode.dispose();
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: layerLink,
child: TextFormField(
keyboardType: TextInputType.none,
readOnly: true,
textInputAction: TextInputAction.next,
decoration: const InputDecoration(
prefixIcon: Icon(Icons.menu_book_rounded),
suffixIcon: Icon(Icons.arrow_drop_down_rounded),
labelText: courseText,
hintText: courseText,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(15))
)
),
controller: courseName,
focusNode: _focusNode,
onChanged: (value) {
widget.courseController.text = value;
},
),
);
}
}
'Dropdown' may not be the correct word that you are using to describe the design of text field referred in your material design example.
Here is how to implement it in Flutter:
import 'package:flutter/material.dart';
void main() {
runApp(TextFieldExample());
}
class TextFieldExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Text Field Example',
home: HomePage(),
theme: ThemeData(
primaryColor: Colors.deepPurple,
accentColor: Colors.white,
),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Text Field Example'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
//Material example
TextField(
decoration: InputDecoration(
filled: true,
hintText: 'Enter text',
labelText: 'Default text field'),
controller: new TextEditingController(),
),
SizedBox(
height: 16.0,
),
//Alternate
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter text',
labelText: 'Text field alternate'),
controller: new TextEditingController(),
),
],
),
),
);
}
}
This sample app contains two different examples of text field design that shrink and expand the associated label.
© 2022 - 2024 — McMap. All rights reserved.