I have two FlatButtons in a row. The row is a column which is in turn in a container that is used for the padding of the screen. This container has padding of right:20 and left:20. I want my buttons to be 20 in from left and 20 in from the right to keep everything aligned in my column. I know the FlatButton widget has default padding and I've tried the solutions in this question Changing the buttons to GestureDectectors widgets works with alignment but doesn't have a very nice user experience, the area to click is too small maybe. Ideally I'd like to remove the padding of the FlatButton on one side left/right depending on which button. Here is my code
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
FlatButton(
child: new Text('SIGN IN',
style: Theme.of(context).textTheme.body1),
onPressed: () {
Navigator.push(
context, SignInPage(widget.onSignedIn));
},
),
new FlatButton(
child: new Text(
'SIGN UP',
style: Theme.of(context).textTheme.body1,
),
onPressed: () {
Navigator.push(
context, SignUpPage(widget.onSignedIn));
},
),
]),
Now with the deprecation of the FlatButton for TextButton
TextButton(
style: TextButton.styleFrom(padding: EdgeInsets.all(0)),
...
)
Use zero padding, for example
padding: EdgeInsets.zero,
To remove extra space from around TextButton and OutlineButton which replace FlatButton use this:
style: OutlinedButton.styleFrom(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
)
try to use option 'padding: EdgeInsets.only( depends which side u wanna padding )'
FlatButton(
padding: EdgeInsets.only(left: 10.0, right:10.0),
child: new Text('SIGN IN',
style: Theme.of(context).textTheme.body1),
onPressed: () {
Navigator.push(
context, SignInPage(widget.onSignedIn));
},
),
SizedBox(
height: 25,
child: ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(kDefaultPadding))),
child: const Text("More"),
)
)
The FlatButton is now deprecated and you can use TextButton.
Even if you set padding to 0, there is still some padding left. To remove it completely you can use RawMaterialButton as suggested by #Arshak here.
Example:
RawMaterialButton(
constraints: BoxConstraints(),
padding: EdgeInsets.all(5.0), // optional, in order to add additional space around text if needed
child: Text('Button Text')
)
I know answer is right there but It took me hours to do this. So I thought to add it as answer also.
Related
NOTE: Im using Navigator.of(context).push to push ModalRoute,
Hi I have page with ModalRoute with TextFormField in the body, but when keyboard show up, the input is being hide by keyboard, how to fix this?
return Container(
child: ListView(
children: <Widget>[
//other widget
SizedBox(height: _qtyAnimation.value),
Row(
children: <Widget>[
Expanded(
child: Text(
"Jumlah",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
SizedBox(
width: 145.0,
child: TextFormField(
focusNode: _qtyFocusNode,
controller: qty,
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(0.0),
prefixIcon: IconButton(
icon: Icon(Icons.remove),
onPressed: () {},
),
border: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.grey, width: 0.1),
),
suffixIcon: IconButton(
icon: Icon(Icons.add),
onPressed: () {},
),
),
),
),
],
),
],
);
thats my code, i try with focusnode and more, still same result
please help me
thanks solve my problem with this padding on bottom of textfield
Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom));
and mare reverse list
This worked for me...
First add this
final bottom = MediaQuery.of(context).viewInsets.bottom;
Then use a SingleChildScrollView() to wrap around the main widget (whatever you're using, e.g. Column, ListView, etc) like this...
You need "reverse: true"
Widget build{
return Scaffold(
body: SingleChildScrollView(
reverse: true;
child: Container(...
You also need these two lines of code for the Scaffold as well..
return Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
body: SingleChildScrollView(...
and finally, reference the 'bottom' for your EdgeInsets..
body: SingleChildScrollView(
reverse: true,
child: Padding(
padding: EdgeInsets.only(bottom: bottom),
child: Container(...
You need to wrap everything in a SingleChildScrollView and set the reverse to true.
SingleChildScrollView(
reverse: true,
child: Container(),
);
Just that worked for me!
I had a similar problem. I try all solution, but didn't work.
Finally I removed
<item name="android:windowFullscreen">true</item>
from my styles.xml file in android folder, and fix the problem.
There are few methods for this (as of Dec 3rd 2018):
You can read this for a better solution: When i select a Textfield the keyboard moves over it.
Inside Scaffold() add: resizeToAvoidBottomPadding: false,.
You can also wrap your TextWidget with SingleChildScrollView(). This will allow you to scroll whenever the keyboard is shown.
Set resizeToAvoidBottomInset to false inside your Scaffold Widget.
Note that resizeToAvoidBottomPadding will be deprecated.
Scaffold( resizeToAvoidBottomInset: false, ...)
I use form elements in modal_bottom_sheet plugin. I solved it by just adding the following code to SingleChildScrollView.
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom)
Too add to the commonly accepted answers here which is
body: SingleChildScrollView(
reverse: true,
child: Container(
child: Padding(
padding: EdgeInsets.only(bottom: bottom),
child: Stack(
fit: StackFit.loose,
children: <Widget>[
I added a thing to the bottom inset to prevent it from going too high.
var bottom = MediaQuery.of(context).viewInsets.bottom;
bottom = max(min(bottom, 80), 0);
What worked for me was combining the docs with tips over here. It uses, LayoutBuilder, SingleChildScrollView, Padding (with bottom hack) and finally, ConstrainedBox (to use Expanded). By combining these It works with Expanded widgets inside Columns.
The docs (from where LayoutBuilder comes):
https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html
Structure
return Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,`
body: SafeArea(
child: Container(
child: LayoutBuilder(builder:
(BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
reverse: true,
child: Padding(
padding: EdgeInsets.only(bottom: bottom),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
maxHeight: viewportConstraints.maxHeight),
child: Column(
SingleChildScrollView does solve the problem while the resizeToAvoidBottomInset is set to true, while setting it to false would be a not recommended solution. Let me explain why:
When user presses the TextField, usually a virtual keyboard will popup and takes up a large portion of the bottom space on the screen. In such case, problem would occur, if the TextField is near said bottom, it will be covered by the keyboard (resizeToAvoid... set to false), and user will be unable to see what they've typed in; if there are other widgets below the TextField (when resizeToAvoid is true, e.g. buttons in the same Column with TextField), there will be overflow because there is no space for them to show on the remaining viewport.
Speaking from a user's perspective, what we want is:
TextField who gets focus is always visible.
No bottom overflow and bugged graphics.
However, such description is not technical, it does not tell us how exactly do we implement it. What we actually want is, make the whole layout scrollable, and allow Scaffold to resize. When the viewport resizes, anything below the focused TextField scrolls away to the invisible bottom, and the TextField itself snaps to the keyboard.That's why SingleChildScrollView + resize = true is what we want.
To have a centered content first on build method I added this:
final bottom = MediaQuery.of(context).viewInsets.bottom;
and return this:
return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
fit: StackFit.expand,
children: [
///Content
Align(
alignment: Alignment.center,
child: SingleChildScrollView(
reverse: true,
child: Padding(
padding: EdgeInsets.only(bottom: bottom),
child: Column(
children: [
MyContent()
],
),
),
),
),
///Button
Align(
alignment: Alignment.bottomCenter,
child: MyBottomButton()
)
],
),
),
);
And it works very well with keyboard flow
In my case, there was were important to use only small padding, otherwise when open the keyboard it makes a big mess.
Padding(padding: EdgeInsets.only(bottom: 20)
Check my solution:
child: Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
body: Container(
color: Colors.black,
child: SingleChildScrollView(
reverse: true,
child: Padding(
padding: EdgeInsets.only(bottom: 20),
child: Container(
child: ReservationCard(
),
),
),
),
)
For Android, check for windowSoftInputMode. (AndroidManifest.xml)
android:windowSoftInputMode="adjustResize"
I have used the Expansion Tile to generate a Expansion List View.
I'm facing some customization issues in Expansion Tile Header.
Below is my code.
ExpansionTile(
title: Container(
child: Text(
getCategory(i),
style: TextStyle(
color: Colors.white,
),
),
color: Colors.black
),
children: <Widget>[
new Container(
height: 60.0,
margin: const EdgeInsets.only(top:10.0, left: 10.0, right:10.0, bottom: 10.0),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: new BorderRadius.all( Radius.circular(5.0) ),
),
),
new Container(
height: 60.0,
margin: const EdgeInsets.only(top:10.0, left: 10.0, right:10.0, bottom: 0.0),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: new BorderRadius.all( Radius.circular(5.0) ),
),
)
],
backgroundColor: Colors.white,
)
I'm getting below result.
What I'm expecting to have is below.
If anyone know a workaround to customize the header color, please advice.
If you check the source code of the ExpansionTitle , you will notice that the header item is a ListTile , so you can't change the background because it hasn't a parent with a color property.
I modified a little the class to support what you need.
Add this file to your project: https://gist.github.com/diegoveloper/02424eebd4d6e06ae649b31e4ebcf53c
And import like this way to avoid conflicts because the same name.
import 'package:nameofyourapp/custom_expansion_tile.dart' as custom;
I put an alias 'custom' but you can change for any alias.
Usage:
custom.ExpansionTile(
headerBackgroundColor: Colors.black,
iconColor: Colors.white,
title: Container(
...
Remember, Flutter has a lot of Widgets out of the box, but If any of them don't fit what you need, you'll have to check the source code and create your own widget.
In my opinion, the more preferable way is wrap It with a new Theme, so It could work as expected:
Theme(
data: Theme.of(context).copyWith(accentColor: ColorPalette.fontColor, unselectedWidgetColor: ColorPalette.fontColor..withOpacity(0.8)),
child: ListView(
children: <Widget>[
ExpansionTile(
title: Text("Padding"),
children: <Widget>[
Text("Left"),
Text("Top"),
Text("Right"),
Text("Bottom"),
],
)
],
),
)
Instead of copy a full class to customize, check the source code, you could find more Theme attribute to override.
_borderColorTween
..end = theme.dividerColor;
_headerColorTween
..begin = theme.textTheme.subhead.color
..end = theme.accentColor;
_iconColorTween
..begin = theme.unselectedWidgetColor
..end = theme.accentColor;
_backgroundColorTween
..end = widget.backgroundColor;
If you want a more animatable widget or something, I would recommend diegoveloper's answer. Otherwise, just wrap It with Theme, so you won't need to maintain the Component, and get native flutter component.
A much easier way than all of those suggested is to wrap your ExpansionTile in a ListTileTheme.
Once you do this, you can change the backgroundColor to whatever you'd like. In my case, I've done the same thing with the ListTiles inside of the ExpansionTile so that the header can have one color and the children can have another color.
return ListTileTheme(
tileColor: Colors.grey.shade300,
child: ExpansionTile(
leading: Padding(
padding: const EdgeInsets.only(top:4.0),
child: Text('Outer Tile'),
),
title: null,
children: [
Slidable(
actionPane: SlidableDrawerActionPane(),
child: ListTileTheme(
tileColor: Colors.white,
child: ListTile(
title: Text('Inner Tile'),
subtitle: Text('subtitle'),
leading: FlutterLogo(),
),
),
)
],
),
);
I think this is easier than digging through the docs to find which Theme elements correspond to individual ListTile parameters.
I think better this solution more than custom list tile .
Widget customTheme(Widget child, BuildContext context) => Theme(
data: Theme.of(context).copyWith(
dividerColor: Colors.transparent,
dividerTheme: DividerThemeData(
color: Theme.of(context).colorScheme.background)),
child: child,
);
Code Gist
It seems the ExpansionTile was changed and you can now directly configure lots of colors. As an example, for the arrows:
return ExpansionTile(
// sets the color of the arrow when collapsed
collapsedIconColor: Colors.red,
// sets the color of the arrow when expanded
iconColor: Colors.green,
);
For changing trailing arrow icon color you can wrap expansion tile with Theme and make theme light and set accet color and primary color to dark and it will work.
return Theme(
data: ThemeData.light()
.copyWith(accentColor: darkAccent, primaryColor: darkAccent),
child: ExpansionTile(
title: Text(
data['number'],
style:
TextStyle(color: darkAccent, fontWeight: FontWeight.bold),
),
Another option which should work is wrapping both the entire expansion tile and each individual container in a Card() widget as they have a color property. The downside is that the background for your expansion will be colored as well as the title, but if you set a color for the child cards, they will not be affected by the parent an so they could be individually colored as you like.
For trouble with the arrow color: notice it's an ExpandIcon, defined as a local Widget expandIconContainer in _ExpansionPanelListState.build().
When your ExpansionPanel uses canTapOnHeader: true, you get ExpandIcon(onPressed: null), so the color used for the underlying IconButton is determined by Theme#disabledColor.
I use this great little plugin, much more flexible than the Flutter Material. You can change the background and borders and have custom icons for open and close states. https://pub.dev/packages/configurable_expansion_tile
I am trying to make a simple chat app, so I created a scaffold and my body, will be the messages and my bottomNavigationBar would be my typing field and sending icon.
I added a text field but when typing the navigation bar is hidden by the keyboard.
this is the code of my BottomNavigationBar :
bottomNavigationBar: new Container(
height: ScreenSize.height/12,
/*color: Colors.red,*/
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new Container(
child: new Icon(Icons.send),
width:ScreenSize.width/6,
),
],
),
new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Material(
child: new Container(
child: new TextField(
autofocus: false,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(9.0),
border: InputBorder.none,
hintText: 'Please enter a search term',
),
),
width:ScreenSize.width*4/6,
),
elevation: 4.0,
/*borderRadius: new BorderRadius.all(new Radius.circular(45.0)),*/
clipBehavior: Clip.antiAlias,
type: MaterialType.card,
)
],
),
new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new Container(
child: Text('HELLO C1'),
color: Colors.green,
width:ScreenSize.width/6,
),
],
)
],
),
),
here is how it looks when focused :
if you use a Stack on your Scaffold's body, instead of bottomNavigationBar, your nav will push up above the keyboard. even if you fix to the bottom with a Positioned:
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: MyNav(),
),
simply wrap your bottom navigation bar with Padding and set it to MediaQuery.of(context).viewInsets,
bottomNavigationBar: Padding(
padding: MediaQuery.of(context).viewInsets,
child: ChatInputField(),
),
Literally just worked through the same issue. Given the code i was refactoring, this worked like a charm. Peep the github link, review his change and apply. Couldn't be much more straight forward: https://github.com/GitJournal/GitJournal/commit/f946fe487a18b2cb8cb1d488026af5c64a8f2f78..
Content of the link above in case the link goes down:
(-)BottomAppBar buildEditorBottonBar(
(+)Widget buildEditorBottonBar(
BuildContext context,
Editor editor,
EditorState editorState,
BottomAppBar buildEditorBottonBar(
folderName = "Root Folder";
}
*REPLACE* return BottomAppBar(
elevation: 0.0,
color: Theme.of(context).scaffoldBackgroundColor,
child: Row(
children: <Widget>[
FlatButton.icon(
icon: Icon(Icons.folder),
label: Text(folderName),
onPressed: () {
var note = editorState.getNote();
editor.moveNoteToFolderSelected(note);
},
)
],
mainAxisAlignment: MainAxisAlignment.center,
*WITH THE WRAPPER* return StickyBottomAppBar(
child: BottomAppBar(
elevation: 0.0,
color: Theme.of(context).scaffoldBackgroundColor,
child: Row(
children: <Widget>[
FlatButton.icon(
icon: Icon(Icons.folder),
label: Text(folderName),
onPressed: () {
var note = editorState.getNote();
editor.moveNoteToFolderSelected(note);
},
)
],
mainAxisAlignment: MainAxisAlignment.center,
),
),
);
}
class StickyBottomAppBar extends StatelessWidget {
final BottomAppBar child;
StickyBottomAppBar({#required this.child});
#override
Widget build(BuildContext context) {
return Transform.translate(
offset: Offset(0.0, -1 * MediaQuery.of(context).viewInsets.bottom),
child: child,
);
}
}
I achieved this by a mix of two things I found separated in the web:
1 - Inside the Scaffold, I put other with only a bottomNavigationBar with a empty Container. For some reason, this trick push all my real bottomNavigationBar up to the top of the keyboard.
Scaffold(
bottomNavigationBar: Container(
height: 0,
),
body: Scaffold(
body: MyWidget(
But, I did not want all the content up, so I got that Package:
2 - I added flutter_keyboard_visibility: ^5.1.0 from
https://pub.dev/packages/flutter_keyboard_visibility
With this Package, you can do anything you want in response to keyboard visibility - is up to you. In my case, I made all content of my real bottomNavigationBar disappear except the textfield, which stay on the top of the keyboard:
[TextFormField] // dont go away,
//The others:
KeyboardVisibilityBuilder(builder: (context, visible) {
return Column(
children: [
visible
? SizedBox(
height: 0,
)
: OtherWidgets(
If you need some kind of button; you can do:
Scaffold(
bottomNavigationBar: bottomNavigationBar,
floatingActionButton: ExampleButton(
text: 'Hello',
),
body: body,
),
You can apply further customizations on the Floating Action Button using parameters in the Scaffold.
There is a simple way to do this if you want to really need to use the bottom navigation bar of the scaffold to put your widgets in rather than put it on a stack. Just wrap your scaffold with another scaffold and it should solve the problem.
return Scaffold(
body: Scaffold(
bottomNavigationBar: yourBottomNavigationBarWidget(),
body: yourBody(),
This works best especially when the height of your widget changes dynamically (because the text user types may introduce multiple lines) and you want the body to resize accordingly. A body in the stack, as suggested by many, will require a bottom padding to be visible over the text field and need to change dynamically as user types which is difficult to handle when you have multiple widgets sitting in and around the text field.
I want to make my TextField height the same as my container height. Please check my code below and let me know how can I make TextField match_parent of my container. I've checked this question The equivalent of wrap_content and match_parent in flutter? but I didn't find any solution. I need to make TextField to take full height and width of my container.
new Container(
height: 200.0,
decoration: new BoxDecoration(
border: new Border.all(color: Colors.black)
),
child: new SizedBox.expand(
child: new TextField(
maxLines: 2,
style: new TextStyle(
fontSize: 16.0,
// height: 2.0,
color: Colors.black
),
decoration: const InputDecoration(
hintText: "There is no data",
contentPadding: const EdgeInsets.symmetric(vertical: 40.0),
)
),
),
)
Please check the screenshot below. As said, I need my TextField to take full height of Container
Here is my solution:
Container(
height: 200,
color: Color(0xffeeeeee),
padding: EdgeInsets.all(10.0),
child: new ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 200.0,
),
child: new Scrollbar(
child: new SingleChildScrollView(
scrollDirection: Axis.vertical,
reverse: true,
child: SizedBox(
height: 190.0,
child: new TextField(
maxLines: 100,
decoration: new InputDecoration(
border: InputBorder.none,
hintText: 'Add your text here',
),
),
),
),
),
),
),
It works pretty good for me. And here is a screen shot.
Answering this in 2021. There is an expands property available now. This code works:
Column(
children: [
Expanded(
child: TextField(
maxLines: null,
minLines: null,
expands: true,
),
flex: 1),
],
)
Let's remove a few lines in code and understand how flutter works.
Why we are giving height 200 to Container. Can't the Container adjust the height based on its child (in this case SizedBox.expand)
If we remove height 200, then Container occupied the entire screen because of SizedBox.expand
Do we really need the SizedBox for our use case. Let's remove that also see what happens.
Now our Container wraps the TextField. But there is some space above and below.
Who decided that space? TextField's decoration's contentPadding. Let's remove that also. It looks like below where textField wrapped by Container. Hope this is what you want. If not, please comment, we can tweak a bit and get what you want. Cheers
Final version of code which displays the above image
new Container(
// height: 200.0,
decoration: new BoxDecoration(
border: new Border.all(color: Colors.black)
),
child: new TextField(
maxLines: 2,
style: new TextStyle(
fontSize: 16.0,
// height: 2.0,
color: Colors.black
),
decoration: const InputDecoration(
hintText: "There is no data",
// contentPadding: const EdgeInsets.symmetric(vertical: 40.0),
)
),
)
Currently the only way to achieve the TextField to fill the available vertical space is:
TextField(maxLines: 1000000) //maxlines: any large int
While it is tempting to use TextField(maxLines: null), it will just set the TextField to expand with its content, until it reaches its container limit.
I think there needs to be a bool stretchVertically parameter. TextField(stretchVertically: true) would mean that the TextField will try to fill as much vertical space as it can. stretchVertically and maxLines would have to be mutually exclusive.
In Android we can position elements in a linear layout using LayoutGravity , I would like to know how to achieve the same in Flutter. I have widgets in a column and I would like some widgets to be position on the left, some on the right and some on the left. How can I achieve this? Here is my code:
return new Container(
margin: const EdgeInsets.only(top: 16.0),
color: Colors.white,
child: new Column(
children: <Widget>[
//the following textfields must be positioned on the right, but they are on the center
new Text("Hair cut",),
new Text("Shampoo",),
//the button is in the center and that is correct
new RaisedButton(
onPressed: ()=>{},
color: Colors.purple,
child: new Text("Book",style: new TextStyle(color: Colors.white),),
)
],
),
);
Setting crossAxisAlignment to CrossAxisAlignment.end moves everything to the right. I tried adding the textfields in their own Column widget and setting crossAxisAlignment to end but nothing happens.
You can set crossAxisAlignment for a generic alignment. And then override it for a specific item by wrapping it in Align widget.
new Column(
children: <Widget>[
//the following textfields must be positioned on the right, but they are not the center
new Align(
alignment: Alignment.centerRight,
child: new Text("Hair cut"),
),
new Align(
alignment: Alignment.centerRight,
child: new Text("Shampoo"),
),
//the button is in the center and that is correct
new RaisedButton(
onPressed: () => {},
color: Colors.purple,
child: new Text(
"Book",
style: new TextStyle(color: Colors.white),
),
)
],
),
You may also want to wrap your Column into a IntrinsicWidth if you don't want your column to fill the width.