Flutter - определяет положение прокрутки ListView, вверху или внизу?
Я пытаюсь реализовать функцию бесконечной прокрутки.
Я попытался использовать ListView
внутри NotificationListener
для обнаружения событий прокрутки, но я не вижу события, которое говорит, что прокрутка достигла нижней части представления.
Какой будет лучший способ достичь этого?
Ответы
Ответ 1
Вы можете использовать ListView.builder
для создания списка прокрутки с неограниченными элементами. Ваш itemBuilder
будет вызываться по мере необходимости при обнаружении новых ячеек.
Если вы хотите получать уведомления о событиях прокрутки, чтобы вы могли загрузить больше данных из сети, вы можете передать аргумент controller
и использовать addListener
для присоединения слушателя к ScrollController
. position
ScrollController
можно использовать для определения того, насколько прокрутка близка к нижней.
Ответ 2
_scrollController = new ScrollController();
_scrollController.addListener(
() {
double maxScroll = _scrollController.position.maxScrollExtent;
double currentScroll = _scrollController.position.pixels;
double delta = 200.0; // or something else..
if ( maxScroll - currentScroll <= delta) { // whatever you determine here
//.. load more
}
}
);
Коллин должен быть принят ответ....
Ответ 3
// create an instance variable
var _controller = ScrollController();
@override
void initState() {
super.initState();
// set up listener here
_controller.addListener(() {
if (_controller.position.atEdge) {
if (_controller.position.pixels == 0)
// you are at top position
else
// you are at bottom position
}
});
}
Использование:
ListView(controller: _controller) // assign it like this
Ответ 4
Я использовал другой подход для бесконечной прокрутки. Я использовал класс ChangeNotifie r для слушателя изменения переменных. Если есть изменение в переменной, это вызывает событие и в конечном итоге попадает в API.
class DashboardAPINotifier extends ChangeNotifier {
bool _isLoading = false;
get getIsLoading => _isLoading;
set setLoading(bool isLoading) => _isLoading = isLoading;
}
Инициализируйте класс DashboardAPINotifier.
@override
void initState() {
super.initState();
_dashboardAPINotifier = DashboardAPINotifier();
_hitDashboardAPI(); // init state
_dashboardAPINotifier.addListener(() {
if (_dashboardAPINotifier.getIsLoading) {
print("loading is true");
widget._page++; // For API page
_hitDashboardAPI(); //Hit API
} else {
print("loading is false");
}
});
}
Теперь лучшая часть - это когда вы должны использовать API. Если вы используете SliverList
, то в какой момент вы должны использовать API.
SliverList(delegate: new SliverChildBuilderDelegate(
(BuildContext context, int index) {
Widget listTile = Container();
if (index == widget._propertyList.length - 1 &&
widget._propertyList.length <widget._totalItemCount) {
listTile = _reachedEnd();
} else {
listTile = getItem(widget._propertyList[index]);
}
return listTile;
},
childCount: (widget._propertyList != null)? widget._propertyList.length: 0,
addRepaintBoundaries: true,
addAutomaticKeepAlives: true,
),
)
_reachEnd() method take care to hit the api. It trigger the '_dashboardAPINotifier._loading'
// Function that initiates a refresh and returns a CircularProgressIndicator - Call when list reaches its end
Widget _reachedEnd() {
if (widget._propertyList.length < widget._totalItemCount) {
_dashboardAPINotifier.setLoading = true;
_dashboardAPINotifier.notifyListeners();
return const Padding(
padding: const EdgeInsets.all(20.0),
child: const Center(
child: const CircularProgressIndicator(),
),
);
} else {
_dashboardAPINotifier.setLoading = false;
_dashboardAPINotifier.notifyListeners();
print("No more data found");
Utils.getInstance().showSnackBar(_globalKey, "No more data found");
}
}
Примечание. После ответа API необходимо уведомить слушателя,
setState(() {
_dashboardAPINotifier.setLoading = false;
_dashboardAPINotifier.notifyListeners();
}
Ответ 5
Я хотел бы добавить пример для ответа, предоставленного Коллин Джексон. Смотрите следующий фрагмент
var _scrollController = ScrollController();
_scrollController.addListener(() {
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
// Perform your task
}
});
Это будет срабатывать только тогда, когда последний элемент виден в списке.