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.
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.
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 .
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.
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.
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]}'));
},
),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With