could we detect if we reach the top list or bottom using ScrollablePositionedList.builder instead of ListView.builder - flutter

ok i decided to use
ScrollablePositionedList.builder
https://pub.dev/packages/scrollable_positioned_list
instead of ListView.builderfor more controlling of the index navigation ..
we know that ScrollablePositionedList.builder use ItemScrollController() instead of ScrollController()
using ScrollController() we can do the following to detect if we reach the top list or bottom
ScrollController scrollController= ScrollController();
scrollController.addListener(() {
if(scrollController.position.atEdge){
if (scrollController.position.pixels == 0) {
///we arrive to the end
}
}else{
///we arrive to the top
}
}
});
but how could i do the same with using ScrollablePositionedList.builder that use ItemScrollController()
so i tried to do this
ItemScrollController scrollController = ItemScrollController();
final listener = ItemPositionsListener.create();
listener.itemPositions.addListener(() {
listener.itemPositions.value // here all what i get .. i cannot see any
position.atEdge or pixels like normal ScrollController
});
really does it not support the detection of top list or bottom or something went wrong with me ?
thanks

You can check
if the value of itemPositionsListener.itemPositions.value.first.index is 0
to say it is on top. And to check
if the value of ${itemPositionsListener.itemPositions.value.last.index} = list.length - 1
to say it reaches the bottom.
itemPositionsListener.itemPositions.addListener(() {
print(
'====current first ${itemPositionsListener.itemPositions.value.first.index}====');
print(
'====current last ${itemPositionsListener.itemPositions.value.last.index}====');
});

Related

Ensure the visibility of the first item in a horizontal listview after prepending some items

I have a horizontal list view where I detect if the user has scrolled to the leftmost or rightmost edge and prepend, or append, new list items respectively.
The code structure is like so:
class WidgetState extends State<SomeWidget> {
// This list is prepended with some items when the user scrolls to the left edge
// (i.e when position.pixels = 0)
var _list;
// I use the scroll controller to detect if the user has hit the leftmost or rightmost edge
// of the list and trigger the logic that updates the above list
var _scrollController;
#override
Widget build(BuildContext context) {
ListView.separated(
itemBuilder: (context, index) {
return _list[ index ];
},
controller: _scrollController
);
}
}
The issue is that the new prepended items will push the old items outside of the visible view. What I would like to do is somehow preserve the scroll position such that the user still has to scroll to the left to see the now newly prepended items.
One idea I had is to use https://pub.dev/packages/scrollable_positioned_list and scroll to the index of the first old item in the list. However, I didn't want to add a whole new list implementation just for this. Is there a better way?

Flutter Horizontal ListView-- how to 'jumpTo' selected Index

I have ListView.builder with horizontal scrolling (a custom top navigation bar). As I scroll to the right and left, the 'selectedIndex' is changing, but the UI inside this widget isn't showing this change in position. I'd like to 'Jump To' the selected index upon swiping.
Here's how my ListView is currently updating its index:
void onChanged(int index) {
pageController.jumpToPage(index);
setState(() {
this.selectedIndex = index;
});
}
How can I accomplish this? Any guidance would mean a lot.
Thanks, A.V.
You can calculate selected item offset by item width and height and then use
_gridViewController.jumpTo(calculatedOffset);

How to know if list view is scrollable programatically

I am copying my question from here as it is the same question but for flutter
How do you know if your ListView has enough number of items so that it
can scroll?
For instance, If I have 5 items on my ListView all of it will be
displayed on a single screen. But if I have 7 or more, my ListView
begins to scroll. How do I know if my List can scroll
programmatically?
Thank you
I am adding the code I tried, in which I test if the controller is attached, to be able to get the position. I couldn't get the position because the controller is not attached until you actually scroll
Widget build(BuildContext context) {
_afterBuild();
ListView.builder(
controller: controller,
// ...
)
}
Future<void> _afterBuild () async {
if (controller.hasClients) {
print("controller.hasClients");
// here I would be able to get the position
} else {
print("controller.has no Clients");
}
}
Edit: For anyone coming here: The controller was not being attached because I had a condition under which to build the ListView
So I combined the comments with the accepted answer (which is actually the answer for the question) and solved it like this (with some pseudocode):
Widget build(BuildContext context) {
if (not loaded results from api) {
return Something()
} else {
Future(_afterBuild);
return ListView.builder(
controller: controller,
// ...
)
}
}
Future<void> _afterBuild () async {
if (controller.hasClients) {
if(controller.position.maxScrollExtent > 0){
print('it can be scrolled');
}
} else {
print("controller has no client");
}
}
Actually it's quite easy to do in Flutter. You should have a ScrollController attached to your ListView and then you can check the maxScrollExtent. If it's bigger than zero then your ListView can be scrolled. It also works for any scrolling view which uses ScrollController.
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if(controller.position.maxScrollExtent > 0){
print('it can be scrolled');
}
});
}
Step 1 - Assign a GlobalKey
GlobalKey myKey= GlobalKey();
Step 2 - Assign key to ListView
ListView(
key: myKey,
...
)
Step 3 - In your function that checks if the ListView is scrollable, use the following code-
final RenderBox renderBoxRed = myKey.currentContext.findRenderObject();
final height = renderBoxRed.size.height; // find height of ListView
if (height > MediaQuery.of(context).size.height) { // checking if listview height is greater than page height
print("ListView is SCROLLABLE !!!");
}
I like where most of the rest of the answers are going, but they aren't getting the data the most succinctly or reliably. What you want to do is, yes, attach a ScrollController, and then look for the .position on that (which may throw if there's no single attached position). Then, ask the position for extentAfter and extentBefore, and you'll discover how much virtual view (in pixels) there is after and before the current visible portion. If those are 0, no scrolling. No need to figure out the size of the screen or the containers. Flutter already knows all that when it laid everything out!

How to add specific actions to ListView when user drags to its start or end (when the curvy blue lines appear)?

I'm curious is there an easy way to add such functionality to my Flutter ListViews?
For example, I would like to trigger some animation on another widget when the user drags "over the edge" on the ListView with all of it's items scrolled to the top or bottom, that is when the curvy blue line indicating that we're at the end of the list appears.
It obviously has an event firing up to show those lines anyway.
It's not hard actually, you can use a custom ScrollController with a listener:
declare it, then in initState put:
_myController = ScrollController();
_myController.addListener(_myScrollListener);
and the function itself can be something like this:
_myScrollListener(){
if (_myController.offset >= _controller.position.maxScrollExtent && !_myController.position.outOfRange) {
print("List end");
}
if (_myController.offset <= _controller.position.minScrollExtent && !_myController.position.outOfRange) {
print("List top");
}
Use the controller with your ListView, add what you need to the listener.

changing variables inside listview builder

i want to change variable values when the widget is loading the data from the web,
just want to do something like this:
_playid = _notes[1].id;
title = _notes[1].title;
but wherever I put it, i get an error,
I tried to put it in a set state inside listview builder, but no luck since I don't want it with onPress or on tap methods
could someone help, please?
i just found out,
simply we have to use setstate in fetch inside initstate
void initState() {
title = " ";
fetchNotes().then((value) {
setState(() {
_notes.addAll(value);
_playid = _notes[0].numb;
});
});
}