I have my ListView.builder inside Expanded widget which render widgets correctly on the screen but I cannot scroll the widgets rendered by it.
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: getPostsForUid(),
builder: (_, snap) {
return Expanded(
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: snap.data.length,
itemBuilder: (_, index) {
if (snap.data[index]['post_type'] == 'real_estate') {
return realEstate(snap, index);
}
else if (snap.data[index]['post_type'] == 'video_sharing') {
return videoSharing(snap, index);
}
else {
return Text('');
}
},
),
);
},
),
);
}
Try using ScrollPhysics() class,
physics: ScrollPhysics(),
here is the link for reference for the same.
You should set your physics to AlwaysScrollableScrollPhysics().
The docs state the following:
Scroll physics that always lets the user scroll.
This overrides the default behavior which is to disable scrolling when there is no content to scroll. It does not override the handling of overscrolling.
On Android, overscrolls will be clamped by default and result in an overscroll glow. On iOS, overscrolls will load a spring that will return the scroll view to its normal range when released.
Here is an image of "overscroll glow" for you to understand what that means.
Consider using shrinkWrap: false to expand your contents in case they are bounded.
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: getPostsForUid(),
builder: (_, snap) {
return Expanded(
child: ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: snap.data.length,
itemBuilder: (_, index) {
if (snap.data[index]['post_type'] == 'real_estate') {
return realEstate(snap, index);
}
else if (snap.data[index]['post_type'] == 'video_sharing') {
return videoSharing(snap, index);
}
else {
return Text('No data available.');
}
},
),
);
},
),
);
}
See the docs:
https://api.flutter.dev/flutter/widgets/AlwaysScrollableScrollPhysics-class.html
Add Physics:AlwaysScrollable() in your Listview.
Related
Minimum reproducible code:
final _controller = ScrollController();
#override
Widget build() {
return NestedScrollView(
headerSliverBuilder: (_, __) => [SliverAppBar(expandedHeight: 300)],
body: ListView.builder(
controller: _controller, // Removing this solves the issue.
itemCount: 100,
itemBuilder: (_, i) => Text('$i'),
),
);
}
If I scroll my ListView, the SliverAppBar doesn't scroll but if I remove the controller property then it does scroll.
So, how can I use the controller and make the SliverAppBar to scroll with the ListView (i.e. the standard behavior)?
Note: I don't want to use the CustomScrollView as my tree hierarchy won't let me make use of it that well.
You should make sure that the child is wrapped
final _controller = ScrollController();
#override
Widget build() {
return NestedScrollView(
headerSliverBuilder: (_, __) => [SliverAppBar(expandedHeight: 300)],
body: ListView.builder(
//add this to the child ListView
shrinkWrap: true
controller: _controller, // Removing this solves the issue.
itemCount: 100,
itemBuilder: (_, i) => Text('$i'),
),
);
}
Just move the scroll controller to NestedScrollView like this:
Widget build() {
return NestedScrollView(
headerSliverBuilder: (_, __) => [SliverAppBar(expandedHeight: 300)],
body: ListView.builder(
//add this to the child ListView
shrinkWrap: true,
itemCount: 100,
itemBuilder: (_, i) => Text('$i'),
),
controller: _controller,
);
}
That worked for me, I had a waterfalls flow using the scroll controller. and I need the sliver appear style.
I am creating a chat with firebase in flutter and I want that when the listview builder completes it can go to the end of the list (Last message).
This is what my buildmethod looks like:
return Scaffold(
backgroundColor: Color(0xFFf1e4e8),
body: Stack(
children: [
Container(
padding: EdgeInsets.only(bottom: 125),
child: StreamBuilder(
stream: userBloc.chat(widget.chatID),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
} else if(snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
return ListView.builder(
controller: scrollController,
physics: BouncingScrollPhysics(),
itemCount: snapshot.data.size,
itemBuilder: (context, index) {
return ChatMessage(
isUserMessage: isUserMessage(snapshot,index),
message:
snapshot.data.docs[index].data()['Message'],
timeStamp:snapshot.data.docs[index].data()['Timestamp']);
},
);
}
}),
);
What is the correct way to do it?
In your initState(), you can register a callback with addPostFrameCallback and it will get called once after the first frame completes rendering. You could use this callback to scroll to the bottom of your ListView.
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback( (_) {
_scrollToBottomOfListView();
}
}
Attach addListener to your scrollcontroller and then use jumpTo function accordingly. You can follow this example
ScrollController _scrollController;
double _lastEndOfScroll = 0;
_scrollController.addListener(() {
double maxScroll = _scrollController.position.maxScrollExtent;
double currentScroll = _scrollController.position.pixels;
if (maxScroll == currentScroll) {
_lastEndOfScroll = maxScroll;
}
});
_scrollController.jumpTo(_lastEndOfScroll);
The simplest solution is the following:
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('<MessagesColection>')
.orderBy('<Time field>',descending: true)
.snapshots(),
builder: (context,snapshot) {
return ListView.builder(
//The reversed list will put the list backwards.
//The start of the list will start at the bottom.
reverse: true,
controller: scrollController,
itemCount: snapshot.data.size,
itemBuilder: (context, index) {
return ChatMessage(snapshot);
},
);
}
),
In the previous code, what was done was to invert the list, the most recent messages will be at the bottom, and order the records in descending order, that is, from the most recent to the least recent. In this way the most recent messages will be at the beginning of the list (in this case at the bottom), and the least at the bottom of the list (in this case at the top).
Does anyone know if there is a way to remove the PageView color that occurs when the user reaches the end of the items?
this is an image that describes what I mean
Click here
PageView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
controller: _controller,
itemCount: 4,
itemBuilder: (BuildContext context, int index) {
_isValid = false;
return [
SizedBox.expand(...),
SizedBox.expand(...),
SizedBox.expand(...),
SizedBox.expand(...),
][index];
},
)
I found the complete and right answer here: How to remove scroll glow?
This effect is provided by ScrollBehavior. You need to provide your custom ScrollBehavior and wrap it inside a ScrollConfiguration.
class CustomScrollBehavior extends ScrollBehavior {
#override
Widget buildViewportChrome(
BuildContext context, Widget child, AxisDirection axisDirection) {
return child;
}
}
To remove the effect in your PageView
ScrollConfiguration(
behavior: CustomScrollBehavior(),
child: PageView.builder(
...
),
)
above one is not worked for me , after the new flutter v2 ( sdk 2.8.1),
NotificationListener<OverscrollIndicatorNotification>(
onNotification: (overscroll) {
overscroll.disallowIndicator();
return true;
},
child: SingleChildScrollView(
)
)
I'd like to add an info box on top of the listview and instead of having it fixed, I'd like it to scroll along with the content while the page is scrolled down. Instead what I'm experiencing is that it stays always in fixed position no matter what I try to do.
My code:
return new Column(children: <Widget>[
new Text('I want to be scrollable as well with other content as well'), // I want widget or widgets here to be part of the scroll instead of them being fixed.
new Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return index >= state.posts.length
? BottomLoader()
: PostWidget(post: state.posts[index]);
},
itemCount: state.hasReachedMax
? state.posts.length
: state.posts.length + 1,
controller: _scrollController,
),
),
]);
Is this possible to achieve?
I think you could return your Text widget or any other widget at the 0 position ?
return new Column(children: <Widget>[
new Text('I want to be scrollable as well with other content as well'), // I want widget or widgets here to be part of the scroll instead of them being fixed.
new Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
if (index == 0) {
return Text('Your widget');
else {
return index >= state.posts.length
? BottomLoader()
: PostWidget(post: state.posts[index]);
}
},
itemCount: state.hasReachedMax
? state.posts.length
: state.posts.length + 1,
controller: _scrollController,
),
),
]);
Widget servicesListview() {
return Container(
decoration: new BoxDecoration(color: const Color(0xFFEAEAEA)),
child: Column(
children: <Widget>[
ListView.builder(
scrollDirection: Axis.vertical,
itemCount: menServicesList.length,
itemBuilder: (BuildContext context, int index) {
Text(menServicesList[index].name);
}),
],
));
}
I am implementing listview in my flutter project whenever i call this method list is not visible.The page becomes blank,help me to solve this
I have a same problem.
The ListView.builder don't work inside a Column, this necessary use the Expanded.
The Expanded widget allows you to expand and fill the space with the relative widget.
See this:
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
.......
)
)
]
)
Wrap your ListView inside of a Expanded or a Container widget, if you use a Container, you'll need to set a height/width.
This happens because ListView doesn't have a height/width property to edit.
EDIT
Don't forget to return your Text inside the itemBuilder property.
You're missing the return statement in your itemBuilder
itemBuilder: (BuildContext context, int index) {
return Text(menServicesList[index].name);
}),
or
itemBuilder: (BuildContext context, int index) => Text(menServicesList[index].name)),
If you remove Column widget from the ListView, the list will definitely appear
and if you want to give a decoration property to each element of a ListView.
Widget servicesListview() {
return ListView.builder(
scrollDirection: Axis.vertical,
itemCount: menServicesList.length,
itemBuilder: (BuildContext context, int index) {
Container(
decoration: new BoxDecoration(color: const Color(0xFFEAEAEA)),
child: Text(menServicesList[index].name)
);
})
}