Row mainAxisAlignment is not working after wrapping with FittedBox
Please explain me why this is happening.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: 20,
child: FittedBox(
fit: BoxFit.fill,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('THis is the thing'),
Text('THis is another thing'),
],
),
),
)
);
}
Expected
Output
If you really want to use Row inside FittedBox with effect of mainAxisAllignment.spaceBetween or any, you have to manually set spaceBetween using SizedBox with width as per spacing. Also set fit property to BoxFit.fitHeight .
Container(
height: 20,
child: FittedBox(
alignment: Alignment.center,
fit: BoxFit.fitHeight,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('THis is the thing',style: TextStyle(fontSize: 20),),
SizedBox(width: 300,),
Text('THis is another thing',style: TextStyle(fontSize: 20,),),
],
),
),
)
Note: Set allignment property to specify positioning. for MainAxisAllignment.start and MainAxisAllignment.start.
Eg: Alignment.topLeft to get MainAxisAllignment.start effect.
To answer your question,
Row mainAxisAlignment is not working after wrapping with FittedBox
Please explain me why this is happening.
Container always fills the entire width of the screen size. If it has child, then it will wraps up itself to match the width of its child.
Another interesting widget FittedBox will fits its children based on the size of the children within itself by scaling based on available space.
Solution
To achieve the expected result, you can force set the width of Container widget to double.infinity
Snippet
body: Container(
height: 20,
width: double.infinity,
child: FittedBox(
fit: BoxFit.fill,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [Text('THis is the ROW'), Text('THis is another ')],
),
),
)
NOTE : If texts are small it will be enlarged to occupy the rest of the space because it is inside the FittedBox and vice-versa.
Related
I am using a CustomScrollView and tried to limit its children's size by using BoxConstraints but they are simply ignored. My text expands to the width of the screen and I don't understand why.
This is my code:
SliverToBoxAdapter(
child: ConstrainedBox(
constraints: maxWidthConstraint,
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.project.description,
),
],
),
),
),
),
What am I missing here? Let me know if you need any more info!
The parent forces it to be the full width so you can wrap it with UnconstrainedBox or Align or Center widget to get rid of that behavior.
SliverToBoxAdapter(
child: UnconstrainedBox( // this should allow it to have its own constraints
child: ConstrainedBox(
constraints: maxWidthConstraint,
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.project.description,
),
],
),
),
),
),
)
I have the below layout and want to push CustomPaints at the end of the page for any screen size, how to achieve that? I tried Spacer but got an error and tried Flexible but I don't know how to use them properly.
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
const HeaderShape(),
const SizedBox(
height: 50,
),
body,
SizedBox(
height: 150,
child: Stack(
children: [
CustomPaint(
painter: const FooterPainter1(),
child: Container(),
),
CustomPaint(
painter: const FooterPainter2(),
child: Container(),
),
],
),
),
],
),
),
);
}
You can not use spacer in a column widget, if you did not wrap your column widget with a container/sizedBox with a definite height.
Flexible widget will wrap your widget to take the available space of the parent widget, but will NOT force the child to fit the space.
Expanded will share the available space of the parent widget, and force the child widget to change its width/height to fill the available space.
So, wraping you column with a sizedbox with height and using spacer widget will help you to achieve what you are looking for. Check the code below:
SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height -kToolbarHeight - MediaQuery.of(context).padding.top -MediaQuery.of(context).padding.bottom,
child: Column(
children: [
Container(child: Text('My Header')),
const SizedBox(
height: 50,
),
Container(child: Text('My Body')),
Spacer(),
Container(child: Text('My Footer')),
],
),
),
)
If you are not using appbar in your page, just remove kToolbarHeight and MediaQuery.of(context).padding.top from your SizedBox height parameter.
I'm trying to create a scrollable column that has a widget at the bottom of the screen if it does not fill it up. However, if it does it scrolls.
First I tried with a simple Column with MainAxisSize.max and Expand with an empty Container which worked well until the column overflowed.
[...]
Column(
mainAxisSize: MainAxisSize.max,
children: [
MyWidget(),
MyWidget(),
[...],
MyWidget(),
Expand(child: Container()),
ElevatedButton()
],
)
Then I searched and found the recommended solution for making a Column scrollable is the SingleChildScrollView. This made all of my widgets in the column disappear (which I am still unsure why) until I removed the Expand which although solved one problem, introduced another.
[...]
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
MyWidget(),
MyWidget(),
[...],
MyWidget(),
// Expand(child: Container()),
ElevatedButton()
],
)
)
So my question is, how can I make a Column both scrollable and if it does not need all the space to expand so that the last child is at the bottom of the screen?
IntrinsicHeight is too expensive to use but in this situation you have no choice. Try this:
LayoutBuilder(builder: (context, constraint) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: Column(
children: [
Container(
color: Colors.red,
height: 400,
width: double.infinity,
),
Expanded(
child: Container(
color: Colors.blue,
width: double.infinity,
),
),
],
),
),
),
);
})
in this example if you set height for blue container you will see the scrollview works, and if you use Expanded on it, it takes the available size.
I have a Text() widget I am trying to stack on a CircularProgressIndicator()
I thought it would be as simple as just wrapping them both in a Stack() widget but the text is not centered.
I tried wrapping the Text() in a Center() widget but that did not solve the issue:
return Expanded(
child: PageView(
controller: pageViewController,
children: [
PackSummaryWeightGraph(
categoryWeightList: categoryWeightList,
totalWeight: totalWeight),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Stack(
children: [
Text((packedItemsPercent * 100)
.toString()),
SizedBox(
height: 150,
width: 150,
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
],
),
),
],
),
const Center(
child: Text('Third Page'),
),
],
),
);
Bonus points if there is a way to have the CircularProgressIndicator() fill the space without hard coding its width and height...
Stack has an alignment argument:
Stack(
alignment: Alignment.center,
children: [...],
),
If you want to fill the given space use the SizedBox.expand constructor:
SizedBox.expand(
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
One issue with the above is that if the available space has a different height than width you will end up with an oval shaped indicator rather than a circle. You can avoid this by wrapping it in an AspectRatio widget:
AspectRatio(
aspectRatio: 1,
child: SizedBox.expand(
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
),
See complete demo:
import 'package:flutter/material.dart';
void main() {
double packedItemsPercent = .67;
runApp(
MaterialApp(
home: Scaffold(
body: Stack(
alignment: Alignment.center,
children: [
Text((packedItemsPercent * 100).toString()),
AspectRatio(
aspectRatio: 1,
child: SizedBox.expand(
child: CircularProgressIndicator(
value: packedItemsPercent,
),
),
),
],
),
),
),
);
}
Make sure that any widget like Expanded or SizedBox.expand is not inside of an infinite sized container like a ListView or similar. Expanded means to take up the maximum available space, but that isn't possible if you have an infinite amount of space.
You'll need to set the alignment of the Stack to center:
Stack(
alignment: Alignment.center,
children: [
// ...
],
);
To get the circular progress indicator to fill the space, you should be able to use a FittedBox with a Positioned.fill widget:
Stack(
children: [
Positioned.fill(
child: FittedBox(
fit: BoxFit.fill,
child: CircularProgressIndicator(
value: packedItemsPercent
),
),
),
],
);
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
),
),
);