Search code examples
flutterscrollcontroller

Scrolling to the end of the ListView does not work as expected


I'm having a list of messages and after getting all the previous messages or after sending a new message, I want my ListView to get scrolled to the bottom.

I have created a ScrollController:

    final ScrollController _scrollController = ScrollController();

a listener:

void _scrollListener() {
    // Checks if it needs to be scrolled or will get OOR
    if (_scrollController.offset >=
            _scrollController.position.maxScrollExtent &&
        !_scrollController.position.outOfRange) {}
  }

and a scrollToBottom():

void _scrollToBottom() {
    // Scrolls to bottom if needed
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_scrollController.hasClients) {
        _scrollController.animateTo(
          _scrollController.position.maxScrollExtent,
          duration: const Duration(milliseconds: 300),
          curve: Curves.easeOut,
        );
      }
    });
  }

and I'm calling the scrollToBottom() in my sendMessage(), fetchPreviousMessages() and initState():

void _sendMessage(String message) async {
    // Sends message to the WebSocket
    final userData = await _preferencesService.getPreferences();
    if (message.isNotEmpty) {
      MessageRequest messageRequest = MessageRequest(
          message: _textFieldController.text,
          username: userData.username,
          roomID: widget.room.uniqueID);

      _channel.sink.add(jsonEncode(messageRequest.toJson()));
    }
    // clear textfield
    _textFieldController.clear();
    _scrollToBottom();
  }
void _fetchPreviousMessages() async {
    // get all previous messages for the room

    final websocketService = WebSocketService();

      await websocketService
          .fetchPreviousMessage(widget.room.uniqueID)
          .then((messages) {
        for (var i = 0; i < messages.length; i++) {
          _messages.add(messages[i]);
          setState(() {
            _isLoading = false;
          }); //hide loader
        }

        _scrollToBottom();
      });
 @override
  void initState() {
    super.initState();

    // get all previous messages for the room
    _fetchPreviousMessages();

    // init WebSocket
    _initWebSocket();

    // init the scroll controlled
    _scrollController.addListener(_scrollListener);
    _scrollToBottom();

    // init textField listened in order to make button unavailable
    _textFieldController.addListener(() {
      bool isChatButtonActive = _textFieldController.text.isNotEmpty;

    });
  }

Sometimes it does work and scrolls to bottom, but sometimes it scrolls only halfway or not at all and I cannot understand why...

Thanks in advance!


Solution

  • Just a workaround but it should work as expected. Use clamping physics in the list view. Add an extra number to the max extent

    _scrollController.animateTo(
     _scrollController.position.maxScrollExtent+300,
     duration: const Duration(
       milliseconds: 200,
      ),
      curve: Curves.easeInOut,
      );