Why FlatButton takes more space than it should? - flutter

The space around FlatButton is bigger than the space between Containers in the column with spaceEvenly alignment. This flatbutton contains nothing except a text widget. Does it use some default padding or something else which takes extra space?
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(...),
constraints: const BoxConstraints.expand(),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(...),
Container(...),
FlatButton(...),
],
),
),
),
);
}

FlatButton comes with some internal padding, which is like 8px of padding on each side, and for the text is 20px high.
FlatButton(
padding: EdgeInsets.zero, // Will add default padding as zero
child: ...,
)

Yes it has a default internal padding, use this to remove it
FlatButton(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,)

Use this code :
FlatButton(
padding: EdgeInsets.all(0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap
)

Related

Remove space between Card

How to remove the column space between Card ?
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample"),
),
body: Column(
children: <Widget>[
Card(
child: Padding(
padding: EdgeInsets.all(15),
child: Text("Card 1"),
)),
Card(
child: Padding(padding: EdgeInsets.all(15), child: Text("Card 2")),
)
],
),
);
}
Output
By default, the card widget has a default margin set to 4.0 logical pixels , to eliminate the spaces, you can adjust the default margin to your preference:
I added a demo using your widget tree as an example:
Column(
children: <Widget>[
Card(
// set the margin to zero
margin: EdgeInsets.zero,
child: Text("Card 1"),
),
Card(
// set the margin to zero
margin: EdgeInsets.zero,
child: Text(
"Card 2",
),
)
],
),
The error is because you using. padding: EdgeInsets.all(15) in your card. You Can alloy padding only on the required sides.
In the card try adding margin:EdgeInsets.zero
Card(
margin: EdgeInsets.zero,
),
The default margin in Flutter is 4.0 pixels on all sides. To change this set
margin: EdgeInsets.zero
To learn more about margins go here

How to adjust TextField width?

I'm re-writing a simple app which calculates averages. However, I have a hard time with a TextField. I would like it to be exactly as on a first screenshot.
The TextField's width is stretched, I don't want that. I want it to be exactly as it is on the screenshot.
Desired look:
What I have:
Code:
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
class ArithmeticAverageScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('arithmetic_average_title').tr(),
),
body: Container(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Card(
child: Container(
padding: EdgeInsets.symmetric(vertical: 20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.help),
title: Text('arithmetic_average_help').tr(),
subtitle: Text('arithmetic_average_help_content').tr(),
)
],
),
)
),
SizedBox(height: 16.0),
Card(
child: Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text('arithmetic_average_your_grades', style: Theme.of(context).textTheme.headline5).tr(),
SizedBox(height: 16.0),
Text('arithmetic_average_grades_one_at_a_time', style: Theme.of(context).textTheme.headline6,).tr(),
SizedBox(height: 16.0),
Text('arithmetic_average_grade', style: Theme.of(context).textTheme.subtitle2).tr(),
TextField()
],
),
),
)
],
),
)
);
}
}
This will help you make generic width on all devices, so here width * 0.3 means it will take 30% of the screen width
Container(
width: MediaQuery.of(context).size.width * 0.3,
child: TextField(),
)
Use Row Widget, and put Expanded Widget as child Widget and inside that put your widgets, as Expanded will take up equal space.
return Row(
children: [
Expanded(
child: TextField();
),
Expanded(
child: Button();
)
],
);
When ever you want to play with height and width you can use the widget Container.If you want to play with a property which cannot found in the widget you are using wrap it with a widget with that property will help you.
Container(
margin: const EdgeInsets.only(right: 150),
child: new TextField(
decoration: new InputDecoration(
hintText: 'Grade',
)
)
)
You can try to wrap your TextField and Button with two Flexible widgets and apply desired proportions, e.g. 1:2 which would give you following result:
Row(
children: [
Flexible(
flex: 1,
child: TextField(),
),
Flexible(
flex: 2,
child: RaisedButton(
child: Text('Hello'), onPressed: () {}),
)
],
)
],
You can also replace the first Flexible with SizedBox and set an exact value, e.g:
Row(
children: [
SizedBox(
width: 100.0,
child: TextField(),
),
Flexible(
flex: 2,
child: RaisedButton(
child: Text('Hello'), onPressed: () {}),
)
],
)
],
TextField doesn't have an intrinsic size (width) constraint so it will always try to occupy all horizontal space. Flexible allows to constraint it to desired width in a Row.
Full example on DartPad.

Stretch and start FlatButton.icon

In a Column there's a group of FlatButtons created with FlatButton.icon()
so that it has image and text laid beside each other,
I need the FlatButton's contents to be aligned to the left, but the button is stretched horizontally,
setting the column's crossAxisAlignment to CrossAxisAlignment.stretch stretches the button's width as I want, but centers the button's content:
and setting it to CrossAxisAlignment.start aligns the button's contents to the left but the button's width gets shrinked:
is it possible to align the button contents to the left but the button be stretched? or I have to use other combinations of widgets (InkWell for example?)
you can use a normal FlatButton() constructor that has the child property and then you can have a row as the child and make it's mainAxisAlignment:MainAxisAlignment.start and make your text and icon it's children's, like below:
Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
FlatButton(
color: Colors.grey,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(Icons.check),
SizedBox(width: 10),
Text('Recharge and balance')
],
), onPressed: () {},
)
],
),
)
the result:
It is a bit of a hack, but you could use a regular FlatButton widget and do something like this could work:
class SampleWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 200,
),
child: FlatButton(
onPressed: () {},
child: Row(
children: <Widget>[
Icon(Icons.home),
Text('Recharge and balance'),
Spacer(),
],
),
),
),
],
);
}
}
Spacer widget will take up the remaining space of row. All you have to do from here is just adjust the padding of the Icon to be the same as FlatButton.icon
Try changing padding property of Flatbutton to Edgeinsets.only(left: 0.0)
padding: Edgeinsets.only(left: 0.0),

How to position a Widget at the bottom of a SingleChildScrollView?

I need to use SingleChildScrollView in order to be able to use keyboard_actions so that i can put a "Done" button on top of the keyboard in iOS (using a numeric keyboard at the moment)
The SingleChildScrollView will have a column as a child and then a button to be placed at the bottom. I tried using LayoutBuilder to enforce a height to the SingleChildScrollView.
LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints:
BoxConstraints(minHeight: viewportConstraints.maxHeight),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Column(),
// Spacer() ?
FlatButton()
])));
});
I tried using the BoxConstraints with the maxHeight attribute, but ultimately the widget wouldn't scrooll up when the keyboard appeared.
Side note: the Scaffold has both resizeToAvoidBottomInset and resizeToAvoidBottomPadding set to true (the default value)
The issue with SingleChildScrollView is that it shrikwrap it's children.
So to have auto size widget in between - we need to use MediaQuery to get the screen height & SizedBox to expand - SingleChildScrollView.
Here Button will be at bottom of screen.
working Code:
double height = MediaQuery.of(context).size.height;
SingleChildScrollView(
child: SizedBox(
height: height,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Column(
children: <Widget>[
Text('Dummy'),
Text('Dummy'),
Text('Dummy'),
],
),
Spacer(),
FlatButton(
onPressed: () {},
child: Text('Demo'),
)
])),
)
The chosen answer doesn't really work, as using a SizedBox restrict the max size of the Column to the height of the screen, so you can't put as many widgets as you want in it (or they will go off-screen without beeing scrollable).
This solution will work no matter of many widgets are in the column:
https://github.com/flutter/flutter/issues/18711#issuecomment-505791677
Important note: It will only work if the widgets in the column have a fixed height (for example TextInputField does NOT have a fixed height). If they have variable a height, wrap them with a Container of fixed height.
I just copied and pasted here the best solution I found, quoted by #Quentin, elaborated by #NikitaZhelonkin in issue 18711 of Flutter on Github. Simply the perfect solution!
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AppBar'),
),
body: LayoutBuilder(builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: constraints.maxWidth, minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Text('header'),
Expanded(
child: Container(
color: Colors.green,
child: Text('body'),
),
),
Text('footer'),
]
),
)
)
);
})
);
}
}
You may use this workaround appraoch also, You can use padding attribute in SingleChildScrollView like this:
SingleChildScrollView(
padding: EdgeInsets.only(top: height),
child: yourWidgets(),
while height is the distance far away from top.
You can also use this line to get mobile screen height:
double height = MediaQuery.of(context).size.height;
The best solution I have found for myself.
Center the widgets and push them from top to bottom with padding.
return Scaffold(
resizeToAvoidBottomInset: true,
//resizeToAvoidBottomPadding: false,
backgroundColor: PrimaryColor,
body: Center(
SingleChildScrollView(child:
_body())));
Widget _body() {
return Padding(
padding: EdgeInsets.only(top: MediaQuery.of(context).size.height/2.7),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Visibility(
visible:
_userProvider.stateReqVMTokenSocial !=
StateReqVM.Processing,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
...
...
...
],
)),
Visibility(
visible:
_userProvider.stateReqVMTokenSocial ==
StateReqVM.Processing,
child: CircularProgressIndicator()),
Text(
'',
style: Theme.of(context).textTheme.headline4,
),
],
)
);
}

Center widget vertically inside a SingleChildScrollView

I'm new to Flutter so I train myself by making a simple form. I realized while I was debugging on my iPhone the virtual keyboard triggered an error: "A RenderFlex overflowed by 29 pixels on the bottom". I fixed this issue by wrapping my Container inside a SingleChildScrollView.
The problem now is my Column's content is no longer centered. I can't figure out why ...
Here's my code to help you to understand :
List<Widget> _buildBody() {
var listWidget = List<Widget>();
SingleChildScrollView singleChild = SingleChildScrollView(
padding: EdgeInsets.only(top: 1.0),
child: Container(
alignment: Alignment.center,
margin: EdgeInsets.all(30.0),
padding: EdgeInsets.all(10.0),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 50.0),
child: Image.asset(
'assets/github.png',
width: 100.0,
height: 100.0,
),
),
Container(
margin: EdgeInsets.only(bottom: 10.0),
child: TextFormField(
controller: _usernameController,
autofocus: true,
decoration: InputDecoration(
hintText: 'Username',
suffixIcon: Icon(Icons.account_circle)))),
Container(
child: TextFormField(
controller: _passwordController,
obscureText: true,
decoration: InputDecoration(
hintText: 'Password', suffixIcon: Icon(Icons.vpn_key)),
),
),
Container(
margin: EdgeInsets.only(top: 10.0),
child: RaisedButton(
splashColor: Colors.greenAccent,
color: Colors.blue,
child: Text('Submit'),
onPressed: () {
_handleSubmit();
},
),
)
],
),
),
));
listWidget.add(singleChild);
if (_requesting) {
var modal = new Stack(
children: [
new Opacity(
opacity: 0.3,
child: const ModalBarrier(dismissible: false, color: Colors.grey),
),
new Center(
child: new CircularProgressIndicator(),
),
],
);
listWidget.add(modal);
}
return listWidget;
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Github Login'),
),
body: Stack(
children: _buildBody(),
));
}
I added the property "mainAxisAlignment: MainAxisAlignment.center" to my Column. It worked well before I wrapped it into the SingleChildScrollView.
If someone could help me and explain me why it doesn't work anymore I would really appreciated it :)
ArtiomLK Suggested a solution in comments which helped me:
wrap SingleChildScrollView in a Center. The widgets tree is:
Center( child: SingleChildScrollView( child: Column(...)))
None of the others helped.
Solution:
Put your top level Stack inside Center widget.
body: Center(child: Stack(
children: _buildBody(),
)));
Tip to debug:
Use Flutter Inspector to find where the layout is going wrong.
I edited your code a bit(to make to work in my local) and then I inspected. It showed like below
We have a Stack and SingleChildScrollView as per code(refer to the right side of the diagram where the stack of widgets are displayed). As size is determined by SingleChildScrollView(contents inside it), Stack occupies only a little space and by default, it aligned at top. So put it under Center, the whole Stack view will come in the center.
You can use "Center" widget like as
return Center(
child: SingleChildScrollView()
)
There's a section about it in the official docs:
Using SingleChildScrollView with a Column
Source: https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html
However I found that using a combination of the above worked better. Namely confining the Column to the minimum size possible (MainAxisSize.min). This should be fine, as the SingleChildScrollView will take up as much space as is possible on screen, before scrolling can happen.
Widget _buildPortraitPage() {
return Center(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min, // <-- notice 'min' here. Important
children: [
Flexible(
child: Image.asset('assets/images/my-image.png'),
),
Flexible(
child: Text('My content'),
),
],
),
),
);
}
The layout engine in Flutter is pretty hard to figure out.
use LayoutBuilder widget to wrap all the widget and use Spacer widget before and after your centered widget inside the Column
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AppBar'),
),
body: LayoutBuilder(builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: constraints.maxWidth, minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Spacer(),
Container(
child: //your widget
),
Spacer()
]
),
)
)
);
})
);
}
}
Just wrap the Column in a Center. I used that for my apps and it seems to center the contents of my Column even inside a SingleChildScrollView.
There's another way to achieve this:
Center(
child: ListView(
shrinkWrap: true,
children: []
)
)
wrap SingleChildScrollView with center
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
use SingleChildScrollView widget
body: Center(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
You can use SingleChildScrollView -> ConstrainedBox(with min height and width) -> Center
Wrap your SingleChildScrollView(), with center. and here you go.