Why does AspectRatio not work in a ListView? - flutter

Why does AspectRatio not preserve my aspect ratio when it is placed in a ListView?
Unexpected behaviour (doesn't preserve aspect ratio in a ListView)
return ListView(
children: [
Container(
height: 200,
child: AspectRatio(
aspectRatio: 1 / 2,
child: Container(
color: Colors.red,
),
),
),
],
);
Expected behaviour (works outside of a ListView)
return Container(
height: 200,
child: AspectRatio(
aspectRatio: 1 / 2,
child: Container(
color: Colors.red,
),
),
);

This is because "in the cross axis, the children are required to fill the ListView." So the ListView stretches the Container.
The solution will be to wrap the Container in a Center widget which helps maintain the child widget size "in case the parent widget has its own opinions regarding the size that the Container should take" like below:
Center(
child: Container(
height: 200,
child: AspectRatio(
aspectRatio: 1 / 2,
child: Container(
color: Colors.red,
),
),
),
)

Related

How to layout these widgets in Flutter?

I'm developing a desktop app using Flutter, which have three widgets as above, a scrollable widget, an expended widget with a min-width, and a fixed-width widget. Notice that, the first widget is a horizontal scroll widget, so its width depends on its contents.
I know the whole width, but to set the max-width of the scrollabe widget, I need to know the min-size of the Expanded widget and the width of the fixed-width widget.
As a newbie of Flutter, I really have no idea how to layout these widgets.
Andbody help!
Few ways of providing space like providing flex on Flexiable/Expnaded widget, using LayoutBuilder/MediaQuery or just provide Expanded one of it to get available space.
You can test this widget
return Scaffold(
body: LayoutBuilder(
// in case of needed
builder: (context, constraints) {
return Row(
children: [
SizedBox(
width: constraints.maxWidth * .6,
child: ListView.builder(
itemBuilder: (context, index) => ListTile(
tileColor: index.isEven ? Colors.red : Colors.deepPurple,
),
)),
//or just use Expanded for available width
Expanded(
child: Container(
// width:constraints.maxWidth * .4-100,
// constraints: BoxConstraints(
// minWidth: 200,
// // constraints.maxWidth * .6 - 100,
// maxWidth: constraints.maxWidth * .4 - 100,
// ),
color: Colors.cyanAccent,
child: Column(
children: [
Text("an Expamed with min 2idth"),
],
),
),
),
Container(
width: 100,
height: 200,
color: Colors.red,
child: Text("Fixed-width widget"),
)
],
);
},
),
);
You can use a row and use containers with constrains to achieve this layout. For example.
Row(
children:[
Container(
constrains: BoxConstrain(
maxWidth: MediaQuery.of(context).size.width*0.5
),
child: SingleChildScrollView ()
),
Expanded(
child : Container(
constrain : BoxConstrain (
minWidth : MediaQuery.of(context).size.width*0.2
)
)
),
SizedBox(
width: MediaQuery.of(context).size.width*0.3,
)
]
)

Flutter | How to fill the remaining space of a ListView?

In my Flutter app, I have a ListView:
return Scaffold(
body: SafeArea(
child: Container(
color: Colors.blueAccent,
child: ListView(
children: [
Container(
color: Colors.yellow,
height: 100
),
const SizedBox(height: 10),
// How to make this container fill up the remaining height?
Container(
color: Colors.black,
),
],
),
),
),
);
This produces the following view:
Question: How can I make the second box (with black background color) fill up the remaining space? If the content of the box exceeds the remaining space, the ScrollView will enable scrolling.
Is this possible?
There is a better option here using SliverFillRemaining in combination with CustomScrollView instead of a ListView
in your case the code will look like this.
Container(
color: Colors.blueAccent,
child: CustomScrollView(
shrinkWrap: true, // or false
slivers: <Widget>[
SliverToBoxAdapter(
child:Container(
color: Colors.yellow,
height: 100
),),
SliverToBoxAdapter(
child: SizedBox(height: 10),),
// use SliverFillRemaining to make this container fill up the remaining height?
SliverFillRemaining(
hasScrollBody: false, // if using a column, so the widgets in it, doesn't scroll
child:Container( //this container will fill the remaining space in the ViewPort
color: Colors.black,
),
) ,
],
),
),
Fill the remaining space of a ListView means filling the infinite height. I will prefer using Stack as body in this case, hope you can simply archive this.
How can we do without stack?
In this case, we can get the height and use it on Column and using Expanded on inner child that will fill the remaining spaces even for dynamic height.
I prefer using LayoutBuilder to get height.
body: LayoutBuilder(builder: (context, constraints) {
return SafeArea(
child: Container(
color: Colors.blueAccent,
child: ListView(
children: [
SizedBox(
// 1st child of listView
height: constraints.maxHeight,
child: Column(
children: [
Container(color: Colors.yellow, height: 100),
const SizedBox(height: 10),
Expanded(
child: Container(
color: Colors.black,
),
),
],
),
)
],
),
),
);
}),
You can get size and then set a proportion for each...
And set NeverScrollableScrollPhysics() to ensure no slight scrolling, as per below this appears to get what you are seeking.
Widget build(BuildContext context) {
Size _size = MediaQuery.of(context).size;
return Container(
child: Scaffold(
body: SafeArea(
child: Container(
color: Colors.blueAccent,
child: ListView(
physics: NeverScrollableScrollPhysics(),
children: [
Container(color: Colors.yellow, height: _size.height * 0.20),
SizedBox(height: _size.height * 0.10), // How to make this container fill up the remaining height?
Container(
height: _size.height * 0.70,
color: Colors.black,
),
],
),
),
),
));
}
}
Try below code hope its helpful to you. use MediaQuery here. add MediaQuery height to your black container
Refer blog also here for relative to screen size
Container(
color: Colors.blueAccent,
child: ListView(
shrinkWrap: true,
physics: ScrollPhysics(),
children: [
Container(
color: Colors.yellow,
height: 100,
),
const SizedBox(height: 10),
// How to make this container fill up the remaining height?
Container(
color: Colors.black,
height: MediaQuery.of(context).size.height,
),
],
),
),
Your result screen->

Grow a container while maintaining heights of the other containers in flutter

I have these three containers. That the first one needs to grow to cater for the children that will be in it. The second one could have a fixed height say a flex factor of 1, while the third one has a fixed height too say flex of 2. The whole of this screen can be scrollable. It actually has to be scrollable since the children of the first container can be a lot.
Note: the children of the first container will have a fixed height, the container will house a listview or column which will have fixed height children, say containers each of 50.0. How do I achieve this, especially the 'growability' of the first container, while maintaining the heights of the other containers.
What I have currently is
SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
child: ListView(
children: [
Flexible(
flex: 1,
child: Container(
color: Colors.blueAccent[200],
child: Column(children: [
Container(
height: 100.0,
color: Colors.greenAccent[200],
),
Container(
height: 100.0,
color: Colors.purpleAccent[200],
),
Container(
height: 100.0,
color: Colors.orangeAccent[200],
)
]),
)),
Expanded(
flex: 1,
child: Container(
color: Colors.redAccent[100],
),
),
Expanded(
flex: 1,
child: Container(
//height: 120.0,
color: Colors.redAccent[400],
),
),
],
),
),
),
Which just brings up lots and lots of errors, does not matter how I lay it out using flexibles and Expanded widgets. Again, I don't need the first container to scroll internally, it should grow according to the number of children in it, while the rest of the two containers maintain their heights.
You can not user Expanded or Flexible inside a scrollable widget since the child of Expanded will then get a height of infinity and the height of the child of Flexible will not get its parents height to compare with.
You can set the height of the bottom two containers based on the height of the screen.
SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
child: ListView(
children: [
Container(
color: Colors.blueAccent[200],
child: Column(
children: [
Container(
height: 100.0,
color: Colors.greenAccent[200],
),
Container(
height: 100.0,
color: Colors.purpleAccent[200],
),
Container(
height: 100.0,
color: Colors.orangeAccent[200],
)
],
),
),
Container(
// 33 % of the screen height
height: .33 * MediaQuery.of(context).size.height,
color: Colors.redAccent[100],
),
Container(
// 33 % of the screen height
height: .33 * MediaQuery.of(context).size.height,
color: Colors.redAccent[400],
),
],
),
),
),

Bottom Overflowed by Infinite Pixels by using Stack inside Column

I am using a stack widget to display animations inside a screen. I am using only 70% of the screen and the rest I have kept it unused. I want to display something else there. When I am wrapping my stack widget inside a column it is giving the error: Bottom Overflowed by Infinite Pixels.
I tried adding a custom height using Container and SizedBox. Also tried using SingleChildScrollView. Still the same error.
Code:
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: whiteColor,
body: Column(
children: [
Stack(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height * 0.72,
child: FlareActor(
'assets/videos/stars.flr',
alignment: Alignment.center,
fit: BoxFit.cover,
animation: 'Blink',
controller: _controller,
),
),
Container(
child: Transform.scale(
scale: 0.6,
child: FlareActor(
'assets/videos/talking-earth.flr',
alignment: Alignment.center,
fit: BoxFit.cover,
animation: 'activated',
controller: _controller,
),
),
),
Positioned(
left: MediaQuery.of(context).size.width / 3.8,
top: MediaQuery.of(context).size.width / 10,
child: Text(
"Published",
style: GoogleFonts.ptSansNarrow(
color: whiteColor,
fontSize: ScreenUtil().setSp(50),
fontWeight: FontWeight.bold),
),
),
],
),
Text("Test"),
],
),
);
}
}
You need to wrap your stack with a Container first, setting a predefined height. This is because the Stack size relies on its parent.
Here's the official documentation on Stack: https://api.flutter.dev/flutter/widgets/Stack-class.html

How to make the width of a container match its height

I have a Container which has a height based on its parent which is an Expanded with a flex of 2. I need the height and the width to be the same. I don't want to create a fixed width such as width: 100.0. Is it possible to make the width match the height of this Container inside an Expanded?
For that you'll have to use LayoutBuilder, here is the minimal code:
Column(
children: <Widget>[
Expanded(
flex: 2,
child: LayoutBuilder(
builder: (_, constraints) {
return Container(
color: Colors.blue,
width: constraints.maxHeight, // width is made equal to height
);
},
),
),
Expanded(
flex: 9,
child: Container(color: Colors.orange),
),
],
)
Edit: As #pskink and other mentioned you can also use AspectRatio
AspectRatio(
aspectRatio: 1,
child: Container(color: Colors.blue),
)
Aspect Ratio will work
AspectRatio(
aspectRatio: 1,
child: Container(
color: Colors.red,
),
)