Flutter高性能列表展示插件huge_listview的使用

Flutter高性能列表展示插件 huge_listview 的使用

HugeListView 是一个高性能的列表组件,能够轻松处理任意数量的项。与传统的无限滚动列表不同,它不会不断增加列表项,而是使用固定大小的缓存来保持少量页面(通常是几百个项),并随着新页面的到来丢弃旧页面。

基本介绍

  • 特点

    • 只加载和缓存当前需要显示的页面。
    • 支持异步加载数据。
    • 支持非均匀高度的项,不影响性能。
    • 使用自定义的 DraggableScrollbar 来支持滚动条功能。
  • 依赖库

    • scrollable_positioned_list:用于支持滚动到特定项。
    • draggable_scrollbar:用于实现可拖动的滚动条。

使用示例

安装

pubspec.yaml 文件中添加依赖:

dependencies:
  huge_listview: ^latest_version

然后运行 flutter pub get 来安装依赖。

示例代码

以下是一个完整的示例,展示了如何使用 HugeListView

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:huge_listview/huge_listview.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const MyHomePage(),
    );
  }
}

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

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Expanded(
          child: PageView(
            controller: PageController(initialPage: 0),
            children: const [
              SimplePage(title: 'HugeListView simple demo'),
              DeletablePage(title: 'HugeListView deletable demo'),
            ],
          ),
        ),
        Container(
          color: Colors.blue.shade200,
          padding: const EdgeInsets.all(12),
          child: Text(
            'Swipe to see other pages',
            style: Theme.of(context).textTheme.bodyLarge!,
          ),
        )
      ],
    );
  }
}

class SimplePage extends StatefulWidget {
  final String title;

  const SimplePage({super.key, required this.title});

  [@override](/user/override)
  State<SimplePage> createState() => _SimplePageState();
}

class _SimplePageState extends State<SimplePage> {
  static const int PAGE_SIZE = 24;
  final scroll = ItemScrollController();
  final controller = HugeListViewController(totalItemCount: 999999);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: HugeListView<String>(
        scrollController: scroll,
        listViewController: controller,
        pageSize: PAGE_SIZE,
        startIndex: 0,
        pageFuture: (page) => _loadPage(page, PAGE_SIZE),
        itemBuilder: (context, index, String entry) {
          return ListTile(title: Text(entry));
        },
        thumbBuilder: DraggableScrollbarThumbs.SemicircleThumb,
        placeholderBuilder: (context, index) => buildPlaceholder(),
        alwaysVisibleThumb: false,
      ),
    );
  }

  Future<List<String>> _loadPage(int page, int pageSize) async {
    int from = page * pageSize;
    int to = min(999999, from + pageSize);
    return List.generate(to - from, (index) => 'Item #${from + index}');
  }

  Widget buildPlaceholder() {
    double margin = Random().nextDouble() * 50;
    return Padding(
      padding: EdgeInsets.fromLTRB(3, 3, 3 + margin, 3),
      child: Container(
        height: 15,
        color: Colors.grey,
      ),
    );
  }
}

class DeletablePage extends StatefulWidget {
  final String title;

  const DeletablePage({super.key, required this.title});

  [@override](/user/override)
  State<DeletablePage> createState() => _DeletablePageState();
}

class _DeletablePageState extends State<DeletablePage> {
  static const int PAGE_SIZE = 24;
  final scroll = ItemScrollController();
  final controller = HugeListViewController(totalItemCount: 10000);
  late List<String> list;

  [@override](/user/override)
  void initState() {
    super.initState();
    list = List.generate(controller.totalItemCount + 1,
        (index) => 'Item #$index of ${controller.totalItemCount}');
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: HugeListView<String>(
        scrollController: scroll,
        listViewController: controller,
        pageSize: PAGE_SIZE,
        startIndex: 0,
        pageFuture: (page) => _loadPage(page, PAGE_SIZE),
        itemBuilder: (context, index, String entry) {
          return ListTile(title: Text(entry));
        },
        thumbBuilder: DraggableScrollbarThumbs.SemicircleThumb,
        placeholderBuilder: (context, index) => buildPlaceholder(),
        alwaysVisibleThumb: false,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          final newCount = Random().nextInt(10000) + 10000;
          setState(() {
            list = List.generate(
                newCount + 1, (index) => 'New Item #$index of $newCount');
          });
          controller.invalidateList(true);
          controller.totalItemCount = newCount;
        },
        tooltip: 'Update list',
        child: const Icon(Icons.refresh),
      ),
    );
  }

  Future<List<String>> _loadPage(int page, int pageSize) async {
    int from = page * pageSize;
    int to = min(controller.totalItemCount, from + pageSize);
    return list.sublist(from, to);
  }

  Widget buildPlaceholder() {
    double margin = Random().nextDouble() * 50;
    return Padding(
      padding: EdgeInsets.fromLTRB(3, 3, 3 + margin, 3),
      child: Container(
        height: 15,
        color: Colors.grey,
      ),
    );
  }
}

关键参数说明

  • pageSize: 每页的项数,默认为24。
  • startIndex: 初始对齐的索引。
  • pageFuture: 异步加载数据的方法,返回 Future<List<T>>
  • itemBuilder: 构建每个项的回调函数。
  • thumbBuilder: 自定义滚动条样式。
  • placeholderBuilder: 加载占位符构建器。
  • alwaysVisibleThumb: 是否始终显示滚动条。

自定义滚动条

如果需要自定义滚动条样式,可以提供一个 thumbBuilder 函数:

thumbBuilder: (Color backgroundColor, Color drawColor, double height, int index, bool alwaysVisibleScrollThumb, Animation<double> thumbAnimation) {
  return ScrollBarThumb(backgroundColor, drawColor, height, index.toString(), alwaysVisibleScrollThumb, thumbAnimation);
}

其中 ScrollBarThumb 可以根据需求进行定制,例如:

class ScrollBarThumb extends StatelessWidget {
  // ... 省略其他代码 ...
  
  [@override](/user/override)
  Widget build(BuildContext context) {
    final thumb = Row(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        Container(
          padding: EdgeInsets.all(8),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(10),
            color: Colors.white.withOpacity(0.8),
          ),
          child: Text(
            title,
            style: TextStyle(
              color: Colors.black,
              backgroundColor: Colors.transparent,
              fontSize: 14,
            ),
          ),
        ),
        Padding(
          padding: EdgeInsets.all(2),
        ),
        CustomPaint(
          foregroundPainter: _ArrowCustomPainter(drawColor),
          child: Material(
            elevation: 4.0,
            child: Container(constraints: BoxConstraints.tight(Size(height * 0.6, height))),
            color: backgroundColor,
            borderRadius: BorderRadius.only(
              topLeft: Radius.circular(height),
              bottomLeft: Radius.circular(height),
              topRight: Radius.circular(4.0),
              bottomRight: Radius.circular(4.0),
            ),
          ),
        ),
      ],
    );
    return alwaysVisibleScrollThumb ? thumb : SlideFadeTransition(animation: thumbAnimation, child: thumb);
  }
}

更多关于Flutter高性能列表展示插件huge_listview的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter高性能列表展示插件huge_listview的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用 huge_listview 插件在 Flutter 中实现高性能列表展示的示例代码。huge_listview 插件旨在处理大规模数据列表的高效渲染,这对于需要展示大量数据的应用来说非常有用。

首先,确保你的 pubspec.yaml 文件中已经添加了 huge_listview 依赖:

dependencies:
  flutter:
    sdk: flutter
  huge_listview: ^最新版本号  # 替换为最新版本号

然后运行 flutter pub get 来获取依赖。

接下来是一个完整的示例代码,展示了如何使用 huge_listview 来展示一个包含大量数据的列表:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Huge ListView Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> {
  // 模拟大量数据
  List<int> _data = List.generate(10000, (index) => index);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Huge ListView Example'),
      ),
      body: HugeListView.builder(
        itemCount: _data.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('Item ${_data[index]}'),
          );
        },
        // 可以根据需要调整缓存策略等参数
        cacheExtent: 50, // 预加载项数
        // itemExtent: 50, // 如果每个item高度固定,可以设置这个参数
      ),
    );
  }
}

代码解释:

  1. 依赖导入

    • pubspec.yaml 中添加 huge_listview 依赖。
  2. 主应用入口

    • MyApp 类是应用的根组件,包含一个 MaterialApp,它定义了应用的主题和主页。
  3. 主页

    • MyHomePage 是一个 StatefulWidget,它持有一个包含大量数据的列表 _data
    • build 方法中,返回一个包含 AppBarHugeListViewScaffold
  4. 数据展示

    • 使用 HugeListView.builder 构造函数来构建列表。
    • itemCount 指定了列表中的项数。
    • itemBuilder 是一个回调,用于构建每个列表项。在这个例子中,每个列表项都是一个 ListTile,显示数据项的值。
    • cacheExtent 参数指定了预加载的项数,这有助于改善滚动性能。如果每个列表项的高度是固定的,可以设置 itemExtent 参数来进一步优化性能。

通过这种方式,你可以使用 huge_listview 插件在 Flutter 应用中高效地展示大规模数据列表。

回到顶部