I'm trying to display the data using GridView.count but it is not displaying all items. here is my code
class CategoriesBody extends StatefulWidget {
const CategoriesBody({Key? key}) : super(key: key);
#override
_CategoriesBodyState createState() => _CategoriesBodyState();
}
class _CategoriesBodyState extends State<CategoriesBody> {
Widget header() {
return Center(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.2,
width: MediaQuery.of(context).size.width,
child: Container(
color: appThemeColor,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Align(
alignment: Alignment.topLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
customText(context, "Available", 25.0,
FontWeight.w600, Colors.white),
customText(context, "Categories", 35.0,
FontWeight.w600, Colors.white),
]))))),
);
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: SingleChildScrollView(
child: objResult == ""
? Column(
children: [
header(),
showCircularLoader(context),
],
)
: objResult == "not connected"
? Column(
children: [
header(),
SizedBox30(),
noInternetConnection(context)
],
)
: apiError == "Server down"
? Column(
children: [
header(),
SizedBox30(),
serverError(context),
],
)
: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
header(),
//list of all categries
SizedBox(
height: MediaQuery.of(context).size.height *
0.97,
child: GridView.count(
crossAxisCount: 2,
scrollDirection: Axis.vertical,
children: List.generate(category.length,
(index) {
return InkWell(
child: customCategoryContainer(
context,
"assets/img/cat2.jpg",
category.length != 0
? category[index].title
: "",
18.0,
MediaQuery.of(context)
.size
.height *
0.18,
MediaQuery.of(context)
.size
.height *
0.18));
}))),
]))));
}
}
api response count is 12, but its displaying 10 items. please help where i'm doing wrong.
The items are probably there but larger than the screen height. And because you have a SingleChildScrollView and it's a scrollable widget, then the Grid is not scrollable, and the Grid and header are taking in total the full height of the screen and not more than that, so the SingleChildScrollView is also not scrollable.
One solution I can think of is to disable the scroll for the SingleChildScrollView widget and force scroll always for the Grid like so:
SingleChildScrollView(
physics: const NeverScrollableScrollPhysisc(),
//...
child: Column(
children: [
//...
SizedBox(
height: MediaQuery.of(context).size.height * 0.97,
child: GridView.count(
physics: const AlwaysScrollableScrollPhysics(),
//...
)
),
]
),
)
This will make the header fixed, and the grid scrollable within the screen height it occupies.
SingleChildScrollView(
physics: const NeverScrollableScrollPhysisc(),
//...
child: Column(
children: [
//...
Expanded(
child: GridView.count(
physics: const AlwaysScrollableScrollPhysics(),
//...
)
),
]
),
)
If this error happens to someone then set the height of SizedBox of GridView.count instead giving it to full screen height, this solve the issue.
Related
I have a Gridview builder to list items in flutter web. Render flex issue is happening when minimizing screen size. I gave aspect ratio based on screen size. But it is not working as expected. I used layout builder to get screen width.I gave static width but I think its not a good practice.
How to change the aspect ratio dynamically?
class CateGorySellectView extends StatefulWidget {
const CateGorySellectView({Key? key}) : super(key: key);
#override
State<CateGorySellectView> createState() => _CateGorySellectViewState();
}
class _CateGorySellectViewState extends State<CateGorySellectView> {
#override
Widget build(BuildContext conText) {
return Scaffold(
body: Center(
child: Row(
children: [
Expanded(
flex: 3,
child: Container(
child: Padding(
padding: const EdgeInsets.only(left: 80.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(right: 300.0),
child: LayoutBuilder(builder: (context, constraints) {
var parentWidth = constraints.maxWidth;
return GridView.builder(
itemCount: areaOfintrest.length,
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: parentWidth < 600 ? 3 : 5,
childAspectRatio: parentWidth < 350
? 300 / 250
: parentWidth < 700
? 200 / 150
: parentWidth < 800
? 200 / 170
: 180 / 87,
crossAxisSpacing: 7),
itemBuilder: (_, index) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: Obx(() {
return Padding(
padding: const EdgeInsets.only(
right: 0, top: 8),
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: AppColors.primaryColor)),
child: Stack(
children: [
Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Padding(
padding:
const EdgeInsets.only(
top: 4.0),
child: AutoSizeText(
areaOfintrest[index]
.toJson()[
'tag_display_name'],
textAlign: TextAlign.center,
),
)
],
)),
],
),
),
);
}),
);
});
}),
)
],
),
),
)),
],
)),
);
}
}
I have created a flutter webapp but I have a screen that shows a grey page not sure why, I think its something to do with the listview since all pages with the listview have the same problem. Can you take a look at the code below to figure out the problem?
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
endDrawer: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 300),
child: const SideMenu()),
body: SingleChildScrollView(
child: SafeArea(
child: Container(
width: size.width,
constraints: BoxConstraints(minHeight: size.height),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
const NavBar(),
This is where the grey screen start to appears
const BrowseScreenBody(),
const Footer(),
]),
),
),
),
);
}
}
class BrowseScreenBody extends StatelessWidget {
const BrowseScreenBody({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
final events = Event.events.toList();
return Container(
margin: const EdgeInsets.symmetric(vertical: 20, horizontal: 40),
child: Expanded(
child: Padding(
padding: ...,
child: Column(
children: <Widget>[
RichText(
text: TextSpan(
children: [
...
],
),
),
//Events Lists
SizedBox(
height: size.height * 0.65,width: size.width,
child: ListView.builder(
shrinkWrap: true,
itemCount: events.length,
itemBuilder: (context, index) {
final event = events[index];
return Card(
child: Container(
decoration: BoxDecoration(
color: Colors.white),
child: Padding(
padding: ...
child: Column(
children: [
Row(
children: [
Container(
height: size.height * 0.25,
width: size. Width * 0.4,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(...))),
),
Row(
children: [
Column(
children: [...
],
),
],
)
],
)
],
),
),
),
);
}),
),
],
),
),
));
}
}
Everything works well on debug mode, but when hosted to github pages I can't seem to get the widgets shown.
The problem is that you are using an Expanded as child of a Container. Expanded can only be a child of a Flex widget like Row or Column. But it's very likely that you actually do get errors in debug mode as well in your console. Because when I tried your code (slightly modified to make it runnable) it did give an error. Something like
======== Exception caught by widgets library =======================================================
The following assertion was thrown while applying parent data.:
Incorrect use of ParentDataWidget.
The ParentDataWidget Expanded(flex: 1) wants to apply ParentData of type FlexParentData to a RenderObject, which has been set up to accept ParentData of incompatible type BoxParentData.
Usually, this means that the Expanded widget has the wrong ancestor RenderObjectWidget. Typically, Expanded widgets are placed directly inside Flex widgets.
The offending Expanded is currently placed inside a Padding widget.
I'm learning flutter to make an app. Here I'm trying to make a page to show the full post. The problem is that the page isn't scrolling as a single unit.
class SinglePostPage extends StatefulWidget {
final Post? post;
const SinglePostPage({Key? key, this.post}) : super(key: key);
#override
State<SinglePostPage> createState() => _SinglePostPageState();
}
class _SinglePostPageState extends State<SinglePostPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: const EdgeInsets.only(top: 22.5),
padding: const EdgeInsets.fromLTRB(0, 5, 0, 6),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BackButton(),
Row(
children: [
InkWell(
onTap: () {
showDialog(...);
},
child: CircleAvatar(...),
Container(
padding: const EdgeInsets.only(left: 5.4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
showDialog(...);
},
child: Text(
widget.post!.author[0].profileName,
),
),
const SizedBox(height: 4),
Text(
showTimeAgo(widget.post!.postTime).toString(),
),
],
),
),
],
),
PopupMenuButton(
icon: const Icon(Icons.more_vert),
itemBuilder: (context) => [...],
),
Container(
margin: const EdgeInsets.fromLTRB(12, 9, 12, 3),
// when the text is longer than the screen height it showed RenderFlex overflowed error so I put constraints. how to show it full and make this scroll
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.54,
minHeight: 50),
child: SingleChildScrollView(
child: Text(
widget.post!.postText,
textAlign: TextAlign.start,
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (widget.post!.postMedia.isNotEmpty)
CarouselSlider.builder(...),
const SizedBox(height: 4.5),
if (widget.post!.postMedia.length > 1)
buildDotIndicator(widget.post!.postMedia),
],
),
],
),
),
Container(
// post reactions row
),
CommentBodyWidget(
postId: widget.post!.postId,
),
],
),
);
}
}
I looked up for other answers and tried wrapping it with SingleChildScrollView, but it didn't work , and ListView with shrinkWrap: true also gave 'Incorrect use of ParentDataWidget' error.
CommentBodyWidget has a listview builder. It's scrolling on its own but the widget above isn't scrolling along with it.
How can I show this whole page and scroll together without having to limit the long post in a constrained container? Please help.
You can wrap body Column with SingleChildScrollView and use shrinkWrap: true, and use physics: NeverScrollableScrollPhysics(),. This will solve the issue.
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
//...
ListView.builder(
itemCount: itemlength,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Text("item $index");
},
),
/// instead of listView
...List.generate(itemlength, (index) => Text("itemWidget"))
],
),
),
);
But I will encourage you to check CustomScrollView.
In order for the SingleChildScrollView to work, its parent's height should be defined.
You can achieve this by wrapping the SingleChildScrollView in a Container/SizedBox with defined height, or by wrapping it with the Expanded widget.
Pass SingleChildScrollView as body of your scaffold. Also shrinkwrap: true for the ListView is recommended so that it only takes up as much space as required, which will avoid unbounded height errors.
So instead of
...
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
...
Do this
...
Widget build(BuildContext context)
return Scaffold(
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(...
I recommend you to use CustomScrollView.
Try this:
CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column("""HERE PUT YOUR CODE""")
)]
),
I can't work this out. It should be really simple. (This is Flutter Desktop)
I want a Row with 2 columns. The first column should be full height available but only 200 wide. Column 2 should be full height and use the remainder of the width.
I have tried all sorts but always get an overflow rather than a scrollable list.
What am I doing wrong?
This is the last iteration of my code.
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bnode Management'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('This is the title'),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
width: 200,
child: ListView.builder(
shrinkWrap: true,
itemCount: piItems.length,
itemBuilder: (BuildContext context, int index) {
return Container(width: 40, color: Colors.red, child: Text(piItems[index].id));
}),
),
),
Container(color: Colors.blue, child: const Text('Column 1')),
],
),
],
),
);
}
}
The second Column like to have max space, therefor we can use Expanded on it instead of using on 1st Column. Also, the Row is needed to have max height. For this, we will wrap this Row with Expanded.
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('This is the title'),
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 200,
child: ListView.builder(
shrinkWrap: true,
itemCount: piItems.length,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 40,
color: Colors.red,
child: Text(piItems[index].id));
}),
),
Expanded(
child: Container(
color: Colors.blue,
child: Column(
children: [
const Text('Column 1'),
],
),
),
)
],
),
),
],
),
I also prefer using LayoutBuilder on body in this case.
You almost got it right, just mixed some things. Let's go step by step.
I want a Row with 2 columns
Ok, that's just a Row with two children.
Row(
children: [child1, child2],
)
The first column should be full height available but only 200 wide.
It would take the full height automatically but I see that in your code example you have a Column with Text title, so we should wrap our Row with Expanded. Also, the first Column should take 200 px.
Column(
children: [
const Text('This is the title'),
Expanded(
child: Row(
children: [
Container(
width: 200,
child: child1,
),
child2,
],
),
),
],
)
Column 2 should be full height and use the remainder of the width.
So we wrap our 2nd child with Expanded inside the Row.
Column(
children: [
const Text('This is the title'),
Expanded(
child: Row(
children: [
Container(
width: 200,
child: child1,
),
Expanded(
child: child2,
),
],
),
),
],
)
The end result based on your code:
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bnode Management'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('This is the title'),
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 200,
child: ListView.builder(
shrinkWrap: true,
itemCount: piItems.length,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 40,
color: Colors.red,
child: Text(piItems[index].id));
},
),
),
Expanded(
child: Container(
color: Colors.blue,
child: const Text('Column 1'),
),
),
],
),
),
],
),
);
}
}
My layout is a Form widget with some controls:
Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Form(
key: widget.addEventFormKey,
onChanged: () {},
child: Expanded(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(CustomResources.strings["add_event_category_label"], style: TextStyle(fontWeight: FontWeight.bold)),
/*some other widgets*/
Visibility(
child: Container(
height: 200.0,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _attachments?.length,
itemBuilder: (context, index) {
return Stack(
children: [
Container(
margin: EdgeInsets.fromLTRB(0, 0, 5, 0),
child: Stack(
children: [
ClipRRect(
child: Image.file(File(_attachments[index]), cacheWidth: 200),
borderRadius: BorderRadius.circular(8.0),
),
],
),
),
IconButton(
onPressed: () {
File(_attachments[index]).delete();
setState(() => _attachments.remove(_attachments[index]));
},
icon: Icon(FontAwesomeIcons.trash, color: Colors.white, size: 20),
padding: EdgeInsets.only(top: 4, left: 4),
constraints: BoxConstraints(),
),
],
);
},
),
),
visible: _attachments.length > 0,
),
Visibility(child: Padding(padding: EdgeInsets.fromLTRB(0, 18, 0, 0)),visible: _attachments.length > 0),
SizedBox(
child: RaisedButton(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24.0)),
onPressed: _attachments.length < 3 ? () => _pickImage() : null,
padding: EdgeInsets.all(12.0),
color: Colors.blue,
child: Text(CustomResources.strings["add_event_add_photo_button_label"], style: TextStyle(color: Colors.white))),
width: double.infinity,
),
],
),
),
),
),
],
);
Problematic part is ListView.builder to display horizontally scrolled list of images. As you can see, picture will always get fixed width (200) and unknown height, because height depends from image aspect ratio. ListView.builder is wrapped with Container, so now it has constant height 200.
I want to force my ListView.builder to expand to child image height (it's single row ListView scrolled horizontally), image width always 200 and other widgets should be placed below it without any remaining space. With current approach, if image height is < 200, there will be remaining space left below image list. If image height is >200, image will be scaled (width/height).
I tried to wrap list view with Expanded widget instead Container, but it throws exception:
RenderFlex children have non-zero flex but incoming height constraints
are unbounded.
It says I still need to provide height, which I don't want to. How to solve this?
I think that's not possible with ListView.builder, because its height with dynamic items is not known while building widgets tree. Instead, my thumbnail widgets mus be built upfront, and added to Row after they have been built and wrap row with SingleChildScrollView to make it scrollable. So, my thumbnails list ready to place to my Form:
class AttachmentsListWidget extends StatelessWidget {
const AttachmentsListWidget({
Key key,
#required this.items,
#required this.onAttachmentDeleted,
}) : super(key: key);
final List<String> items;
final Function(String) onAttachmentDeleted;
#override
Widget build(BuildContext context) {
var _thumbnailsScrollController = ScrollController();
final thumbnails = <Widget>[];
Widget thumbnailsWidget;
if (items.length > 0) {
for (int i = 0; i < items.length; i++) {
thumbnails.add(
AttachmentWidget(
attachment: items[i],
onDeleteClicked: (String attachment) => onAttachmentDeleted(attachment),
),
);
}
thumbnailsWidget = Container(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Scrollbar(
isAlwaysShown: true,
controller: _thumbnailsScrollController,
child: SingleChildScrollView(
controller: _thumbnailsScrollController,
scrollDirection: Axis.horizontal,
child: Row(
children: thumbnails,
crossAxisAlignment: CrossAxisAlignment.start,
),
),
),
],
),
);
} else {
thumbnailsWidget = Container();
}
return thumbnailsWidget;
}
}
(also, always visible scrollbar added).
If you got RenderFlex children have non-zero flex but incoming height constraints are unbounded. try below code hope its help to you. add your Column inside Expanded() Widget and remove SingleChildScrollView() in your code
Expanded(
child: Column(
children:[
//Your Widgets
],
),
),