Flutter position Widget between bottom of screen and safe area - flutter

In my app I have a bottomBar which is placed at the bottom right above the SafeArea:
The problem is that I would like to have a white Container at the bottom (red arrow in image) so that for bigger iPhones (where the bottom of the screen IS NOT EQUAL to the safeArea) the empty place in the image if filled white.
For phones where the bottom screen is equal to the safeArea the fillContainerHeight should simply be nil/zero.
This is my setup:
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
// mainAxisSize: MainAxisSize.max,
children: [
SafeArea(
child: Row(
children: [
Expanded(
child: Container(
height: 49,
color: Colors.white,
)),
Container(
height: 49,
child: Image.asset('assets/images/bottomBar.png')),
Expanded(
child: Container(
height: 49,
color: Colors.white,
)),
],
),
),
Container(color: Colors.white) // -> fill container
],
)
Right now the container is not being shown. What is the best way to solve my problem here? I couldn't find anything on this. Let me know if you need any more info!

You could try to use the stack widget like this (the second child (align widget) is positioned above your SafeArea widget):
return Stack(
children: [
SafeArea(
child: Scaffold(
appBar: AppBar(),
body: // Your other widgets here
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.white,
height: MediaQuery.of(context).padding.bottom;,
),
)
],
);
Another option would be to wrap your SafeArea in a Container and give it a white background while setting the top property to false (= meaning the SafeArea will not be applied to the top):
return Container(
color: Colors.white,
child: SafeArea(
top: false,
child: Scaffold(
appBar: AppBar(),
body: // Your other widgets here
),
),
);

Related

Having trouble centering a row widget

I have a Row widget on the bottom of the page that I can't center. I've tried all the mainAxisAlignment's and crossAxisAlignment's there are, as well as wrapping it in an Align widget and setting alignment to alignment.center and it's still on the left edge of the page. I've tried everything and am really stuck. Any help would be appreciated.
The Page (Updated)
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightBlue,
centerTitle: true,
elevation: 5,
title: Text("Pathomatic")),
body: Container(
decoration: new BoxDecoration(color: Colors.black),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 2,
child: new Stack(
children: <Widget>[
new Container(
alignment: Alignment.center,
child: _cameraPreviewWidget(context),
),
new Align(
alignment: Alignment.center,
child: GestureDetector(
child: Stack(children: <Widget>[
Positioned(
top: yPosition,
left: xPosition,
child: Container(
// padding: EdgeInsets.only(top: 200.0, left: 20.0),
height: MediaQuery.of(context).size.height / 3,
width: MediaQuery.of(context).size.width / 3,
child:
Image.asset('assets/images/crosshair.png'),
),
),
]),
onPanUpdate: (tapInfo) {
setState(() {
xPosition += tapInfo.delta.dx;
yPosition += tapInfo.delta.dy;
});
}),
),
],
),
),
SizedBox(height: 5),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_cameraTogglesRowWidget(),
_mlTextWidget(),
],
),
_captureControlRowWidget(context),
//SizedBox(width: 50),
],
),
SizedBox(height: 5),
],
),
),
),
);
}
This is usually because the widget you are trying to center is actually stretching its container. Since it's the size of the screen, it's contents stick to the left. You should use the Flutter Inspector with select widget mode to actually see how large your row is. Then everything will make much more sense.
In your code, your Row is stretching. Try
Row(mainAxisSize: MainAxisSize.min
This should make it not grow. Alternatively, you can keep the row large but make it center its children:
Row(mainAxisAlignment: MainAxisAlignment.Center
Of course, with this approach its children will get close to each other in the center. You can use a SizedBox between them, or use some other way of spacing them apart.

How to expand container height to max?

I'm having an issue trying to make one of my containers stretch to max screen height,
home: Scaffold(
backgroundColor: Colors.teal,
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: double.infinity,
width: 100,
color: Colors.red,
)
],
),
),
),
I thought by making the height value infinity it would stretch the red container across the entirety of the safe area.
Although the container is invisible unless I put a value in height.
You should use an Expanded widget.
According to the official documentation, An Expanded widget is a widget that expands a child of a Row, Column, or Flex so that the child fills the available space.
Read more about the Expanded widget here: Expanded Widget
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.teal,
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
width: 100,
color: Colors.red,
),
)
],
),
),
);
}
}
OUTPUT
Wrapping the container to Expanded will make its size max like this :
home: Scaffold(
backgroundColor: Colors.teal,
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
width: 100,
color: Colors.red,
)
)
],
),
),
),

How can I stretch a container vertically to max screen?

body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
width: 100.00,
height: 100.00,
color: Colors.red,
),
])),
));
Currently, the height is 100.00, but I need to stretch it to infinity.
I tried to change the height to double.infinity:
Container(
width: 100.00,
height: double.infinity,
color: Colors.red,
But then I receive the following error:
The following assertion was thrown during performLayout():
BoxConstraints forces an infinite height.
To achieve this, you can either:
1) Use a widget called Expanded widget.
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
color: Colors.red,
),
),
])),
));
2) Give the Container a height and width of the device screen using the MediaQuery class
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
// give it a width equals to the device screen
width: MediaQuery.of(context).size.width,
// give it a height equals to the device screen
height: MediaQuery.of(context).size.height,
color: Colors.red,
),
])),
));
Wrap your Container with an Expanded-Widget and remove the height completely.
Expanded(
child: Container(
width: 100.00,
color: Colors.red,
),
),
The Expanded-Widget fills the available space of the child of a Row or a Column along the main-axis.
The right way to assign height to is the calculating height of
App Bar
Top Bar Space(Exist on the above App Bar)
Remaining screen
Logic:
1. Get the MediaQuer
final mediaQuery = MediaQuery.of(context);
2. Declare the AppBar Widget and same App Bar instance should be used in Scaffold App Bar
final PreferredSizeWidget appBar = AppBar(
title: Text('Home'),
);
3. Use calculated height
Container(
width: mediaQuery.size.width,
height: (mediaQuery.size.height -
appBar.preferredSize.height -
mediaQuery.padding.top),
color: Colors.red,
),

Align a button the bottom center in flutter

I want to align a button to the bottomcenter of the screen
I created a buttomappbar in a scaffold i want to include a round button but i don't want to use the default fab. Im using another round button and i tried to align the button to the buttomcenter using the Align widget but it stays in the center.
class _MainActivityState extends State<MainActivity> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
backgroundColor: HexColor("ECEDEF"),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Icon(Icons.threed_rotation)
],
),
shape: CircularNotchedRectangle(),
color: Colors.white,
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Align(
alignment: Alignment.bottomCenter,
child: CircularGradientButton(
child: Icon(Icons.gradient),
callback: (){},
gradient: Gradients.rainbowBlue,
shadowColor: Gradients.rainbowBlue.colors.last.withOpacity(0.5),
),
)
)
);
}
}
I want the CircularGradientButton to come to the bottomcenter above the BottomAppBar
With a stack you can achieve that. Set fit property to: StackFit.expand then use a positioned with bottom:0 and width: MediaQuery.of(context).size.width.
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned(
bottom: 0,
width: MediaQuery.of(context).size.width,
child: Center(
child: MaterialButton(
onPressed: () {},
color: Colors.red,
),
),
)
],
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[Icon(Icons.threed_rotation)],
),
shape: CircularNotchedRectangle(),
color: Colors.white,
),
);

When keyboard is shown, everything is pushed up and I get a error

I have the following code:
class _MyHomePageState extends State {
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return new Scaffold(
body: new Column(
children: [
new Container(
color: JBTheme.colorGreenBrand,
height: 130.0,
alignment: Alignment.bottomLeft,
child: new Center(
child: new Align(
alignment: Alignment.bottomCenter,
child: new Container(
color: JBTheme.colorOrange,
constraints: new BoxConstraints(maxWidth: 270.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
new Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Image.asset("flags/flag_dk.png"),
new Container(
margin: const EdgeInsets.only(top: 4.0, bottom: 4.0),
child: new Text("Danmark"),
),
new Text("DKK")
],
),
new Expanded(child: new Image.asset("images/arrow.png")),
new Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Image.asset("flags/flag_us.png"),
new Container(
margin: const EdgeInsets.only(top: 4.0, bottom: 4.0),
child: new Text("USA"),
),
new Text("USD")
],
)
],
),
),
),
),
),
new Expanded(
child: new Container(
color: JBTheme.colorGreyMedium,
child: new Column(
children: [
new Expanded(child: new Container()),
new Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: new Card(
elevation: -8.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: new Container(
width: 200.0,
height: 30.0,
color: JBTheme.colorWhite,
child: new Stack(
children: [
new TextField(
textAlign: TextAlign.center
)
],
)
),
)
)
],
),
)),
new Container(
height: 260.0,
color: JBTheme.colorGreenMint,
)
],
));
}
}
And it looks like this:
But when I click the TextField and the keyboard opens I get this:
I did not expect all of my layout to be moved up by the full keyboard height, I would like it to only move up enough so that the focused TextField is visible (and not to give a error). How can I fix this, and why is it happening?
Thank you
Søren
There are two solutions to this problem.
Add resizeToAvoidBottomPadding: false to your Scaffold
Scaffold(
resizeToAvoidBottomPadding: false,
body: ...)
Put your Scaffold body inside a scrollableView (like SingleChildScrollView or ListView)
new Scaffold(
body: SingleChildScrollView(child: //your existing body
...)
You can find similar problem and answer here
This is Flutters way of showing us how many pixels of content will be hidden from users eyesight when using the keypad. Try setting resizeToAvoidBottomPadding to false... From docs:
Whether the body (and other floating widgets) should size themselves
to avoid the window's bottom padding.
Scaffold(
resizeToAvoidBottomPadding: false,
This will avoid the resizing so you will at least avoid the dev warning being shown. But remember user will not see some content, and also this is a developer warning.
Update on 17/10/2019
resizeToAvoidBottomPadding is now Deprecated.
Use resizeToAvoidBottomInset to specify if the body should resize when the keyboard appears.
Scaffold(
resizeToAvoidBottomInset: false,
If you just use SingleChildScrollView content looses vertical alignment. You can also wrap the SingleChildScrollView in a Center Widget.
child: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>...
A full description of this error and two possible solutions can be found on Medium article available on https://medium.com/zipper-studios/the-keyboard-causes-the-bottom-overflowed-error-5da150a1c660. The last one works great for me.