Issue with Aligning or Positioning Flutter Widgets - flutter

I want the Container attached to the body of the Scaffold to occupy the space of it's child, which is the Padding widget in this case.
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
// backgroundColor: AppColors.grey,
elevation: 0.0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () => Navigator.pushReplacementNamed(context, '/'),
),
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
);
Below is the screenshot for the above code:
But I also want the padding widget to be pushed to the bottom of the screen. To achieve this I wrapped the Padding widget with the Expanded widget, and later wrapped the Expanded widget with a Column widget, as shown below:
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
// backgroundColor: AppColors.grey,
elevation: 0.0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () => Navigator.pushReplacementNamed(context, '/'),
),
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
],
),
),
);
Now that the contents of the Padding widget have got pushed to the bottom of the screen, but the Expanded widget, tries to occupy all the available space. I don't want this to happen.
I don't want the height of the Padding widget to increase. Below is the screenshot after updating the code:
Another issue that's concerning me is, where should I be adding the SingleChildScrollView, as I would experience the "Bottom overflowed by -- px" error when the user would tap on the TextFormFields to input the email and password.
I did raise this issue earlier as well but wasn't much luck, so thought would organize the code and explain it in detail so that it would be easy for others to understand and help.
Thank you so much for your help in advance.
AFTER APPLYING SOLUTION SUGGESTED BY #SoundConception

try adding this to your Column widget :
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,

In your first code example you have:
...
body: Container(
...
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
...
],
),
),
),
The mainAxisSize: MainAxisSize.min specifies that the Column should be as small as possible in height, effectively shrink wrapping it to the height of its children.
The Padding just adds the specified dp of padding around Column widget.
This means the child of the Container has a fixed height equal to the sum of the Column children heights plus (kSpacingUnit * 3.0) dp of padding top and bottom.
Since the Container child height is fixed, the Container will size itself to the height of it's child.
In your second code example you have:
body: Container(
...
child: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
...
],
),
),
),
],
),
),
Here the outermost Column has a single child that is an Expanded which means this will take up all the available room in the Column.
The innermost Column has mainAxisAlignment: MainAxisAlignment.end meaning its children will align to the bottom of the Column. The height of your Padding has not expanded.
You ask about using a SingleChildScrollView. I assume you want the white background decoration to remain stationary, and only the contents of the Column should be able to scroll.
Try something like the following:
return Scaffold(
...
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
),
);
Note: You'll need to make sure your EmailSignInForm() and SocialMediaLoginWidget() do not have unbound height.
My guess is your EmailSignInForm() probably utilises a Column. If so set it's mainAxisSize to min.

Related

SingleChildScroll adding a large inset on-top of the Keyboard

I'm trying to create a scrollable register form for a Flutter app. I got SingleChildScroll to work, but theres a large padding or inset or something on top of the keyboard that can block content. You can see if pretty well If I scroll all they way to the bottom.
Here's my code.
Widget _buildContainer() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ClipRRect(
// This Clips the border Radius of the Container
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
child: Container(
// This sets the attributes of the Container
height: MediaQuery.of(context).size.height * 0.69,
width: MediaQuery.of(context).size.width * 0.9,
decoration: const BoxDecoration(
color: Colors.white,
),
child: Scaffold(
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildFirstNameRow(),
_buildLastNameRow(),
_buildEmailRow(),
_buildPasswordRow(),
_buildConfirmPasswordRow(),
_buildRegisterButton(),
],
),
),
),
),
),
),
],
);
}
I've tried setting resizeToAvoidBottomInset: false, in the Scaffold, but that prevents any scrolling from happening.
I've also tried adding to Scaffold as well, but that only changes the padding around that mystery inset.
body: Padding(
padding: EdgeInsets.only(
bottom: 8.0),
Thanks for your Help!

Flutter: Make Buttons stretch

I having an issue with a Flutter Widget tree I am building:
I Want the Buttons on the Bottom to be bigger and fill all the available space from the text above to the bottom of the screen.
Here my current Code:
class Body extends StatelessWidget {
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return SafeArea(
child: Column(
children: [
UpperDetailsContainer(),
TitleAndPrice(),
//The Row below contains the Two Buttons
Expanded(
child: Row(
children: [
Container(
width: size.width / 2,
child: TextButton(
child: Text("Buy Now"),
style: TextButton.styleFrom(
backgroundColor: kPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(50)
)
)
),
),
),
Container(
width: size.width / 2,
child: TextButton(
child: Text("Description"),
style: TextButton.styleFrom(
backgroundColor: kPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(50)
)
)
),
),
),
],
),
)
],
),
);
}
}
I have already tried:
Making the upper widgets smaller
Adding Mainaxisaligment.spacebetween to the surrounding column
Adding Crossaxisaligment.stretch to the Row that contains the buttons
Removing SafeArea bottom / SafeArea as a whole
Setting the height for the buttons manually as an absolute value, but I don't really wanna do this for obvious reasons
What else can i do? And where does that grey bottom Stripe come from?
add crossAxisAlignment: CrossAxisAlignment.stretch to the row, so that it fills all available vertical space
note: you need the Expanded widget so that the constraint your row gets, isn't infinite
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
height: size.height * 0.7,
child: Container(
color: Colors.amber,
),
),
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildBuyNowButton(size),
_buildDescriptionButton(size),
],
),
)
],
),
);
}
Runnable example: https://www.dartpad.dev/4f568d8e0a334d23e7211207081356b4?null_safety=true

Widget which adjusts to the children size?

Is there a widget in Flutter which adjusts itself on the content of it's children which are in Rows and Columns?
I can't seem to find anything related, and I am constantly hit with infinite overflows errors.....
As an example, lets say I would have 3 Widgets in a Row, 1 of which is a text, which I cannot guess how long it will be, but I need to expand the parent as much as the widget needs and at the sametime wrap the text
I would have something like:
Row(
children: [
Expanded(child: Widget1(....)),
Expended(child: Text(.....)),
Expanded(child: Widget2(....))
]
)
Right?
I would want the parent of the row to expand as much as it needs for the children to be shown, I want to align Widget1 and Widget2 in different ways (1-center, 2-bottom).
If I put them in Column I can center Widget1, but I cannot put Widget2 at the bottom because if I put Column to max size it overflows, if I don't it doesn't align...
How would you do it?
I really don't understand the logic behind the inifnite layout thing....
For example, here is where I am stuck at the moment.
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Global.findCategory(event.categId).color.withAlpha(150),
blurRadius: 20,
spreadRadius: -20,
offset: Offset(0, 5)
)
],
color: Colors.white,
borderRadius: BorderRadius.circular(30)
),
child: Row(
children: <Widget>[
Align(
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
width: Global.scaleSmallDevice(context) * 64,
height: Global.scaleSmallDevice(context) * 64,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
fit: BoxFit.cover,
image: event.image
)
)
),
)
,
),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
CustomText(
text: title,
color: Global.findCategory(event.categId).color,
fontSize: 16,
),
Flexible(
child: CustomText(
text: shortInfo,
color: Global.findCategory(event.categId).color,
fontSize: 12,
),
)
],
),
),
Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: StatefulBuilder(
builder: (context, setState) {
IconData buttonIcon = (event.favorite) ? Icons.favorite : Icons.favorite_border;
return SplashButton(
splashColor: Global.findCategory(event.categId).color,
child: Icon(buttonIcon, color: Global.findCategory(event.categId).color, size: 30),
onTap: () async {
await event.setFavorite(context);
setState(() {
buttonIcon = (event.favorite) ? Icons.favorite : Icons.favorite_border;
});
}
);
},
),
),
],
),
),
],
);
}
In this case I want the StatefulBuilder widget to be on the bottom and the entire container be as small as the column with the CustomText widgets.
The widget with image inside I want it to be centered, while the text to be fully available to the user.
If I don't add a Column as Container, it goes as the height allows it and the StatefulBuilder widget center itself at the bottom, in the curent code it's at the center.....
Sorry if I'm not coherent, it's a bit late and I am tired after coding all day and stuck at this widget for a few hours.

Make container grow to fit width of sibling in column

I have two Container widgets in a Column, each containing a Text widget. I want the Container with the shortest text to expand to match the width of the other container containing the longer text. The container with the longer text should wrap the Text widget and its padding.
I can't get it to work without resorting to fixed widths on the containers:
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// This container has a shorter text than its sibling, so it should expand
// its width to match its sibling/parent
Container(
alignment: Alignment.center,
width: 50, // I don't want this fixed width
decoration: BoxDecoration(color: Colors.orange, borderRadius: BorderRadius.only(topLeft: Radius.circular(4), topRight: Radius.circular(4))),
child: Padding(
padding: const EdgeInsets.fromLTRB(8,4,8,4),
child: Text('short'),
)
),
// This container has a longer text, so it should decide the width of the
// other container (and of the parent Column)
Container(
alignment: Alignment.center,
width: 50, // I don't want this fixed width
decoration: BoxDecoration(color: Colors.orange, borderRadius: BorderRadius.only(bottomLeft: Radius.circular(4), bottomRight: Radius.circular(4))),
child: Padding(
padding: const EdgeInsets.fromLTRB(8,4,8,4),
child: Text('long text here'),
)
),
]
);
I've tried a couple of ways to solve it involving Expanded and Flexible, but they all result in the "red screen of death" (or at least "annoyance").
EDIT
Just to be clear - I want the Column to just wrap its content, i.e. adjust its width to the width of the containers. In summary - everything should be as narrow as possible, except for the container with the shortest text, which should instead be as wide as its sibling (the container with the longer text).
I saw your Fiddle on a comment. And what you need is IntrinsicWidth.
IntrinsicWidth(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// This container has a shorter text than its sibling, so it should expand
// its width to match its sibling/parent
Padding(
padding: const EdgeInsets.symmetric(vertical: 1.0),
child: Container(
color: Colors.orange,
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
child: Text(
'short',
textAlign: TextAlign.center,
),
),
),
),
// This container has a longer text, so it should decide the width of the
// other container (and of the parent Column)
Padding(
padding: const EdgeInsets.symmetric(vertical: 1.0),
child: Container(
color: Colors.orange,
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
child: Text(
'long text here',
textAlign: TextAlign.center,
),
),
),
),
],
),
),
You can use something like this to take the entire width of the Widget (make sure to be inside a MaterialApp and a Scaffold/Material child (home):
Wrap(
children: <Widget>[
Container(
color: Colors.red,
child: IntrinsicWidth(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.black,
height: 200,
child: Align(
alignment: Alignment.bottomRight,
child: Text(
"Hello World",
style: TextStyle(color: Colors.white),
),
),
),
Container(
color: Colors.blue,
height: 100,
child: Align(
alignment: Alignment.topRight,
child: Text(
"Bottom Text Longer Text",
style: TextStyle(color: Colors.white),
),
),
),
],
),
),
),
],
)
The Align is not necessary, is just to showcase how the width actually works with "double.infinity" and moving a text to the bottom right or top right portion of it.

Color bottom of Card in flutter

I'm building a layout with a GridView and Cards. I want to put a color to the bottom of each card. I found this question Fill an area with color in Flutter and tried to do the same trick for bottom, but each time The SizedBox Overflows the round card corners. Any idea of how to fix this?
The sample code below shows the issue. I try to color the bottom part of the card, and when I do this, the corners of the card are lost, like overflow from the Container.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Card(
margin: EdgeInsets.all(20),
elevation: 10,
child: SizedBox(
height: 100,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text("line1"),
Text(
"line2",
),
Expanded(
child: Container(
/*color: Colors.orange,*/ child: Text("Bottom"),
)),
],
),
),
),
Expanded(
child: Container(),
)
],
),
);
}
Try using BoxDecoration in your Container and use the same radius as your Card (4.0)
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(4.0),
bottomRight: Radius.circular(4.0))),
child: Text("Bottom"),
),
),