I would like to vertically align a DropdownButton right next to a TextField.
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DropdownButton<String>(
...
),
Flexible(
child: TextField(
...
),
),
],
)
The current behavior is:
As you can see, the bottom lines aren't aligned. I guess that's happening due to a differences in height. What would be a good practice to fix that? (I'm guessing not using a fixed height)
My final goal is something like this:
Where both lines and the text of DropdownButton and TextField are vertically aligned.
Hope this helps but I got it working! Key prop that did it for me was setting contentPadding for widgets in row to 0.0
Row(
children: <Widget>[
Flexible(
flex: 2,
child: TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
decoration: InputDecoration(
labelText: 'Width',
contentPadding: EdgeInsets.all(0.0),
),
onChanged: (String newValue) {
_stashItem.width = "$newValue $_widthUnit";
},
)),
Flexible(
flex: 1,
child: DropdownButtonFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.all(0.0)
),
value: _widthUnit,
items: ['cm', 'm', 'in', 'ft', 'yd']
.map((String unit) =>
DropdownMenuItem<String>(
value: unit, child: Text(unit)))
.toList(),
onChanged: (value) => setState(() {
_widthUnit = value;
})),
)
],
),
A bit late, but I had the same issue albeit with a slightly different layout:
I used TextFormField rather than TextField.
I used DropdownButtonFormField rather than DropDownButton.
Both fields were wrapped in Flexible widgets within the Row, with mainAxisSize set to MainAxisSize.min.
My text field was laid out to the left of the dropdown.
That being said, setting crossAxisAlignment to CrossAxisAlignment.end worked for me.
Try this:
Row(
mainAxisSize: MainAxisSize.min, // see 3
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Flexible( // see 3
child: DropdownButtonFormField<String>( // see 2
...
),
),
Flexible(
child: TextFormField( // see 1
...
),
),
],
)
I am not sure whether this solution helps you or not, but I think its better than using row.
TextField(
decoration: InputDecoration(
prefix: DropdownButton(underline: Container(), ...)
),
)
Try this:
Row(
Row(mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end
children: <Widget>[
Expanded(
flex: 1
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<String>(
...
))),
Expanded(
flex: 6
child: TextField(
...
),
),
],
)
Try this:
Container(
decoration: BoxDecoration(
border: Border(
//TODO: Customize the underline here
bottom: BorderSide(
color: Colors.white70,
width: 0.5,
),
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
DropdownButton<String>(
onChanged: (c) {},
underline: Container(),
items: [
DropdownMenuItem<String>(
child: Text('Email'),
)
],
),
Flexible(
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
),
),
),
],
),
),
I ended up editing the padding of the TextField's content, and used CrossAxisAlignment.center instead of CrossAxisAlignment.start:
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
DropdownButton<String>(
...
),
Flexible(
child: TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.all(6.0),
),
),
),
],
)
Result:
(You see space between them due to a SizedBox added)
You can simply decrease contentPadding in InputDecoration of DropdownButtonFormField
Related
I am writing a widgets for taking input email address.
But I am getting the error bottom overflowed by infinity pixels.
This is the code.
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: space_8,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(space_2),
color: widgetBackGroundColor
),
child: SizedBox(
height: space_8,
child: TextFormField(
controller: controller,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: "example#gmail.com",
),
),
)
)
],
),
);
Try under your Scaffold:
resizeToAvoidBottomInset: false;
and you can wrap you Column with SingleChildScrollView
Wrap your Container with Expanded widget
return SafeArea(child:Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(child:
Container(
height: space_8,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(space_2),
color: widgetBackGroundColor
),
child: SizedBox(
height: space_8,
child: TextFormField(
controller: controller,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: "example#gmail.com",
),
),
)
))
],
),
));
space_8 > size.height.
Your Column children (which is the container with space_8 height) are larger than the available device height (with keyboard open or otherwise).
Consider using SingleChildScrollView (as #fotis_psarris said) if you cannot decrease the height of children.
Or else decrease height of each child or use Flexible/Expanded as per your usecase.
I just wanted to show the suffixIcon after the suffixText.
Now I know that in the InputDecoration documentation says explicitly that it will show the suffixText before the suffixIcon.
What would I like to do is:
the '*' represents that it's a mandatory field.
And I'm getting this :
is there a way for me to change the order of the suffixes in my TextField?
I tried using SizedBox, or Container widgets but never got the result I wanted.
You can use suffix (edit: suffixIcon) property and pass in a Row widget instead. Put both elements in the Row, and you can decide exactly how you want them to appear. For example:
Soure code:
TextField(
decoration: InputDecoration(
suffixIcon: Row(
mainAxisSize: MainAxisSize.min, // <-- important
children: const [
Icon(Icons.visibility, color: Colors.grey),
SizedBox(width: 4), // add a small gap
Text('*'), // second element
],
),
),
)
Try below code, use Row() widget for suffixIcon
TextField(
decoration: InputDecoration(
suffix: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Icon(
Icons.visibility,
color: Colors.green,
),
SizedBox(width: 5),
Text(
'*',
style: TextStyle(
color: Colors.red,
),
),
],
),
),
),
Your result screen->
You can modify your suffixIcon property to:
suffixIcon: Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(Icons.remove_red_eye),
Text(
"*",
style: TextStyle(color: Colors.red),
)
],
),
),
The alignments here are important to maintain.
So, I'm trying to get a numerical input for a price range set up. And yet no matter what I do from looking elsewhere, when I run it, the body is blank. Here's what I'm trying to get it to look like: price input range
And here's my code for it:
Align(
alignment: Alignment.centerLeft,
child: Container(
color: Color(0xFFffffff),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Text(
'\$',
),
TextField(
controller: _textFieldController,
keyboardType: TextInputType.number,
),
new Text(
'To',
),
new Text(
'\$',
),
TextField(
controller: _textFieldController,
keyboardType: TextInputType.number,
),
],
),
),
),
You have to wrap your Textfield with Expanded widget in following way.
Expanded(
child: TextField(
controller: _textFieldController,
keyboardType: TextInputType.number,
),
),
But if you want to limit your TextField widget's width then wrap TextField in following way.
Container(
width: 50,
child: Row(
children: [
Expanded(
child: TextField(
controller: _textFieldController,
keyboardType: TextInputType.number,
),
),
],
),
),
Note: Here you are using same controller for two TextField, which will not give you correct value of textfield, so have to provide different controllers.
I have a Country code(DropdownMenu) and phone (TextFormField), how can I put them in same level?
I've tried Align widget.
Row(
children: <Widget>[
Flexible(
flex: 1,
child: DropdownButtonFormField(
value: _selectedCountryCode ?? 'TR',
onChanged: (value) {
setState(() {
_selectedCountryCode = value;
});
},
items: countryCodes,
),
),
Flexible(
flex: 4,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: TextFormField(
decoration: InputDecoration(labelText: "Phone"),
),
),
),
],
),
Thanks to #danish-khan-I, I solved using crossAxisAlignment: CrossAxisAlignment.baseline. But you also have to provide textBaseline otherwise it gives an exception.
So in my row I've used:
crossAxisAlignment: CrossAxisAlignment.baseline
textBaseline: TextBaseline.ideographic,
Is there any effective way to achieve like this?
Textfields in a row
Using Row should suffice. If you need more control over the width of child widgets, consider using Expanded and it's flex attribute.
Row(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
flex: 3,
child: TextField(
decoration: InputDecoration(
hintText: 'Time'),
),
),
Expanded(
flex: 4,
child: Text("(in mins)/"),
),
],
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
flex: 3,
child: TextField(
decoration: InputDecoration(
hintText: 'Whistle'),
),
),
Expanded(
flex: 4,
child: Text("(whistles)"),
),
],
),
),
],
),
In the above code, the first row contains two Expanded with no flex, which means both widget will have the same width.
The inside row contains two Expanded: one with flex factor of 3 and one with flex of 4, and the first widget's (TextField) length will be 3/7 of the total row width, while the Text's width will be 4/7.