I'm trying to layout two widgets. The top one is a PhotoView and the bottom is a slider. I need the slider to take up as much room as it needs, and the rest to be taken up by the PhotoView.
I tried using a Column class to wrap everything.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GestureDetector(
onTapDown: (TapDownDetails details) {print("Tapped");}),
child: Column(children: [
Container(
child: Center(
child: Container(
margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Container(
child: hasPermission
? PhotoView(
imageProvider:
FileImage(filename)),
)
: Text("Waiting"),
)),
)),
Slider(
min: 0,
max: 10,
value: 5,
onChanged: (double value) {
print(value);
},
),
])),
);
}
The problem is that it overflows on the bottom, saying that "BOTTOM OVERFLOWED BY infinity PIXELS".
I suspect that the reason is that PhotoView is unbounded, and so is column, but I need the PhotoView to be bounded by the limit of the view height - slider height.
It's not the slider which is unbounded. Wrap the top part (Container which indirectly contains PhotoView) in Expanded (https://docs.flutter.io/flutter/widgets/Expanded-class.html).
I'd recommend not going the route of computing heights and widths manually, as often the same effect can be achieved without it and then you get reacting all dynamic window geometry changes (like phone orientation changing) "for free".
Related
I have the following in my widget's build method:
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Title bar'),
),
body: Center(
child: SizedBox(
width: 250,
child: ListView(
children: [
const Text('Text goes here'),
Container(
width: 250,
height: 250,
color: Colors.green,
child: Texture(textureId: textureId)), // ID of a texture that displays pixels
],
),
),
),
floatingActionButton: FloatingActionButton(
child: const Text('Button'),
onPressed: () {
noisy();
},
),
));
What I want to have take place is that the Texture widget is always 250x250 pixels, regardless of what I resize the window to. When I resize the window vertically, this is what happens, and the overflow of the widget that goes past the bottom of the screen is just clipped and ignored. However, when I resize horizontally making the window less wide than the widget, the widget is scaled horizontally, getting compressed in that direction instead of being clipped to the right. What arrangement if widgets would I need in order to keep the Container/Texture at 250x250 pixels and have it clipped past the end of the window instead of being compressed?
I have tried surrounding the inner Container in another horizontal ListView, as the outer ListView appears to clip the window vertically correctly, but that causes RenderBox was not laid out: RenderRepaintBoundary#51231 relayoutBoundary=up5 NEEDS-PAINT.... I also attempted placing that inner ListView in another Container/SizedBox, though this did not fix the shrinking issue and cause it to clip instead.
Try using unconstrainedBox
UnconstrainedBox(
child: SizedBox(
)
)
This allows a child to render at the size it would render if it were alone on an infinite canvas with no constraints. This container will then attempt to adopt the same size, within the limits of its own constraints. If it ends up with a different size, it will align the child based on alignment. If the box cannot expand enough to accommodate the entire child, the child will be clipped.
In debug mode, if the child overflows the container, a warning will be printed on the console, and black and yellow striped areas will appear where the overflow occurs.
simple, use ConstraintBox & set it minHeight and minWidth
ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 100,
minHeight: 100,
maxWidth: 100,
maxHeight: 100,
),
)
I have a list of widgets (from a list of objects that have an x and y coordinate value) of the same size I want display in a grid arrangement, the size and placement wont change.
My initial thought is to use 2 for loops for the columns and rows and pass the widgets as children accordingly.
But would a Stack widget or CustomMultiChildLayout be more performant and suited for this? Given that columns and rows are made to be more dynamically sized and I don't need that functionality.
Edit: Image, literally just a grid of tiles at the moment. It's currently using loops of columns+rows. Yes I will be flipping the Y around to start at the bottom corner.
You can use a gridview to create this layout
class MyHomePage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Scaffold(
body: GridView.count(
crossAxisCount: 15,
children: List.generate(225, (index) {
return GridTile(
child: Container(
height: 50,
width: 50,
color: Colors.blue.shade200,
child: Center(
child: Text('$index'),
)
),
);
}),
),
);
}
}
Or In a wrap
Wrap(
children: List.generate(225, (index) => Container( width: 20, height: 20, child: Text("$index")))
)
Code
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('Search Families'),
centerTitle: true,
),
backgroundColor: StaticEntry.backColor,
body: Center(
child: FractionallySizedBox(
widthFactor: 0.8,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SearchInput(onSubmitHandler: onSubmit),
SizedBox(
height: 300,
),
resultList.isNotEmpty
? Container( // <---------------- Container that I am using to wrap the list view widget
height: 400, // <---------------- fixed height I am setting on the container that is wrapped around the ListView widget
child: ListView.builder( // <---------------- ListView widget
itemCount: 20,
itemBuilder: (context, index) {
return Text('Heyyyy!');
},
),
)
: SizedBox()
],
),
),
),
),
);
}
Problem
In the above code, as I have pointed using arrows, I am wrapping a ListView widget in a Container and assigning a fixed height to that Container since ListView widgets has an infinite height by default.
The problem with this approach is, since that height I am providing to the container is a fixed height, the layout breaks on devices with small viewport heights, while it works fine with devices that has a large viewport height.
So what I am trying to figure out is, how can I set a height to that Container that works on all devices without breaking the layout? (I am trying to make that height as maximum as possible without making the app break on smaller devices.)
(While researching about this, I came across this stack overflow link and according to that link, I tried wrapping the ListView widget with a Flexible widget and set the shrinkWrap property of the ListView widget to true. This did not work and it caused my ListView widget and the other widget to gain as much space as possible between them and pushed my ListView widget to the bottom of the screen.)
I have 2 widget in stack. One of them is aligned in center. And the widget which is on the top is other stack. And I want show second widget with first widget's top and left position. Here is the explain:
The yellow area is my stack. And first widget is setted like Center(child: myFirstWidget). My second widget is referenced from here it's a resizable widget so it's an another stack and it's childs are "positioned". So I need to set top and left value for initialize. But my main stack filled page So when I set my second widget's top and left to 0. It's shown as below.
But I want to show align it to centered child's top like:
My code snip:
child: Container(
color: Colors.red,
child: Stack(
children: [
Center(
child: Image.file(
File("myfilepath"),
),
),
ResizableWidget(
child: Container(
color: Colors.blue,
),
),
],
),
),
You can adjust the position of the widgets with the Position widget like this:
Positioned(
child: ResizableWidget(
child: Container(
color: Colors.blue,
),
),
top: 80,
right: -5,
),
The value of top and right are just random values, you should check what works for you!
You should make Center the parent of the Stack.
The Stack will be positioned at the center of its parent because of Center, it will get the dimensions of its biggest childs (height and width) and will position other childs according to the alignment value.
Edit : I modified the code to include a placeHolder image. Here I gave it a 6000x2000 size but you can change it to whatever value you want. Code is working as expected, see capture below.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Stack(
alignment: AlignmentDirectional.topStart,
children: [
Image.network('https://via.placeholder.com/6000x2000'),
SizedBox(
height: 50,
width: 50,
child: Container(
color: Colors.green,
))
],
),
),
);
}
child:Column(
children: <Widget>[
Container(
height: double.infinity,
width: 100.0,
color: Colors.red,
child: Text('hello'),
),)
in this,when i make height:double.infinity,it gives error in run saying **BoxConstraints forces an infinite height.**but when i give height manually it work fine.
can anyone explain me why this happening.
How about this one.
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
children: <Widget>[
Expanded(
child: Container(
// height: double.infinity,
width: 100.0,
color: Colors.red,
child: Text('hello'),
),
),
],
),
),
);
}
}
This means that you can't offer inifite height to the container. It's obvious behaviour if you don't provide the contraints to height.
You have to specify limited height to the container so that flutter can render it, if you offer it infinite it how can flutter render that and up to which constraints it would do that !
Rather you can set double.infinity to width and flutter will successfully render that because by default flutter has constraints for width it will set width to width of screen.
Considering that you have to provide height as that of screen you can use MediaQuery for that
Widget yourMethod(or build)(BuildContext context){
final screenHeight = MediaQuery.of(context).size.height;
return Column(
children:<Widget>[
Container(
height:screenHeight,//but this will be height of whole screen. You need to substract screen default paddings and height of appbar if you have one
width:100.0,
....
)
]);
}
Hope this helps !
Happy coding..
BoxConstraints forces an infinite height
Why This Happens
You're asking to render an infinite height object without a height constraint... Flutter can't do that.
Column lays out children in two phases:
Phase 1: non-Flex items (anything not Expanded, Flexible or Spacer)
done in unconstrained space
Phase 2: Flex items (Expanded,Flexible, Spacer only)
done with remaining space
Phase 1
Column's phase 1 vertical layout is done in unbounded space. That means:
no vertical constraint → no height limit
any widget with infinite height will throw the above error
you can't render an infinite height object in an infinite height constraint... that's goes on forever
Phase 2
after Phase 1 widgets have taken as much space as they intrinsically need, phase 2 Flex items share the remaining/leftover space
the remaining space is calculated from incoming constraints minus Phase 1 widgets dimensions
double.infinity height will expand to use up the remaining space
Infinite Height is OK
Here's an example of using infinite height on a Container inside a Column, which is fine:
class ColumnInfiniteChildPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Flexible(
child: Container(
height: double.infinity, // ← perfectly fine
child: Text('Column > Container > Text')),
),
Text('Column > Text')
],
),
),
);
}
}
Remove the Flexible and the error will be thrown.