Flutter 应用程序中的无限列表

Infinite List in Flutter Application

我正在将我的应用程序从 android 迁移到 flutter,直到现在我已经在 flutter 中使用了 ListView。我的问题是,是否有专门的技术来处理颤振中的大量数据?作为参考,您可以查看 android RecyclerView。它处理内存中的视图并回收其运行时。那么如何在Flutter中实现类似RecyclerView的功能呢?还是不需要颤振?

最简单的方法是使用 ListView.builder 而不指定 itemCount 参数。

这是最简单的例子:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Infinite List"),
      ),
      body: ListView.builder(
        itemBuilder: (context, index) {
          return Text("$index");
        },
      ),
    );
  }
}

稍后,您可以通过获取真实数据来增强这一点。您可以在等待新数据时在列表的最后一项显示 'CircularProgressIndicator'。

  body: ListView.builder(
    itemBuilder: (context, index) {
      if (index < data.length) {
        // Show your info
        return Text("$index");
      } else {
        getMoreData();
        return Center(child: CircularProgressIndicator());
      }
    },
    itemCount: data.length + 1,
  ),

您可以看到我们通过添加索引来欺骗列表,并在显示最终索引时调用更多数据。

getMoreData() 将包括对 setState() 的调用以强制重建并考虑新数据。

显示数据列表是移动应用程序的基本模式。 Flutter 包含 ListView 小部件,使使用列表变得轻而易举。

我已经通过执行以下步骤解决了问题

  1. 使用 ListView 小部件
  2. ListView有四个构造函数Class
  3. 您必须使用 Builder 构造函数 (ListView.builder)
  4. 当你必须按需制作元素列表时使用构造函数
  5. 适用于具有大量(或无限)子项的列表视图

在这里你可以看到解决方案视频CLICK HERE

对于无限滚动 ListView 使用 infinite_scroll_pagination 包此包管理延迟加载并在用户向下滚动屏幕时显示项目页面。

添加依赖项

dependencies:
  flutter:
    sdk: flutter
  infinite_scroll_pagination: ^2.3.0

在文件顶部添加对新库的导入:

import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';

使用示例

class CharacterListView extends StatefulWidget {
  @override
  _CharacterListViewState createState() => _CharacterListViewState();
}

class _CharacterListViewState extends State<CharacterListView> {
  static const _pageSize = 20;

  final PagingController<int, CharacterSummary> _pagingController =
      PagingController(firstPageKey: 0);

  @override
  void initState() {
    _pagingController.addPageRequestListener((pageKey) {
      _fetchPage(pageKey);
    });
    super.initState();
  }

  Future<void> _fetchPage(int pageKey) async {
    try {
      final newItems = await RemoteApi.getCharacterList(pageKey, _pageSize);
      final isLastPage = newItems.length < _pageSize;
      if (isLastPage) {
        _pagingController.appendLastPage(newItems);
      } else {
        final nextPageKey = pageKey + newItems.length;
        _pagingController.appendPage(newItems, nextPageKey);
      }
    } catch (error) {
      _pagingController.error = error;
    }
  }

  @override
  Widget build(BuildContext context) => 
      // Don't worry about displaying progress or error indicators on screen; the 
      // package takes care of that. If you want to customize them, use the 
      // [PagedChildBuilderDelegate] properties.
      PagedListView<int, CharacterSummary>(
        pagingController: _pagingController,
        builderDelegate: PagedChildBuilderDelegate<CharacterSummary>(
          itemBuilder: (context, item, index) => CharacterListItem(
            character: item,
          ),
        ),
      );

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

下面是一个基于 答案的简单无限列表小部件。它接受 itemBuilder 来构建当前项目,并接受 onRequest 回调以在用户滚动到底部时请求更多数据。

import 'package:flutter/material.dart';

typedef Future<List<T>> RequestFn<T>(int nextIndex);
typedef Widget ItemBuilder<T>(BuildContext context, T item, int index);

class InifiniteList<T> extends StatefulWidget {
  final RequestFn<T> onRequest;
  final ItemBuilder<T> itemBuilder;

  const InifiniteList(
      {Key? key, required this.onRequest, required this.itemBuilder})
      : super(key: key);

  @override
  _InifiniteListState<T> createState() => _InifiniteListState<T>();
}

class _InifiniteListState<T> extends State<InifiniteList<T>> {
  List<T> items = [];
  bool end = false;

  _getMoreItems() async {
    final moreItems = await widget.onRequest(items.length);
    if (!mounted) return;

    if (moreItems.isEmpty) {
      setState(() => end = true);
      return;
    }
    setState(() => items = [...items, ...moreItems]);
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (context, index) {
        if (index < items.length) {
          return widget.itemBuilder(context, items[index], index);
        } else if (index == items.length && end) {
          return const Center(child: Text('End of list'));
        } else {
          _getMoreItems();
          return const SizedBox(
            height: 80,
            child: Center(child: CircularProgressIndicator()),
          );
        }
      },
      itemCount: items.length + 1,
    );
  }
}

用法

child: InifiniteList<String>(
  onRequest: requestItems,
  itemBuilder: (context, item, index) => Container(
    padding: const EdgeInsets.all(30),
    color: index % 2 == 0 ? Colors.purple.shade100 : Colors.lime.shade100,
    child: Text(item, style: Theme.of(context).textTheme.headline6),
  ),
),
// normally this is the place where you request the next batch of items
// on the network.
Future<List<String>> requestItems(int nextIndex) {
  const pageSize = 15;
  var result = List<String>.generate(pageSize, (i) => "Item: ${nextIndex + i + 1}");
  return Future<List<String>>.delayed(
    const Duration(milliseconds: 500),
    () => result,
  );
}

Live Demo