problem SingleChildScrollView with PageView flutter - flutter

I want to add SingleChildScrollView in my page but i have PageView.
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new IneatAppBarPollWidget()
.getAppBar('Blackblox', 'assets/img/logo_ineat.png', cand),
body: new Center(
child: SingleChildScrollView(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Expanded(
child: new Container(
child: new FutureBuilder<List<PollQuestionsDto>>(
future: _future,
// ignore: missing_return
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Failed connection API');
case ConnectionState.waiting:
return new Text('Wait...');
case ConnectionState.done:
if (snapshot.hasData) {
if (snapshot.data != null) {
return PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, index) {
print(this.responses);
return PollListViewItem(
entitled:
snapshot.data[index].entitled,
answers:
snapshot.data[index].answers,
currentAnswer:
this.responses[index],
onSelect: (Answer answer) {
this.responses[index] = answer;
},
);
},
);
}
}
break;
case ConnectionState.active:
}
}),
),
),
new ProgressBar(),
new Container(
margin: EdgeInsets.only(right: 10.0),
child: new RaisedButton.icon(
onPressed: () async {
//await Poll().submitPoll(answers: answers);
setState(() {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) =>
PollPage()));
});
},
label: Text('Suivant'),
icon: Icon(Icons.navigate_next),
),
alignment: Alignment.bottomRight,
),
],
),
),
),
);
}
}
When I added this, I have this error :
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.
RenderBox was not laid out: RenderFlex#4c442 relayoutBoundary=up12 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1681 pos 12: 'hasSize'

I recreated your case with a sample data. Below are the issues that I fixed:
Column used inside SingleChildScrollView expands to fill vertical space by default if we don't set the mainAxisSize for it. So here, you will need to add mainAxisSize: MainAxisSize.min, which tells column to take only the minimum space.
The children to be displayed inside Column were wrapped in Expanded which again takes up default space for its child. Here, instead of Expanded, use Flexible which takes the space as applicable to its child.
The Container used to display the data from future builder again expands to the entire screen if not provided a height. So just provide a custom height to the Container.
Working code below:
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Container(
height: 200,
child: FutureBuilder<Post>(
future: post,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Failed connection API');
case ConnectionState.waiting:
return new Text('Wait...');
case ConnectionState.done:
if (snapshot.hasData) {
if (snapshot.data != null) {
return PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: 5,
itemBuilder: (BuildContext context, index) {
return Card(
child: Text('test'),
);
},
);
}
}
break;
case ConnectionState.active:
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
)
),
Container(
margin: EdgeInsets.only(right: 10.0),
child: new RaisedButton.icon(
onPressed: () {},
label: Text('Suivant'),
icon: Icon(Icons.navigate_next),
),
alignment: Alignment.bottomRight,
)
],
),
)
),
Based on the sample data I used, I was able to see below result and was able to scroll horizontally to see the data properly.

Related

Two direction scrolling in data table flutter

I made a DataTable in flutter and it has about 10 columns and that's more than what the screen can handle so I wrapped the DataTable inside a SingleChildScrollView widget and this solution worked fine until the rows inside the DataTable grew up and exceeded the screen height and I couldn't scroll down because of the scroll direction is set to horizontal in the SingleChildScrollView widget!
And as a temporary solution, I wrapped the DataTable inside a fittedBox inside the SingleChildScrollView but this doesn't solve the whole problem and still, there is some responsibility issues.
What I need is a way to make the DataTable scrollable in both directions horizontally and vertically.
This is my code
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(16),
child: Card(
child: Container(
padding: const EdgeInsets.all(16),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: FutureBuilder(
future: getCategories(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return FittedBox(
child: DataTable(
headingRowColor: MaterialStateProperty.resolveWith(
(states) => Colors.grey.shade900),
columns: _columns,
rows: _rows,
),
);
}
},
),
),
),
),
);
}
The easiest solution I know, is to wrap the SingleChildScrollView in a second SingleChildScrollView.
https://stackoverflow.com/a/57539405/1151983
But there are also other approaches:
https://stackoverflow.com/a/63546017/1151983

Use of Listview.builder makes the screen go away

I want to show Listview underneath my two widgets but when i hot reload, nothing happens and if i run again, UI shows blank screen. If i remove Listview.builder it works fine.
Below is my code.
import 'package:flutter/material.dart';
import 'package:plant_clone/constants.dart';
import 'package:plant_clone/model/model.dart';
import 'package:plant_clone/screens/home/components/header_with_searchbox.dart';
import 'package:plant_clone/screens/home/components/title_with_more_btn.dart';
import 'package:plant_clone/viewmodel/recommended_plants_viewmodel.dart';
class Body extends StatelessWidget {
RecommendedPlantViewModel recommendedPlantViewModel =
new RecommendedPlantViewModel();
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
recommendedPlantViewModel.setWidgetsData();
return SingleChildScrollView(
child: Column(
children: [
HeaderWithSearchBox(size: size),
TitleWithMoreButton(
title: "Recommended",
press: () {},
),
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) {
return Card(
child: ListTile(
onTap: (){},
title: Text('Hello'),
),
);
})
],
),
);
}
}
It doesn't look like there's any other way than setting height constraint using a SizedBox that's wrapping a ListView.
Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: size.height,
child: ListView.builder(
...
),
),
],
)
https://flutter.dev/docs/cookbook/lists/horizontal-list
i think it happened because the list view should have a height,,
the esiest way is to test that put it inside a container and give a height to it..
and the second way is wrap the listview inside a Expanded widget and it will fix ..
if not then post the error from debug log
In order to make this to work, you must wrap your ListView with a Container and define the height property as it is part of a Column. You also need to wrap the widget returned by the itemBuilder with a Container and define the width property as the scrollDirection is set to Axis.horizontal.
Container(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) {
return Container(
width: 100,
child: Card(
child: ListTile(
onTap: () {},
title: Text('Hello'),
),
),
);
},
),
)

Make ListView from background of the stack scrollable

I have a Stack that has some containers and horizontal listView at the very bottom of it.(Intentionally, it's a part of design). Now that I'm trying to scroll through it, it doesn't work because top container make it unreachable sort of. How can I remain the same widget tree but make the bottom listView scrollable?
return Stack(
children: <Widget>[
AnimatedBuilder(
animation: ctrl,
builder: (context, child){
var pos = ctrl.position.pixels;
return Container(
height: pos<h?(pos/h * 250):250,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (ctxt, index){
return Container(
height: pos<h?(pos/h * 250):250,
width: 250,
child: Image(), //Horizontal listview
);
},
),
);
},
),
ListView(
controller: ctrl,
children: <Widget>[
AnimatedBuilder(
animation: ctrl,
builder: (context, child){
var pos = ctrl.position.pixels;
return Container(
height: pos<h?(pos/h * 250):250,
);
},
),
//This is the container I'm talking about, it's just like padding(It's nothing in there)
],
),
],
);
You could put the ListView after the Container in the order inside the Stack, so it will be over the Container and you can interact with it.
Or you could wrap the Container with IgnorePointer, so the gestures won't be intercepted by the Container and you could interact with the ListView.

Vertical ListView inside horizontal SingleChildScrollView

I need to build a page with lists of objects that are grouped in a single line. This needs to be scrolled both vertically (to show more groups) and horizontally (to show groups children).
The vertical and horizontal scroll needs to move the items altogether.
Something like this: https://gph.is/g/46gjW0q
I'm doing this with this code:
Widget _buildGroups() {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container(
width: 2000,
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: boardData.length,
itemBuilder: (context, index) {
return Row(children: _buildSingleGroup(index));
},
),
),
);
}
List<Widget> _buildSingleGroup(int groupIndex) {
return List.generate(...);
}
I need this to be horizontally dynamic but here, as you can see, I need to set a width cause otherwise an error occurs:
══════════════════ Exception caught by rendering library ═════════════════════
The following assertion was thrown during performResize()
Vertical viewport was given unbounded width.
Viewports expand in the cross axis to fill their container and constrain their
children to match their extent in the cross axis. In this case, a vertical
viewport was given an unlimited amount of horizontal space in which to expand.
I tried to set "shrinkWrap: true" in the ListView but the result gives another error:
Failed assertion: line 1629 pos 16: 'constraints.hasBoundedWidth': is not true.
So how do you do this with a dynamical ListView width?
The error happens because when ListView tries to get height from its parent to fill the entire height, the parent returns infinity height because SingleChildScrollView doesn't have fixed container height value. To fix that issue you need to limit the height value. For example, I used SizedBox to specify height for ListView.
The following code works for me.
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 120, // <-- you should put some value here
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: items.length,
itemBuilder: (context, index) {
return Text('it works');
},
),
),
],
),
);
Please can you explain your guess about the objects size?
I have a solution, but in my solution , flutter will build all objects (In both axes) for first frame. And build again any setState in the three. So its not good solition.
Last scroll offset horizontally
and
But I'll explain anyway.
///
class BothAxisScroll extends StatefulWidget {
#override
_BothAxisScrollState createState() => _BothAxisScrollState();
}
class _BothAxisScrollState extends State<BothAxisScroll> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.all(30),
child: Container(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: _build(),
),
),
),
),
),
);
}
}
List<Widget> _build() {
return List.generate(
20,
(index) => Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: _buildSingleGroup(index),
));
}
List<Widget> _buildSingleGroup(int _index) {
return List.generate(
Random().nextInt(20),
(index) {
print('BUILD: $_index');
return Container(
padding: const EdgeInsets.all(15), child: Text("$_index-$index"));
},
);
}
and result in first frame :

Flutter ListView.Builder() in scrollable Column with other widgets

I have a TabBarView() with an amount of different views. I want of them to be a Column with a TextField at top and a ListView.Builder() below, but both widgets should be in the same scrollable area (scrollview). The way I implemented it threw some errors:
#override
Widget build(BuildContext context) {
return new Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: new TextField(
decoration: new InputDecoration(
hintText: "Type in here!"
),
)
),
new ListView.builder(
itemCount: _posts.length, itemBuilder: _postBuilder)
],
);
}
Error:
I/flutter (23520): The following assertion was thrown during performResize():
I/flutter (23520): Vertical viewport was given unbounded height.
I/flutter (23520): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter (23520): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter (23520): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter (23520): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter (23520): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter (23520): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter (23520): the height of the viewport to the sum of the heights of its children.
I read about stacking the ListView.builder() in an Expanded-Area but it made the textfield kind of "sticky" which is not what I want. :-)
I also came across CustomScrollView but didn't fully understand how to implement it.
Here is the solution:
SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(
children: <Widget>[
Text('Hey'),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount:18,
itemBuilder: (context,index){
return Text('Some text');
})
],
),
),
Placing the ListView inside an Expanded widget should solve your problem:
#override
Widget build(BuildContext context) {
return new Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: new TextField(
decoration: new InputDecoration(
hintText: "Type in here!"
),
)
),
new Expanded(child: ListView.builder(
itemCount: _posts.length, itemBuilder: _postBuilder))
],
);
}
Use SingleChildScrollView which allows the child widget to scroll
Solution
SingleChildScrollView(
child: Column(
children: <Widget>[
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
Two properties used here
shrinkWrap: true
only occupies the space it needs (it will still scroll when there more items).
physics: NeverScrollableScrollPhysics()
Scroll physics that does not allow the user to scroll. Means only Column+SingleChildScrollView Scrolling work.
Reason for the error:
Column expands to the maximum size in main axis direction (vertical axis), and so does the ListView
Solution
You need to constrain the height of the ListView, so that it does expand to match Column, there are several ways of solving this issue, I'm listing a few here:
If you want to allow ListView to take up all remaining space inside Column use Flexible.
Column(
children: <Widget>[
Flexible(
child: ListView(...),
)
],
)
If you want to limit your ListView to certain height, you can use SizedBox.
Column(
children: <Widget>[
SizedBox(
height: 200, // constrain height
child: ListView(),
)
],
)
If your ListView is small, you may try shrinkWrap property on it.
Column(
children: <Widget>[
ListView(
shrinkWrap: true, // use it
)
],
)
Use physics: NeverScrollableScrollPhysics() and shrinkWrap: true inside ListView.Builder() and enjoy
Here is an efficient solution:
class NestedListExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
const SliverToBoxAdapter(
child: Text('Header'),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(ctx, index) {
return ListTile(title:Text('Item $index'));
},
),
),
],
);
}
}
Here is a preview on dartpad.
You can use a SliverToBoxAdapter for the other children as only Slivers can be a direct child of a CustomScrollView.
If all the list items are the same height, then you could use SliverFixedExtentList, which is more efficient because the height of each child isn't calculated on the fly, but you will have to know the exact pixel height. You could also use a SliverPrototypeExtentList, where you provide the first item in the list(the prototype), and all the other children will use the height of the prototype so you don't need to know the exact height in pixels.
Use Expanded widget to constrain without overflowing those pixels, :)
Column(
children: <Widget>[
Expanded(
child: ListView(),
),
Expanded(
child: ListView(),
),
],
)
just add
Column(
mainAxisSize: MainAxisSize.max, //Add this line onyour column
children:[
SomeWidget(),
Expanded(child:ListView.builder())
]
)
In my case with a future i did it like this:
SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("Hey ho let's go!"),
Flexible(
child: FutureBuilder(
future: getData(),
builder: (BuildContext context,
AsyncSnapshot<List<Sale>> snapshot) {
if (snapshot.connectionState != ConnectionState.done ||
snapshot.hasData == null) {
return CircularProgressIndicator();
} else {
data = snapshot.data;
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return dataItemWidget(size, data[index], context);
},
itemCount: data.length,
);
}
},
),
),
],
),
),
//If you want Listview.builder inside ListView and want to scroll the parent ListView// //whenever the Items in ListView.builder ends or start you can do it like this
body: ListView(
physics: ScrollPhysics(),
children: [
SizedBox(height: 20),
Container( height: 110.0 *5, // *5 to give size to the container //according to items in the ListView.builder. Otherwise will give hasSize Error
child:ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: 5,
itemBuilder: (BuildContext context, int indexChild) {
return InkWell(child:Container(height:100));}))
),]),
The best way will be to make the column scrollable by making the column child of SingleChildScrollView and then assigning the same ScrollController to both the SingleChildScrollView and the ListView.builder. This will make the text field and the below ListView as scrollable.
Just add physics: NeverScrollableScrollPhysics() in ListView.builder() so you can scroll
Add physics: NeverScrollableScrollPhysics() inside Listview.builder() method and the nested Listview will scroll
Column is not scrollable, which is why the TextField on top wouldn't scroll but the ListView on the bottom would.
The best way to solve this in my opinion is to make your TextField the first item in your ListView.
So you won't need a column, your parent widget is the ListView, and its children are the TextField followed by the remaining items you build with _postBuilder.
return Column(
children: [
Text("Popular Category"),
Expanded(
child: ListView.builder(`enter code here`
shrinkWrap: false,
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("hello"),
],
);
}),
),
],
);
body: SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(
children: [
getFiltersOnHomePage(),
SizedBox(
child: StreamBuilder(
stream: FirebaseFirestore.instance.collection('posts').snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (ctx, index) => Container(
margin: EdgeInsets.symmetric(
horizontal: width > webScreenSize ? width * 0.3 : 0,
vertical: width > webScreenSize ? 15 : 0,
),
child: PostCard(
snap: snapshot.data!.docs[index].data(),
),
));
},
),
),
],
),
),[enter image description here][1]***You will be able to scroll through the page by using Expanded Widget
Blockquote
Using this you can scroll over the entire page. This page includes a row and a listview builder inside a scrollable column.
In my case, I added a Container with transparent color and height up to 270 to solve this one.
Column(
children: <Widget>[
ListView(
shrinkWrap: true, // use it
),
Container(
color: Colors.transparent,
height: 270.0,
),
],
)