StreamBuilder
Listview.builder
Card(
child: Container(
width: double.infinity,
padding: EdgeInsets.all(10),
child: Column(
children: [
CardMenuTitle(id: menu.title),
CardMenuImage(menu: menu, index: index),
... ]
...
Now in cardmenuimage
Widget build(BuildContext context) {
return Stack(
children: [
Container(), //just tried to add empty container to see if it fixes the problem
Positioned(
top: 1, //if I remove this line, it works,
child: Container(
width: double.infinity,
// needed
color: Colors.transparent,
child: Image.asset(
"assets/images/menu/${menu.image}",
fit: BoxFit.cover,
),
),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
splashColor: Colors.black.withOpacity(0.5),
onTap: () {
}, // needed
),
),
),
],
);
}
}
The following assertion was thrown during performLayout():
BoxConstraints forces an infinite width.
These invalid constraints were provided to _RenderColoredBox's layout() function
by the following
function, which probably computed the invalid constraints in question:
RenderConstrainedBox.performLayout
(package:flutter/src/rendering/proxy_box.dart:279:14)
The offending constraints were:
BoxConstraints(w=Infinity, 0.0<=h<=Infinity)
Positioned(
top: 1, //if I remove this line, it works,
child: Container( //removing container solves the problem but image is not displayed
width: double.infinity,
// needed
color: Colors.transparent,
child: Image.asset(
"assets/images/menu/${menu.image}",
fit: BoxFit.cover,
),
),
),
After removing the container from the position widget, the error goes away but image is not displayed.
replace width: double.infinity with width: MediaQuery.of(context).size.width
Related
I am new to Flutter and was practicing its UI where I came across a situation where I had a list where each list element have an image on the left and some text on right.
Below is my approach to that
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 20),
children: [
const SizedBox(height: 5),
Row(
children: [
Container(
height: 80,
width: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: const DecorationImage(
image: NetworkImage('http://images.unsplash.com/photo-1555010133-d883506aedee?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max'),
fit: BoxFit.cover
)
),
),
const SizedBox(width: 10),
Container(
color: Colors.green,
height: 80,
width: 280,
)
],
),
],
),
Here I am specifying width individually for both containers which is not an efficient way to do this since phone sizes may vary.
Below is the result for above block of code
Screenshot of the app screen
I tried specifying crossAxisAlignment: CrossAxisAlignment.stretch to the Row() but it throws an error as below
The following assertion was thrown during performLayout():
BoxConstraints forces an infinite height.
How can I achieve this? Please assist
Thank you
Wrap the widget with an Expanded inside the row:
Row(
children: [
...otherChildren,
Expanded(
child: Container(
color: Colors.green,
height: 80,
),
),
],
),
Use ListView.builder with ListTile widgets. It has a leading widget (normally an icon or an avatar) to the left, text in the middle and trailing widget (normally an icon), each of which is optional.
ListView.builder(
itemCount: ...,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: const CircleAvatar(
radius: 20.0,
foregroundImage: NetworkImage(...),
),
title: Text(...),
subtitle: Text(...),
trailing: ...,
onTap: () => ...,
);
},
)
I'm using a Stack to Positioned one widget on top of an Image.asset widget, but the problem I have is that my whole Stack widget is not scrollable to see the whole content. I wrapped the Stack widget with a SingleChildScrollView but the problem still persists. If I wrap the Stack widget with a Containter and give the height: MediaQuery.of(context).size.height, it's scrollable but I can't still see the whole content of the page. Where is my mistake, that's what I'm wondering? With what widget should I wrap Stack or is there a better way for my problem? In short, I'm stacking a Column on top of an Image and I need the whole Stack widget to be scrollable so I can see the whole content of the Stack widget. Here is the code:
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: SafeArea(
child: SingleChildScrollView(
child: Stack(
overflow: Overflow.visible,
children: [
Image.asset(
'lib/modules/common/images/logo.png',
width: double.infinity,
height: 196.0,
),
Positioned(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
top: 136.0,
child: Column(
children: [
Container(), // some content inside the container
Container(), // // some content inside the container
],
),
),
],
),
),
),
);
}
Thanks in advance for the help!
if you mean to have a image on back and scrollable content at fron check this answer, if not let me know and share a prototype/image that you want.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: SafeArea(
child: SingleChildScrollView(
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 3,
child: Stack(
fit: StackFit.loose,
children: [
Align(
alignment: Alignment.topCenter,
child: Image.asset(
'assets/image.jpg',
width: double.infinity,
height: 196.0,
),
),
Positioned(
top: 136.0,
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisSize: MainAxisSize.min,
children: List.generate(
2,
(index) => Container(
height: 100,
width: double.infinity,
color: index % 2 == 0
? Colors.amberAccent
: Colors.cyanAccent,
), // some content inside the container
// some content inside the container
),
),
),
),
],
),
),
),
),
);
}
I have a simple card design, my card is wrapped with a container with a specific height and width, so the children are bounded
The card has a picture from Image.network and a text at the bottom, both occupying half the height of the card
However, my code receives this error:
Error: Cannot hit test a render box that has never been laid out.
From what I know, constraints goes down the tree and children return the size to the parent. I know the column would not pass constraints to the children, however, the two expanded widget SHOULD know to take up half of the card's height?
My goal is to understand WHY this doesn't work, moreover than the actual working code. thank you!
Code:
var height = MediaQuery.of(context).size.height;
return Container(
height: height * 0.45,
width: double.infinity,
child: Card(
elevation: 4,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Column(
children: [
Expanded(
flex: 1,
child: FittedBox(
child: Image.network('https://source.unsplash.com/random'),
),
),
Expanded(
flex: 1,
child: Container(
child: Text("hello"),
),
)
],
)),
);
The problem is that FittedBox tries to scale its child to fit accordingly; thus the child needs to be laid out before. Because the child is an image being loaded in this example, it's not laid before the fitting. To overcome this issue, you can use a SizedBox.expand instead of the FittedBox:
Container(
height: height * 0.45,
width: double.infinity,
child: Card(
elevation: 4,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Column(
children: [
Expanded(
flex: 1,
child: SizedBox.expand(
child: Image.network('https://source.unsplash.com/random'),
),
),
Expanded(
flex: 1,
child: Container(
child: Text("hello"),
),
)
],
)),
)
-Don't use MediaQuery inside the build Methode, before the return.
-Avoid redundant argument: https://dart-lang.github.io/linter/lints/avoid_redundant_argument_values.html for the flex: 1
Use fit: BoxFit.contain
return Container(
height: MediaQuery.of(context).size.height* 0.45,
width: double.infinity,
child: Card(
elevation: 4,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Column(
children: [
Expanded(
flex: 1,
child: Image.network('https://source.unsplash.com/random',fit: BoxFit.contain),
),
Expanded(
flex: 1,
child: Container(
child: Text("hello"),
),
)
],
)),
);
Even if the ModalBarrier is wrapped with a GestureDetector, it doesn't trigger taps outside the Container. But replace ModalBarrier with Container and it works.
The Container becomes a workaround but why doesn't it work with ModalBarrier?
Here's the code:
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: _onDropdownTap(),
child: Stack(
fit: StackFit.expand,
children: [
ModalBarrier(
color: Colors.black26,
),
Positioned(
left: width/2 - cardWidth/2,
top: height/2 - cardHeight/2,
width: dropdownWidth,
height: dropdownHeight,
child: Container(
color: Colors.red,
),
),
],
),
);
I'm trying to create a circle image. Unfortunately, the width of the container is not honoured and I can't figure out why. What am I missing?
Drawer _getDrawer(List<Job> data) {
return Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the Drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
_getDrawerHeader(),
ListTile(
title: Text('Item 1'),
onTap: () {
// Update the state of the app
// ...
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app
// ...
},
),
],
),
);
}
DrawerHeader _getDrawerHeader() {
return DrawerHeader(
child: StreamBuilder(
stream: FirebaseAuth.instance.currentUser().asStream(),
builder: (context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.hasData) {
return ListView(
children: <Widget>[
_getCircleImage(snapshot.data.photoUrl),
Text('test'),
Text('test'),
],
);
}
return Center(child: CircularProgressIndicator());
}),
decoration: BoxDecoration(
color: Colors.blue,
),
);
}
_getCircleImage(String url) {
return Container(
width: 64.0,
height: 64.0,
decoration: new BoxDecoration(
image: new DecorationImage(
image: new NetworkImage(url),
fit: BoxFit.cover,
),
shape: BoxShape.circle,
),
);
}
That's a little tricky but it's how Flutter works, your Container doesn't know the constraints of the Parent, then It try to fill all the space available.
You can fix it adding an Align Widget
_getCircleImage(String url) {
return Align(
alignment: Alignment.centerLeft,
child: Container(
width: 64.0,
height: 64.0,
decoration: new BoxDecoration(
image: new DecorationImage(
image: new NetworkImage(url),
fit: BoxFit.cover,
),
shape: BoxShape.circle,
),
),
);
}
More info : https://docs.flutter.io/flutter/widgets/Container-class.html
A widget can decide its own size only within the constraints given to it by its parent. This means a widget usually can’t have any size it wants.
A widget can’t know and doesn’t decide its own position on the screen, since it’s the widget’s parent who decides the position of the widget.
The parent widget takes the entire space available to draw the widget, Here Container is the parent widget, and it's taking whatever space is available, so to give heigh/width to the Container, that needed to be placed inside any widget which assigns x,y position of widgets to get it to draw.
So as per the above description, Container should have a parent that aligns Container on the screen.
Ex: Use
Align(
alignment: Alignment.center,
child: Container(),
);
OR
Center(
child: Container(),
);
Problem:
Container's constraints wont' have any impact if the passed constraints were tight.
For example:
SizedBox.fromSize(
size: Size.fromRadius(100), // Tight constraints are passed to the Container below
child: Container(
width: 100, // No impact
height: 100, // No impact
color: Colors.blue,
),
)
Solutions:
You need to loose those tight constraints. There are multiple ways of doing it. I'm listing a few here:
Use UnconstrainedBox:
SizedBox.fromSize(
size: Size.fromRadius(100),
child: UnconstrainedBox( // <-- UnconstrainedBox
child: Container(
width: 100, // Works
height: 100, // Works
color: Colors.blue,
),
),
)
Use Center or Align:
SizedBox.fromSize(
size: Size.fromRadius(100),
child: Center( // <-- Center
child: Container(
width: 100, // Works
height: 100, // Works
color: Colors.blue,
),
),
)
Use a Column or better Wrap:
SizedBox.fromSize(
size: Size.fromRadius(100),
child: Wrap( // <-- Wrap
children: [
Container(
width: 100, // Works
height: 100, // Works
color: Colors.blue,
),
],
),
)