I have a list storing the asset image location. Using that list I display those many cards of certain width side by side inside a website.
When the items in list increases, the row overflows. I want those cards to appear below, To have rest of cards in another line.
I'm returning this row to a singleChildScrollView parent widget.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: ProjectData.map((item) => Container(
constraints: BoxConstraints(maxHeight: 320, maxWidth: 240),
child: Card(
child: Image.asset(item.fileLoc),
),
)).toList(),
),
This row sits under a Column() widget and this entire Column is returned to a SingleChildScrollView()
Use the Wrap widget:
A widget that displays its children in multiple horizontal or vertical runs.
In your case, you can use as follows:
Wrap(
spacing: 8.0, // gap between adjacent cards
runSpacing: 4.0, // gap between lines
children: ProjectData.map((item) => Container(
constraints: BoxConstraints(maxHeight: 320, maxWidth: 240),
child: Card(
child: Image.asset(item.fileLoc),
),
)).toList(),
)
You can use GridView class, since, you can keep count of the item you want to show in per row. Basically GridView.count() is the one for you.
To control the number of items in it, the power will be given by crossAxisCount
Do not forget to give height to the GridView(), else, you will see a lot of errors coming up. It needs a parent height
We are passing the item as arrayname.map((item) => Your_Widget()).toList().cast<Widget>()
I have used my myArray for dummy show purpose. Feel free to use yours. The idea is to give you the best possible option
In case you wanna explore SingleChildScrollView class it will come in handy
LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Container(
height: MediaQuery.of(context).size.height * 0.7,
width: MediaQuery.of(context).size.width,
child: GridView.count(
crossAxisCount: 2, // here you keep track of count
children: myArray.map((item) => Container(
margin: EdgeInsets.only(left: 15.0, right: 15.0, top: 15.0),
constraints: BoxConstraints(maxHeight: 320, maxWidth: 240),
decoration: BoxDecoration(
color: Colors.redAccent,
borderRadius: BorderRadius.circular(15.0)
)
)).toList().cast<Widget>()
)
)
)
);
}
)
Result
Feel free to try it out.
Related
I have a widget that exceeds the size of the display and I would like to show different parts depending on user input.
When using this code:
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.red,
...
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Transform.translate(
offset: const Offset(-50, 0), // offset hardcoded to -50
child: Container(
width: 2000,
height: 100,
color: Colors.yellow,
),
...
The widget respects the constraints, so the container is fitted to the display. After the transform, you see the background instead of a continuation of the widget.
I could wrap the widget in an UnconstrainedBox:
UnconstrainedBox(
alignment: Alignment.topLeft,
child: Transform.translate(...)
)
This fixes the problem, but results in an error:
A RenderConstraintsTransformBox overflowed by 1500 pixels on the
right.
I want it to overflow, I don't think this is an error! Any ideas on how I can fix this?
Note: I could use a SingleChildScrollView with NeverScrollableScrollPhysics() and use the controller to set position, but to me, this feels like overkill. Hope there is a simpler method. Thanks for the read :)
UnconstrainedBox is not the widget to use for getting rid of inner child overflow warnings. It's used to loosen the constraints.
You can use an OverflowBox in this case. Usage example:
SizedBox(
width: 100,
height: 100,
child: OverflowBox(
minWidth: 150,
minHeight: 150,
maxWidth: 150,
maxHeight: 150,
child: FlutterLogo(),
),
)
i am trying to align list view items at the top left, but it aligns them in the center. I tried this with another widget, it works fine, but with the listview, it doesn't.
here is my code
Container(
height: height * 30,
// color: Colors.grey[400],
alignment: Alignment.topLeft,
child: ListView.builder(
itemBuilder: (context, i) => ReviewItem(
review: book.reviews[i]['review'],
date: book.reviews[i]['date'],
),
itemCount: book.reviews.length,
),
),
this is the review item
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
timeago.format(DateTime.parse(date)),
style: Theme.of(context).textTheme.headline4.copyWith(
fontSize: width * kFont12Ratio, color: Colors.grey[500]),
),
SizedBox(height: height * 0.5),
Text(review),
Divider(),
],
);
Thanks in advance
By default, ListView will automatically pad the list's scrollable extremities to avoid partial obstructions indicated by MediaQuery's padding. In other words, if you put a widget before the ListView, you should wrap the ListView with a MediaQuery.removePadding widget (with removeTop: true). Like so:
MediaQuery.removePadding(
context: context,
removeTop: true,
child: ListView.builder(...),
);
I achieved that by adding padding inside the listview builder
padding: EdgeInsets.only(top: 0),
You can use padding instead
Or use Stack with Position (top:0,left:0)
Or use Align( )
I'm trying to expand the height of a given grid of cards, so they are able to fit some more information than they currently do. These cards are wrapped by a GridView.count() that is shrinked, since I'm going to put more things below this widget.
As for now, the cards look like these, in which you can see that one of them overflows the text at the bottom, which is an undesired behavior (especially when I want the cards to have some bottom padding):
Being this the case, I would like to know if it's possible to manually change the card's height. I'm maybe letting this concrete configuration stay and remove some info, since I like the fact that the cards currently maintain their 1x1 proportion, but for curiosity sake, I would like to discover how to do this.
I tried many things, such as wrapping the Card widget with a Container or a SizedBox and manually setting the height, but none of these approaches change anything.
I guess that the problem may be in the GridView itself. This is how it looks:
return FutureBuilder<List<Event>>(
future: new EventsService().getEventsForCoords(),
builder: (context, AsyncSnapshot<List<Event>> snapshot) {
if (snapshot.hasData) {
return GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
children: generateProximityEventCards(snapshot.data));
} else {
return CircularProgressIndicator();
}
});
As you can guess, the generateProximityEventCards method is the one that prints the Card widgets at the end. This is how the method looks as for now:
List<Widget> generateProximityEventCards(List<Event> eventList) {
// Render each card
return eventList.map((Event ev) {
return Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 5,
margin: EdgeInsets.all(7),
child: SizedBox(
height: 600,
child: Column(
children: <Widget>[
Image(
alignment: Alignment.topCenter,
fit: BoxFit.fitWidth,
image: ev.imageUrl,
height: 110,
width: 200,
),
Container(
child: Text(ev.name),
padding: EdgeInsets.only(left: 10, right: 10),
),
Container(
child: Text(ev.startDate.toString()),
padding: EdgeInsets.only(left: 10, right: 10),
),
Container(
child: Text(ev.address),
padding: EdgeInsets.only(left: 10, right: 10),
),
],
),
));
}).toList();
}
So, in conclussion: how can I change the height of the cards so they can hold more information?
Thanks!
GridView isn't really designed to have tiles of different size. A good option is to use the package flutter_staggered_grid_view.
Now your tile sizes can even be dynamic, check out the code for the gif above!
To automatically fit some variable length text somewhere you can use the package auto_size_text.
Flutter Newbie here.
Please refer to this example from Flutter docs Example
I have added just 4 lines to that code. You will find those lines which has comment "Lines Added by me".
But there is no change in the output.
Widget build(BuildContext context) {
return DefaultTextStyle(
style: Theme.of(context).textTheme.bodyText2,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
print(viewportConstraints.minWidth); // Lines Added By me
print(viewportConstraints.maxWidth); // Lines Added By me
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
maxWidth : viewportConstraints.minWidth/2, // Lines Added By me
minWidth : viewportConstraints.minWidth/2, // Lines Added By me
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
// A fixed-height child.
color: const Color(0xffeeee00), // Yellow
height: 120.0,
alignment: Alignment.center,
child: const Text('Fixed Height Content'),
),
Container(
// Another fixed-height child.
color: const Color(0xff008000), // Green
height: 120.0,
alignment: Alignment.center,
child: const Text('Fixed Height Content'),
),
],
),
),
);
},
),
);
}
So I am just playing with that example. And i wanted to see that if i can control the width of containers by providing maxWidth to constrainedBox. But its not working and i want to know reason/concept behind that?
Now in section layout behaviour of container says that "If the widget has an alignment, and the parent provides bounded constraints, then the Container tries to expand to fit the parent, and then positions the child within itself as per the alignment."
Can someone explain me where i am wrong in my understanding ?
From the above ScreenShot it seems that proper(width/2) constraints are not passed to column.
I would like to have a drop shadow on each item and each item should overlap the top of the next sibling.
It's probably too late for the original poster, but maybe it will help someone else looking for this:
The best solution I found to this (without resorting to a manually managed stack) is to use an Align widget with a height factor of less than 1. This will cause the next item to overlap with the previous one.
Here are the key elements to make this work:
final elements = ['A', 'B', 'C'];
final padExtend = 16.0;
final media = MediaQuery.of(context);
return ListView.builder(
itemCount: elements.length,
itemBuilder: (BuildContext context, int index) {
final String content = elements[index];
return Align(
child: Container(
width: media.size.width - padExtend / 2.0,
padding: EdgeInsets.all(padExtend),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(color: Colors.grey, spreadRadius: 3, blurRadius: 3, offset: Offset(2, 1)),
],
color: Colors.white,
),
child: Text(content),
),
alignment: Alignment.topCenter,
heightFactor: 0.9,
);
},
);
Since the align would center the elements, a media query is used to set a fixed width.
Wraping your elements with OverflowBox and giving the maxHeight value will achieve this effect.
return SizedBox(
height: 35, //--> list children will be 35 in height
child: OverflowBox(
maxHeight: 50, // --> allowing the child to overflow will cause overlap between elements
child: Container(
height: 50,
child: Text((index + 1).toString()),
),
),
);
use SizedOverflowBox (preferred) or OverflowBox, it is very easy to implement such effects... Flutter YYDS
You could try my package (signed_spacing_flex). It's exactly the same as a normal Column (or Row and Flex). But it lets you set negative spacing which causes its children to overlap.
You can also set which children should be on top when they overlap.
It works with expanded children if you need.
You can use a elevation and padding top to achieve the effect you want :
ListView.builder(
itemCount: 5,
itemBuilder: (BuildContext content, int index) {
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Material(
elevation: 5.0,
child: new Container(
height: 100.0,
),
),
);
})
If you want to overlap your items just use a heightFactor below 1.0
return Align(
alignment: Alignment.topLeft,
heightFactor: 0.9,
child: your item...