Flutter - Getting the items information those are currently displaying in ScrollView

LinXunFeng
4 min readApr 18, 2023

--

I. Overview

I believe everyone has anyone encountered some such needs

  • After scrolling to a specified item, pop up a full-screen starter guide based on the size of the specified item
  • During the scrolling process of the detail page, the module positioning navigation bar at the top needs to update the indicator index in time
  • As the video list scrolls, item in the appropriate positions will automatically play the video

In the daily development, there are still quite a lot of such similar functional requirements, so i encapsulate and publish a package: flutter_scrollview_observer

II. Scenarios

Let’s take a look at common application scenarios:

1. Get the first item information

You can get the current first child widget and all child widget information that is being displayed

2. The video list item plays automatically

When the item widget enters the middle area of the list, the video is played automatically

3. Module positioning

When scrolling to some specific module, the indicator at the top TabBar switches to the corresponding module Tab

III. Useage

1. Basic useage

Create ListView

ListView _buildListView() {
return ListView.separated(
itemBuilder: (ctx, index) {
return _buildListItemView(index);
},
separatorBuilder: (ctx, index) {
return _buildSeparatorView();
},
itemCount: 50,
);
}

construct ListViewObserver

  • child: Pass in the ListView instance
  • onObserve: This callback listens for information about the item widgets those are currently being displayed
ListViewObserver(
child: _buildListView(),
onObserve: (resultMap) {
final model = resultMap[_sliverListViewContext];
if (model == null) return;
// Prints the first item index that is currently being displayed
print('firstChild.index -- ${model.firstChild.index}');
// Prints all item indexs those are currently being displayed
print('displaying -- ${model.displayingChildIndexList}');
},
)

In addition to the above common parameters, there are:

  • leadingOffset: Top offset, used when the viewport of the list is fixed to be blocked by other views
  • dynamicLeadingOffset: Dynamic top offset, used when the viewport of the list is dynamically blocked by other views

Just look at the diagram here

// when NavigationBar is translucent
flutter: firstChild.index -- 0
flutter: displaying -- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
flutter: firstChild.index -- 0
flutter: displaying -- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

// when NavigationBar is completely opaque
flutter: firstChild.index -- 2
flutter: displaying -- [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

The scrolling process changes the transparency of the navigation bar at the top. At this premise:

  1. When translucent, we want all visible item widgets of the ListView to start from the very top
  2. When opaque is complete, we want all visible item widgets of the ListView to start at the bottom of the navigation bar
ListViewObserver(
...
dynamicLeadingOffset: () {
if (_navBgAlpha < 1) {
return 0;
}
return _safeAreaPaddingTop + _navContentHeight;
},
...
),
  • toNextOverPercent: After the first item widget is fetched, if the ratio of the blocked size of the item widget to its own size exceeds this value, the next item widget will be as the first item widget.

2. Manual trigger observe

By default, the data is observed only while scrolling.

If an observation in a non-rolling state is required, you can use ListViewOnceObserveNotification to trigger observe manually.

ListViewOnceObserveNotification().dispatch(_sliverListViewContext);

3. Item widget information

Observed model data:

class ListViewObserveModel {
/// The first observed model data
final ListViewObserveDisplayingChildModel firstChild;

/// Stores observing model list of displaying children widgets
final List<ListViewObserveDisplayingChildModel> displayingChildModelList;

/// Stores index list for children widgets those are displaying
List<int> get displayingChildIndexList =>
displayingChildModelList.map((e) => e.index).toList();
}

ListViewObserveDisplayingChildModel:

class ListViewObserveDisplayingChildModel {
/// The index of child widget
final int index;
/// The renderObject [RenderBox] of child widget
final RenderBox renderObject;
}

For more usage, please see GitHub: LinXunFeng/flutter_scrollview_observer

Series

--

--