0
0
Fluttermobile~7 mins

Infinite scrolling in Flutter

Choose your learning style9 modes available
Introduction

Infinite scrolling lets users keep scrolling to see more items without pressing buttons. It feels smooth and natural, like flipping through a long list.

Showing a long list of news articles that loads more as you scroll down.
Displaying social media posts where new content appears automatically.
Loading product lists in a shopping app without page numbers.
Browsing photos or videos that keep loading as you scroll.
Any app where you want to save space and load data little by little.
Syntax
Flutter
ListView.builder(
  controller: _scrollController,
  itemCount: items.length + 1,
  itemBuilder: (context, index) {
    if (index == items.length) {
      return const CircularProgressIndicator();
    }
    return ListTile(title: Text(items[index]));
  },
);

Use a ScrollController to detect when the user scrolls near the bottom.

Show a loading indicator at the end while new items load.

Examples
Basic list with 20 items, no infinite scroll yet.
Flutter
ListView.builder(
  itemCount: 20,
  itemBuilder: (context, index) => Text('Item $index'),
);
Detect when user scrolls to the bottom to load more data.
Flutter
ScrollController _controller = ScrollController();

_controller.addListener(() {
  if (_controller.position.pixels >= _controller.position.maxScrollExtent) {
    // Load more items
  }
});
Show a loading spinner at the end while fetching more items.
Flutter
ListView.builder(
  controller: _controller,
  itemCount: items.length + 1,
  itemBuilder: (context, index) {
    if (index == items.length) return const CircularProgressIndicator();
    return ListTile(title: Text(items[index]));
  },
);
Sample App

This app shows a list of items. When you scroll to the bottom, it waits 2 seconds and adds 10 more items. A spinning circle appears while loading.

Flutter
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: InfiniteScrollDemo());
  }
}

class InfiniteScrollDemo extends StatefulWidget {
  const InfiniteScrollDemo({super.key});

  @override
  State<InfiniteScrollDemo> createState() => _InfiniteScrollDemoState();
}

class _InfiniteScrollDemoState extends State<InfiniteScrollDemo> {
  final ScrollController _scrollController = ScrollController();
  final List<int> _items = List.generate(20, (index) => index);
  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent && !_isLoading) {
        _loadMoreItems();
      }
    });
  }

  Future<void> _loadMoreItems() async {
    setState(() => _isLoading = true);
    await Future.delayed(const Duration(seconds: 2));
    setState(() {
      _items.addAll(List.generate(10, (index) => _items.length + index));
      _isLoading = false;
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Infinite Scrolling Demo')),
      body: ListView.builder(
        controller: _scrollController,
        itemCount: _items.length + (_isLoading ? 1 : 0),
        itemBuilder: (context, index) {
          if (index == _items.length) {
            return const Padding(
              padding: EdgeInsets.all(16),
              child: Center(child: CircularProgressIndicator()),
            );
          }
          return ListTile(title: Text('Item ${_items[index]}'));
        },
      ),
    );
  }
}
OutputSuccess
Important Notes

Always dispose your ScrollController to avoid memory leaks.

Use a loading flag (_isLoading) to prevent multiple loads at once.

Test on different screen sizes to ensure smooth scrolling.

Summary

Infinite scrolling loads more content as the user scrolls down.

Use ScrollController to detect when to load more items.

Show a loading indicator while fetching new data.