Flutter: Combining ScrollView and PageView Widgets - flutter

body: SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(height: 600, color: Colors.red),
Container( // <------ Container A
child: PageView(
controller: _activityPanelController,
children: [
Container(height: 300, color: Colors.white),
Container(height: 300, color: Colors.blue),
],
),
),
],
),
),
),
I want to set the Container A's height to its child to use the PageView widget inside the SingleChildScrollView in this case.
How can I achieve to put the PageView widget inside the SingleChildScrollView widget?

Unfortunately, you can't make PageView as high as it's children. You'd do so with IntrinsicHeight widget and by removing SizedBox, but you'll get the following error:
The following assertion was thrown during performLayout():
RenderViewport does not support returning intrinsic dimensions.
Also, you can't get rid of the SizedBox, because of the ListView (the same happens with Column and SingleChildScrollView), it's children get unbounded height, and PageView tries to get as big as possible. After removing SizedBox, you'll see this:
The following assertion was thrown during performResize():
Horizontal viewport was given unbounded height.
Working example:
#override
Widget build(BuildContext context) {
final boxHeight = 600.0;
return ListView(
children: <Widget>[
Container(height: boxHeight, color: Colors.red),
Container(height: boxHeight, color: Colors.deepPurpleAccent),
SizedBox(
height: boxHeight,
child: PageView(
controller: PageController(),
children: [
// ...
].map((e) => SingleChildScrollView(child: e)).toList(),
),
),
],
);
}
https://www.dartpad.dev/619458e188ce97f9cd1272441b7a3bf3?null_safety=true

Related

How to fix Flutter web release showing grey screen but no debug error

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.

How to make SingleChildScrollView fill full screen height with blank space where required

In my flutter app I need a layout where I'm able to scroll if all the widgets are too long for the screen,so I added a SingleChildScrollView. But, if the widgets are smaller and leave a lot of space, I want the last row to be pinned to the bottom of the screen with blank space between the last two items. So I added a Spacer to help with that.
However that causes an error, because the SingleChildScrollView doesn't like the Spacer. I've tried everything I know, but I can't find a layout that satisfies both conditions without an error. Can someone suggest a solution please?
Code below - you may have to alter the size (or number) of the containers to demonstrate the issue on your device.
class _TestMain extends State<TestMain> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
child: SingleChildScrollView(
child: Column(
children: [
Container(
color: Colors.blue,
height: 100,
),
Container(
color: Colors.yellow,
height: 100,
),
Container(
color: Colors.green,
height: 100,
),
Container(
color: Colors.pink,
height: 100,
),
// comment out these four containers to demonstrate issue
Container(
color: Colors.blue,
height: 100,
),
Container(
color: Colors.yellow,
height: 100,
),
Container(
color: Colors.green,
height: 100,
),
Container(
color: Colors.pink,
height: 100,
),
// SingleChildScrollView won't allow the Spacer
//const Spacer(),
Container(
color: Colors.blue,
height: 100,
child: Text("I'm always fixed to the bottom of the screen!"),
),
],
),
),
),
),
);
}
}
The error if I add the Spacer is:
======== Exception caught by rendering library =====================================================
The following assertion was thrown during performLayout():
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
When a column is in a parent that does not provide a finite height constraint, for example if it is in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the vertical direction.
These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child cannot simultaneously expand to fit its parent.
Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible children (using Flexible rather than Expanded). This will allow the flexible children to size themselves to less than the infinite remaining space they would otherwise be forced to take, and then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum constraints provided by the parent.
You can make use of CustomScrollView and SliverFillRemaining slightly differently to avoid letting the screen scroll when it's partially filled. This way we can make use of Spacer and Expanded widgets too!
Scaffold(
body: SafeArea(
child: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
children: [
Text("I'm at top part"),
Text("I'm at top part"),
Text("I'm at top part"),
const Spacer(),
Text("I'm at bottom"),
],
),
)
],
),
),
)
You can use
bottomNavigationBar from Scaffold.
return Scaffold(
bottomNavigationBar: Container(
color: Colors.blue,
height: 100,
child: Text("I'm always fixed to the bottom of the screen!"),
),
body: SafeArea(...
And
You can use CustomScrollView which is better than SingleChildScrollView; and use SliverFillRemaining will do the trick with Align widget.
class TestMain extends StatefulWidget {
TestMain({Key? key}) : super(key: key);
#override
State<TestMain> createState() => _TestMain();
}
class _TestMain extends State<TestMain> {
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: Container(
color: Colors.blue,
height: 100,
child: Text("I'm always fixed to the bottom of the screen!"),
),
body: SafeArea(
child: CustomScrollView(
slivers: [
/// your top level items
// SliverList(delegate: SliverChildBuilderDelegate((context, index) => ,)),
SliverList(
// better use `SliverChildBuilderDelegate`
delegate: SliverChildListDelegate([
// you can put regular container here
Container(
color: Colors.amber,
height: 100,
),
])),
SliverFillRemaining(
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.blue,
height: 100,
child: Text("I'm always fixed to the bottom of the screen!"),
),
),
)
],
),
),
);
}
}

A RenderFlex overflowed by 19 pixels on the bottom, while scrolling

In TabBarView -> Column, Iam getting this exception A RenderFlex overflowed by 120 pixels on the bottom.
while scrolling, It happens only on the particular part/container: TabBarView -> Column -> Container.
here is an image for better understanding sample image
here is the code for tabView.dart:
class TabView extends StatelessWidget {
List<Category> categories = [
];
final TabController tabController;
TabView({Key key, this.tabController}) : super(key: key);
#override
Widget build(BuildContext context) {
print(MediaQuery.of(context).size.height / 9);
return TabBarView(
physics: NeverScrollableScrollPhysics(),
controller: tabController,
children: <Widget>[
Column( **//Exception here**
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
margin: EdgeInsets.all(8.0),
height: MediaQuery.of(context).size.height/9,
width: MediaQuery.of(context).size.width,
// padding: EdgeInsets.only(top: 4.0),
child: ListView.builder(
//shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (_, index) => CategoryCard(
category: categories[index],
)),),
SizedBox(
height: 16.0,
),
Flexible(child: RecommendedList()),
],
),
Column(children: <Widget>[
SizedBox(
height: 16.0,
),
Flexible(child: RecommendedList())
]),
Column(children: <Widget>[
SizedBox(
height: 16.0,
),
Flexible(child: RecommendedList())
]),
Column(children: <Widget>[
SizedBox(
height: 16.0,
),
Flexible(child: RecommendedList())
]),
Column(children: <Widget>[
SizedBox(
height: 16.0,
),
Flexible(child: RecommendedList())
]),
]);
}
}
code for recommendedList.dart:
class RecommendedList extends StatelessWidget {
List<Product> products = [....];
#override
Widget build(BuildContext context) {
return Column( **//Exception here**
children: <Widget>[
Container(
height: 20,
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
IntrinsicHeight(
child: Container(
margin: const EdgeInsets.only(left: 16.0, right: 8.0),
width: 4,
color: Colors.lightBlue,
),
),
Center(
child: Text(
'Recommended',
style: TextStyle(
color: darkGrey,
fontSize: 16.0,
fontWeight: FontWeight.bold),
)),
],
),
),
Flexible(
child: Container(),
),//
],
);
}
}
These 2 classes are used in main page, here is the code:
return Scaffold(
resizeToAvoidBottomPadding: false,
bottomNavigationBar: CustomBottomBar(controller: bottomTabController),
body: CustomPaint(
painter: MainBackground(),
child: TabBarView(
controller: bottomTabController,
physics: NeverScrollableScrollPhysics(),
children: <Widget>[
SafeArea(
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
// These are the slivers that show up in the "outer" scroll view.
return <Widget>[
SliverToBoxAdapter(
child: appBar,
),
SliverToBoxAdapter(
child: topHeader, //child: ParallaxMain(),
),
SliverToBoxAdapter(
child: ProductList(
products: products,
),
),
SliverToBoxAdapter(
child: ProductList2(),
),
SliverToBoxAdapter(
child: tabBar,
),
];
},
body: Container(
child: TabView(
tabController: tabController,
),
//: MediaQuery.of(context).size.height/10,
),
),
),
CategoryListPage(),
CheckOutPage(),
ProfilePage()
],
),
),
);
and here is the exception i got:
A RenderFlex overflowed by 104 pixels on the bottom.
The relevant error-causing widget was:
Column file:///E:/arm%20dataset/flutter_ecommerce_template-m/lib/screens/main/components/tab_view.dart:59:11
The overflowing RenderFlex has an orientation of Axis.vertical.
The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the RenderFlex to fit within the available space instead of being sized to their natural size.
This is considered an error condition because it indicates that there is content that cannot be seen. If the content is legitimately bigger than the available space, consider clipping it with a ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex, like a ListView.
The specific RenderFlex in question is: RenderFlex#7b505 OVERFLOWING
... needs compositing
... parentData: <none> (can use size)
... constraints: BoxConstraints(w=411.4, h=13.1)
... size: Size(411.4, 13.1)
... direction: vertical
... mainAxisAlignment: start
... mainAxisSize: min
... crossAxisAlignment: center
... verticalDirection: down
◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
════════════════════════════════════════════════════════════════════════════════════════════════════
════════ (2) Exception caught by rendering library ═════════════════════════════════════════════════
A RenderFlex overflowed by 19 pixels on the bottom.
The relevant error-causing widget was:
Column file:///E:/arm%20dataset/flutter_ecommerce_template-m/lib/screens/main/components/recommended_list.dart:37:12
════════════════════════════════════════════════════════════════════════════════════════════════════
Please help me out.
Use ListView instead of Column should help.
Did you try using wrapping your Column with SingleChildScrollView widget like this?
SingleChildScrollView(
child: Column(
children: <Widget>[
Wrapping the Column widget with SingleChildScrollview should work.. Let me know if it worked for you..

Flutter Row widget solve RenderFlex overflow by cutting off remaining area

There are a lot of questions here already about Renderflex overflow, but I believe my use case might be a bit different.
Just the usual problem - having a Widget that is too big in a Row widget, and I get the A RenderFlex overflowed by X pixels ... error.
I want to create a Row that cuts off it's overflowing child Widget if they would be rendered outside it's area without getting an error.
First off, wrapping the last element in the Row widget with Expanded or Flexible does not work in my case, as recommended here and here and many other places. Please see code and image:
class PlayArea extends StatelessWidget {
#override
Widget build(BuildContext context) {
final dummyChild = Container(
color: Colors.black12,
width: 100,
child: Text('important text'),
);
final fadeContainer = Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Colors.black26,
Colors.black87,
],
),
),
width: 600,
);
return Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
color: Colors.redAccent,
child: Column(children: [
Expanded(
child: Row(
children: <Widget>[
dummyChild,
fadeContainer,
],
),
),
Expanded(
child: Row(
children: <Widget>[
dummyChild,
Expanded(
child: fadeContainer,
),
],
),
),
Expanded(
child: Row(
children: <Widget>[
Container(
color: Colors.black12,
width: 1100,
child: Text('important text'),
),
Expanded(
child: fadeContainer,
),
],
),
),
]),
),
);
}
}
Key points:
Using Expanded changes the width of Container, which changes the gradient's slope. I want to keep the gradient as it is
Even with Expanded widget, the Row is not prepared for the case when important text's area is too wide and does not fit the screen horizontally - it will get an overflow error for that Widget
it is technically working in the first case, because no red color is drawn on the right side on the green field, it 'just' has an error
How do I cut off the remaining space dynamically without any error - regardless of any screen size and content?
One solution I found is that
Row(
children: <Widget>[
dummyChild,
fadeContainer,
],
)
can be converted to
ListView(
scrollDirection: Axis.horizontal,
physics: const NeverScrollableScrollPhysics(),
children: <Widget>[
dummyChild,
fadeContainer,
],
)
Creating a horizontal list and preventing scroll on that.
edit.: just found out it that you'll get unbounded vertical height, so it's not the same.

ListView does not work as a child of Column or Row

I`m new in flutter framework and I want to use CustomLists.
My (body:) I wants to add a listviewBuilder into a Column but I give an empty page. if I use only listView in body part every things is fine.
Here is my Widget:
Widget _buildListView() {
return ListView.builder(itemBuilder: (BuildContext context, int index) {
return Dismissible(
key: Key('ke'),
onDismissed: (DismissDirection direction) {
if (direction == DismissDirection.endToStart) {
print('Swiped end to start');
} else if (direction == DismissDirection.startToEnd) {
print('Swiped start to end');
} else {
print('Other swiping');
}
},
background: Container(
color: Colors.red,
),
child: Container(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Column(children: <Widget>[
Row(
children: <Widget>[
Container(
margin: EdgeInsets.symmetric(
horizontal: 8.0, vertical: 2.0),
padding: EdgeInsets.all(4.0),
color: Colors.red,
child: Text('12'),
),
SizedBox(
width: 8.0,
),
Text('135'),
],
)
]),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
children: <Widget>[
Container(
color: Colors.green,
width: 15,
height: 10,
),
SizedBox(
width: 5,
),
Text('120'),
SizedBox(
width: 5,
),
Container(
color: Colors.yellow,
width: 15,
height: 10,
),
],
)
]),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text('30'),
])),
],
),
Divider()
],
)),
);
},itemCount: 10,);
}
I get this errors:
The following assertion was thrown during performResize():
I/flutter (14466): Vertical viewport was given unbounded height.
I/flutter (14466): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter (14466): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter (14466): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter (14466): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter (14466): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter (14466): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter (14466): the height of the viewport to the sum of the heights of its children.
add shrinkWrap property true for listview.
ListView.builder(
shrinkWrap:true,
itemBuilder: (BuildContext context, int index) {
return Container();
});
you have to wrap your ListView in a container that has the specified width and height values.
for example, wrap the ListView in the Container with height and with values or wrap it to an Expanded widget to fill the entire space its parent.
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: ListView.builder() // your list view builder widget
)
or
Expanded(
child: ListView.builder() // your list view builder widget
)
note that you should use the Expanded widget inside a flex widget that has specified the width and height values. like Column, Row , ...
Also, you should set the shrinkWrap value to true when using ListView inside another ListView widget.