Flutter Notes: Scroll - Implementation of Infinite Scroll and Dynamic Loading

Flutter notes
Implementation of infinite scrolling and dynamic loading

Author : Li Juncai (jcLee95) : https://blog.csdn.net/qq_28550263
Email: [email protected]
Article address : https://blog.csdn.net/qq_28550263/article/details/133342307


There is another version of this article, based on GetX simple state management state. The address is: https://jclee95.blog.csdn.net/article/details/133365040


1. Infinite scrolling list

In Flutter, implementing an endless scrolling list usually involves using a ListView, ListView.builder, or ListView.separated component, combined with a data source and a scroll controller. This allows you to load and display large amounts of data, dynamically loading more data only when needed, for an endless scrolling effect.

2. Basic implementation example of simulating a scrolling list (ListView.builder)

2.1 Introduction to implementation ideas and steps

The following are the general steps to implement Flutter's endless scrolling list:

Prepare data source

First you need to have a data source. For example, a list or a database query result, or data requested from the network for list rendering. Typically, this data should be loaded on demand rather than loading all at once.

Create a scroll controller

Create a scroll controller through ScrollController to listen for scroll events of the list. This will help you determine when to load more data.

Build a list view

Build a list view using ListView.builder , which creates a list that renders only visible items. Define how each list item is rendered by specifying the itemBuilder parameter.

Set up scroll monitoring

Add a scroll controller to the list view and use addListener to listen for scroll events. As the user scrolls through the list, an action to load more data can be triggered at the appropriate time.

load more data

When you need to load more data, you can call the data source's methods or request data. This could be fetching data from the network, querying data from a local database, or other means. Once the data is ready, add it to the data source and then tell the list view to rebuild.

Update list view

When new data is available, call the setState method to notify Flutter to rebuild the list view. This will cause the list view to load and display the new data.

2.2 A simple example

According to the steps in Section 2.1, an example of implementing a simulated wireless scroll is as follows:

import 'package:flutter/material.dart';

void main() {
    
    
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
    
    
  const MyApp({
    
    Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    
    
    return const MaterialApp(
      home: InfiniteScrollList(),
    );
  }
}

/// 一个带有无尽滚动列表的 StatefulWidget。
class InfiniteScrollList extends StatefulWidget {
    
    
  const InfiniteScrollList({
    
    Key? key}) : super(key: key);

  
  State<InfiniteScrollList> createState() => _InfiniteScrollListState();
}

/// [InfiniteScrollList] 的状态类,包含滚动逻辑和数据管理。
class _InfiniteScrollListState extends State<InfiniteScrollList> {
    
    
  List<int> items = List.generate(20, (index) => index); // 初始数据
  final ScrollController _scrollController = ScrollController();
  bool isLoading = false;

  
  void initState() {
    
    
    super.initState();
    _scrollController.addListener(_loadMore);
  }

  /// 处理滚动事件以加载更多数据。
  void _loadMore() {
    
    
    if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent &&
        !isLoading) {
    
    
      // 模拟加载更多数据
      setState(() {
    
    
        isLoading = true;
      });

      // 模拟加载数据的延迟
      Future.delayed(const Duration(seconds: 2), () {
    
    
        setState(() {
    
    
          // 添加新数据到现有列表中
          items.addAll(List.generate(10, (index) => index + items.length));
          isLoading = false;
        });
      });
    }
  }

  
  Widget build(BuildContext context) {
    
    
    return Scaffold(
      appBar: AppBar(
        title: const Text('无尽滚动列表'),
      ),
      body: ListView.builder(
        controller: _scrollController,
        itemCount: items.length + (isLoading ? 1 : 0),
        itemBuilder: (context, index) {
    
    
          if (index < items.length) {
    
    
            return ListTile(
              title: Text('Item ${
      
      items[index]}'),
            );
          } else {
    
    
            // 显示加载指示器
            return const Padding(
              padding: EdgeInsets.all(16.0),
              child: Center(child: CircularProgressIndicator()),
            );
          }
        },
      ),
    );
  }

  
  void dispose() {
    
    
    // 释放滚动控制器
    _scrollController.dispose();
    super.dispose();
  }
}

The code above InfiniteScrollListis one StatefulWidget, which contains an infinitely scrollable list view that can automatically load more data. First, in the initial state, the list contains 20 integer items. When the user scrolls to the bottom of the list, it simulates loading more data. When more data is loaded, a loading indicator is displayed. The effect is as shown in the figure:

Insert image description here
Now we summarize the following implementation ideas. _InfiniteScrollListStateFirst, in the class, we use List.generateto create a list containing the initial data that will be used for the initial display. Next create an ScrollControllerobject _scrollControllerthat will listen to the list's scroll events.

  • In initStatethe method, add a scroll listener _scrollControllerto trigger loading more data when the user scrolls to the bottom.
  • _loadMoreThe method handles the scroll event, checks whether the scroll has reached the bottom of the list, and if so and is not loading, simulates the process of loading more data.
  • In buildthe method, use to ListView.builderbuild the list view. If the user scrolls to the bottom of the list, a loading indicator appears.
  • In disposethe method, release _scrollControllerto prevent memory leaks.

Specific implementation steps include:

Here are the steps to implement an infinite scrolling list:

  1. Create a Flutter application.

  2. Create a StatefulWidgetcontainer for an infinite scrolling list.

  3. In the state class, initialize the data source, including the initial data list.

  4. Create a scroll controller ( ScrollController) and initStateadd a scroll listener to it in the method.

  5. In the scroll listener, check if you have scrolled to the bottom of the list and load more data if necessary.

  6. Use to ListView.builderbuild a list view and dynamically generate list items based on the data source.

  7. Displays a loading indicator at the bottom of the list to indicate that more data is being loaded.

  8. disposeRelease the scroll controller in the method .

With these steps, you can implement an infinite scrolling list that users can scroll through and load more data, creating an infinite scrolling experience. This is useful for applications that need to display large amounts of data, such as social media news feeds or product lists.

3. Transformation 1: Basic implementation example of Taobao-like wireless scrolling grid (GridView.builder)

The basic principle is similar to the wireless scrolling list. The steps required to transform the GridView to simulate infinite scrolling include:

  1. Create a data source: First, you need to prepare a data source, which can be a list containing product information.
  2. Create a scroll view: Replace ListView.builder with GridView.builder to create a grid view. Set the gridDelegate to specify the number of columns and layout.
  3. Scroll Listening: Use a ScrollController to listen for scroll events, similar to the previous example, to determine when to trigger an action to load more data.
  4. Dynamic loading trigger: In the scroll listener, check whether the scroll position is close to the bottom, and if so, trigger the operation of loading more data.
  5. Update the data source: When the trigger loads more data, update the data source, usually by getting new data from the network or other data sources, and adding it to the data source.
  6. Rebuild the UI: Use setState() to notify Flutter to rebuild the UI to display the newly loaded data.

The specific implementation code is as follows:

import 'package:flutter/material.dart';

void main() {
    
    
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
    
    
  const MyApp({
    
    Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    
    
    return const MaterialApp(
      home: InfiniteScrollGrid(),
    );
  }
}

class InfiniteScrollGrid extends StatefulWidget {
    
    
  const InfiniteScrollGrid({
    
    Key? key}) : super(key: key);

  
  State<InfiniteScrollGrid> createState() => _InfiniteScrollGridState();
}

class _InfiniteScrollGridState extends State<InfiniteScrollGrid> {
    
    
  List<String> items = List.generate(20, (index) => 'Item $index'); // 初始数据
  final ScrollController _scrollController = ScrollController();
  bool isLoading = false;

  
  void initState() {
    
    
    super.initState();
    _scrollController.addListener(_loadMore);
  }

  void _loadMore() {
    
    
    if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent &&
        !isLoading) {
    
    
      setState(() {
    
    
        isLoading = true;
      });

      Future.delayed(const Duration(seconds: 1), () {
    
    
        setState(() {
    
    
          items.addAll(
              List.generate(10, (index) => 'Item ${
      
      index + items.length}'));
          isLoading = false;
        });
      });
    }
  }

  
  Widget build(BuildContext context) {
    
    
    return Scaffold(
      appBar: AppBar(
        title: const Text('无尽滚动网格'),
      ),
      body: GridView.builder(
        controller: _scrollController,
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2, // 列数
          childAspectRatio: 0.7, // 网格项的宽高比
        ),
        itemCount: items.length + (isLoading ? 1 : 0),
        itemBuilder: (context, index) {
    
    
          if (index < items.length) {
    
    
            return Card(
              elevation: 3,
              margin: const EdgeInsets.all(8),
              child: Text(items[index]),
            );
          } else {
    
    
            return const Padding(
              padding: EdgeInsets.all(16.0),
              child: Center(child: CircularProgressIndicator()),
            );
          }
        },
      ),
    );
  }

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

The implementation effect of this code is:
Insert image description here

Guess you like

Origin blog.csdn.net/qq_28550263/article/details/133342307