Flutter SingleChildScrollView not scrolling - flutter

My singleChildScollView won't scroll vertically. I've checked similar questions regarding this problem but none of them sem to work for me.
The page fills up with the items, and the homepage button is placed at the bottom...
...so it looks correct, it just doesn't let me scroll.
Can anyone help? [ EDIT - please note in the example code below I have simplified the original widget tree and removed the homepage button]...
Scaffold(
body: SingleChildScrollView(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (ctx, index) {
...list of items here...
}
),
),
)

There is two steps you can do to use SingleChildScrollView in a Column widget
Wrap it in a SizedBox
Set a height to the SizedBox widget
Try this out :
Scaffold(
body:
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(
//set a height
height : MediaQuery.of(context).size.height/5,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (ctx, index) {
...list of items here...
}
),
],
),
),
),
Center(
child: ElevatedButton(
onPressed: () {Navigator.pop(context);},
child: Text('Homepage'),
),
),
],
),
)

#james please check it
Scaffold(
body: Stack(
children: [
SingleChildScrollView(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: ScrollPhysics(),
itemCount: 30,
itemBuilder: (ctx, index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Text("index $index"),
);
}
),
),
Align(
alignment: Alignment.bottomCenter,
child: ElevatedButton(
onPressed: () {Navigator.pop(context);},
child: Text('Homepage'),
),
),
],
),
)

thanks for the help, expecially #Jahidul Islam.
I was missing the physics: ScrollPhysics() line!

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, or by wrapping it with the Expanded widget.

Related

Why do I get this error when using Expanded

After many attempts and trying different things, I get the same error ( throw constraintsError ) as soon as I add Expanded, while the error disappears by deleting it,, i I want the upper part to be fixed and the other part to be Scrollable
thanks
SingleChildScrollView(
child: Column(
children: [
Column(
children: [
Container(), // fixed
Row(), // fixed
**Expanded**(
child: Container(
color: constants.kLightGrayColor,
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
controller: controller.scrollController,
itemCount: data.posts.length,
itemBuilder: (context, index) {
firstly cannot used Expanded inside SingleChildScrollView.
to work normally pls remove SingleChildScrollView widget and remove outer Column,
used one of Column in green box.
it is small example
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
Container(
height: 200,
width: MediaQuery.of(context).size.width,
color: Colors.red,
child: const Center(child: Text("Fixed Box")),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(
title: Text("$index"),
);
},
),
),
],
),
);
}

Make RefreshIndicator work on whole screen (ListView)

While looking for solutions, I found some related discussions, but none of the solutions worked in my case.
I made a "RefreshableScrollFrame" widget in my app, which offers a generic frame for pages that should show a StatusBar (loading indicator, etc.) and which should provide a pull-down to refresh.
RefreshableScrollFrame
return Center(
child: Column(
children: [
SizedBox(
height: 4,
child: const MyStatusbarWidget(),
),
RefreshIndicator(
onRefresh: onRefresh,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: child,
),
)
],
),
);
Child Option - ListView:
ListView.builder(
itemCount: items.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, i) => Card(
child: ListTile(
title: Text(items[i].name),
),
),
);
Child Option - Column with the ListView and static items:
Column(
children: [
ListView.builder(
itemCount: items.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, i) => Card(
child: ListTile(
title: Text(items[i].name),
),
),
),
...someStaticWidgets,
],
);
So far so good, everything works fine, except for one important detail.
The RefreshIndicator is only triggered in areas, which are covered by the child widget. If the content is small and covers just the top of the page, the gesture is detected only in that area.
If the content is just an empty ListView, I won't even be able to trigger a refresh.
I tried several suggested solutions in order to "expand" the child to the whole screen, but I always ran into exceptions, when trying to get rid of shrinkWrap, when adding Expanded(), and so on.
Any hints would be appreciated.
you have to wrap the whole body of your scaffold with refreshIndicator not a portion of it.
I found a solution that seems to work for me, using a LayoutBuilder + ConstrainedBox to wrap the contents of the SingleChildScrollView.
This way, the SingleChildScrollView will always span the whole remaining space.
return Column(
children: [
const SizedBox(
height: 4,
child: MyStatusbarWidget(),
),
Expanded(
child: LayoutBuilder(builder: (context, constraints) {
return RefreshIndicator(
onRefresh: onRefresh,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: child,
),
),
),
);
}),
),
],
);

How to use listview with other widgets?

I want to use ListView with other widgets , but I can't. When I use container for Listview, I can't view any other widgets. How can I do it?
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
ListView.builder(),
RaisedButton(
child: Text('Text'),
onPressed:(){})
])));
You shouldn't nest scroll views at all if you are trying to show some widgets based on a list, dart lets you use for inside any collection also you can use List.generate, or list.map with the spread operator
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
for(final item in list) widget,
RaisedButton(child: Text('Text'), onPressed: () {})
],
),
),
);
or
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
...list.map((item)=> widget).toList(),
RaisedButton(child: Text('Text'), onPressed: () {})
],
),
),
);
or
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
...List.generate(list.length, (index)=> widget).toList(),
RaisedButton(child: Text('Text'), onPressed: () {})
],
),
),
);
This is because you are using ListView inside Column, both ListView and Column take the full screen available to them, as this way we can only see ListView on the screen, to resolve this we have to shrink ListView to its exact size, for it shrinkwrap: true is used.
ListView.Builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
)
physics: NeverScrollableScrollPhysics(), is used here to stop ListView scrolling, you have added SingleChildScrollView() which scroll entire page
Add ShrinkWrap to The ListView
Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
ListView(
shrinkWrap: true,
children:[
Container(),
Container(),
]
),
RaisedButton(
child: Text('Text'),
onPressed:(){})
])));
for More Advanced Scrolling Challenges like More than One ListView in Column I Suggest you add a ScrollPhysics
u need use Expanded here and set data to ListView.builder
final items = List<String>.generate(10000, (i) => 'Item $i');
Column(children: [
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
);
},
),
AnyWidget(...)
])
You have to wrap your ListView widget with Expanded or if you want to wrap it with Container then you must have to give Container height or width
Try this Code...
Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: 4,
shrinkWrap: true,
itemBuilder: (context, index) {
return Text('Hello');
}
),
RaisedButton(
child: Text('Text'),
onPressed: () {}
)
]
)
)
);
In this example, the ListView and the other widget (a Container with yellow color) are both children of the Column widget. By doing this, you can ensure that the ListView and the other widgets can both be displayed on the screen.
Column(
children: <Widget>[
Container(
height: 200,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 160.0,
color: Colors.red,
),
Container(
width: 160.0,
color: Colors.blue,
),
Container(
width: 160.0,
color: Colors.green,
),
],
),
),
Container(
height: 200,
color: Colors.yellow,
),
],
)

Scrollable HomeScreen in Flutter

I wonder why that doesn't work. Maybe one can help me, I think it's just a small mistake.
I would like to be able to scroll the whole screen. The container with the "CompanyCard" widget can be scrolled vertically.
return Column(
children: <Widget>[
SearchBox(),
Expanded(
child: Stack(
children: <Widget>[
Container(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: companies.length,
itemBuilder: (context, index) => CompanyCard(),
),
),
],
),
),
SearchBox(),
SearchBox(),
SearchBox(),
],
);
horizontal: Facebook, Google Twitter (already works)
vertical: the whole screen (not working)
Wrap SingleChildScrollView to the widgets you like to scroll
return Column(
children: <Widget>[
SearchBox(),
SingleChildScrollView(
child: Expanded(
child: Stack(
children: <Widget>[
Container(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: companies.length,
itemBuilder: (context, index) => CompanyCard(),
),
),
],
),
),
),
SearchBox(),
SearchBox(),
SearchBox(),
],
);
New edit:
To make the whole page scrollable, wrap the page in SingleChildScrollView:
Full Code:
return Container(
child: SingleChildScrollView(
child: Expanded(
child: Column(
children: <Widget>[
SearchBox(),
SingleChildScrollView(
child: Expanded(
child: Stack(
children: <Widget>[
Container(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: companies.length,
itemBuilder: (context, index) =>
CompanyCard(),
),
),
],
),
),
),
SearchBox(),
SearchBox(),
SearchBox(),
],
),
),
),
);
You need to specify an explicit height to your List View. By default a List View has infinite height / width.
To be able to scroll the entire screen, you need to wrap your root widget inside a SingleChildScrollView and then specify a height for the List View container. Somewhat like this :-
body : SingleChildScrollView(child :...
... Other widgets...
Container (
height :200,
width :MediaQuery.of(context).size.width, // so that ListView occupies the entire width
child : ListView.builder(...
I think ListView in Column needs height.
I wrapped ListView with Container and give a some height.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: new Text("Home page"),
elevation: 5.0,
),
body: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
SizedBox(child: Text('asdf')),
Container(
height: 500,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) =>
SizedBox(width: 200, child: Text('aaa')),
),
),
SizedBox(child: Text('asdf')),
SizedBox(child: Text('asdf')),
SizedBox(child: Text('asdf')),
],
),
),
),
);
}

Flutter Page don't scroll

I have a problem, when I want to scroll on the screen, the app doesn't scroll. What am I missing?
This is my
code
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * .7,
child: ListView.builder(
itemCount: itemsDishes.length,
itemBuilder: (context, index) {
return itemsDishes[index];
},
)),
Container(
height: MediaQuery.of(context).size.height * .9,
child: ListView.builder(
itemCount: itemsDrinks.length,
itemBuilder: (context, index) {
return itemsDrinks[index];
},
)),
],
),
),
),
);
As you can see, the column is nested within a SingleChildScrollView
Your inner ListView widgets are capturing the scroll event but don't contain enough items to scroll themselves, and when you're using a SingleChildScrollView an inner ListView is redundant anyway. I'd recommend changing them to Column:
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
children: itemsDishes,
),
Column(
mainAxisSize: MainAxisSize.min,
children: itemsDrinks,
),
],
),
),
),
);
Remove Containers wrapping your ListViews and set shrinkWrap as well as physics properties.
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: itemsDishes.length,
itemBuilder: (context, index) {
return itemsDishes[index];
},
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: itemsDrinks.length,
itemBuilder: (context, index) {
return itemsDrinks[index];
},
)
You may just not have enough items on your screen!
You can also set physics: const AlwaysScrollableScrollPhysics(), on your SingleChildScrollView.