Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter, ListView, How to add several items on top of the ListView and make it not scroll to the top

When I add some items on top of the ListView it scrolls to the top item on the 0 index. But I need it to stay in the same position as before adding items.

For example, chat history pagination on the top of the list of messages, if I open any messenger (Telegram, WhatsApp, etc.) open chat with a long history and scroll down downloading the history. History will be added to the top of the list (from the server ~20 messages at a time) but the list will stay on the same position (while scrolling).

Flutter ListView behaves like that if you add to the bottom, but if you add to the top it jumps to the first added item. I want it to stay.

like image 627
Andrew Avatar asked Aug 09 '19 16:08

Andrew


People also ask

How do you make an expandable list in flutter?

Expandable ListView is a type of list view that is used to show multiple types of data based on category and subcategory. Expandable list view is used to expand or collapse the view in list items In a flutter app. We can easily make our own Expandable ListView using the ExpansionTile widget.

How do you add a divider to a ListView in flutter?

separated creates a fixed-length, scrollable , linear array of list “items” separated by list item “separators”. The itemBuilder callback is called whenever there are indices ≥ 0 and< itemCount . The separatorBuilder callback will be called with indices greater than or equal to zero and less than itemCount - 1 .

How do you make a list dynamic on flutter?

Create Dynamic ListView using ListView. builder() And you would not know the number of elements in the list beforehand. In such scenarios, you can use ListView. builder() constructor of ListView class to create a dynamic list of widgets in ListView widget.


1 Answers

Screenshot:

enter image description here


Since you didn't share any code, I just created a simple demo to show how you can achieve the effect like a messaging app. The code is very simple to understand, I have used comments almost everywhere.

Code (Null safe):

class _MyPageState extends State<MyPage> {
  // Say you have total 100 messages, and you want to load 20 messages on each scroll.
  final int _totalMessages = 100, _loadInterval = 20;
  final double _loadingOffset = 20;
  late final List<String> _messages;
  bool _loading = false;
  final ScrollController _controller = ScrollController();

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

    // Initially, load only 20 messages.
    _messages = List.generate(20, (i) => 'Message   #${_totalMessages - i}');
    _controller.addListener(_scrollListener);
  }

  void _scrollListener() async {
    var max = _controller.position.maxScrollExtent;
    var offset = _controller.offset;

    // Reached at the top of the list, we should make _loading = true
    if (max - offset < _loadingOffset && !_loading) {
      _loading = true;

      // Load 20 more items (_loadInterval = 20) after a delay of 2 seconds
      await Future.delayed(Duration(seconds: 2));
      int lastItem = _totalMessages - _messages.length;
      for (int i = 1; i <= _loadInterval; i++) {
        int itemToAdd = lastItem - i;
        if (itemToAdd >= 0) _messages.add('Message   #$itemToAdd');
      }

      // Items are loaded successfully, make _loading = false
      setState(() {
        _loading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Messages')),
      body: ListView.builder(
        controller: _controller,
        reverse: true,
        itemCount: _messages.length + 1, // +1 to show progress indicator.
        itemBuilder: (context, index) {
          // All messages fetched. 
          if (index == _totalMessages) return Container();

          // Reached top of the list, show a progress indicator. 
          if (index == _messages.length) return Align(child: CircularProgressIndicator());

          // Show messages. 
          return ListTile(title: Text('${_messages[index]}'));
        },
      ),
    );
  }
}
like image 113
CopsOnRoad Avatar answered Oct 21 '22 08:10

CopsOnRoad