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
      }
    });

Это будет срабатывать только тогда, когда последний элемент виден в списке.