Flutter分页列表插件paginated_list的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter分页列表插件paginated_list的使用

paginated_list

style: very good analysis License: MIT

paginated_list 是一个Flutter插件,它提供了一个可滚动容器来显示项目列表。该列表可以水平或垂直滚动。此外,这个列表可以是无限的,即当用户滚动时,它会请求更多的项目。

Introduction

此库通过提供易于访问的函数使分页更简单。以下是一些关键特性的说明:

  1. 类型化PaginatedList<T> 接收一个泛型类型参数,这决定了构建器接收到的第一个参数类型以及items列表中的元素类型。
  2. 加载更多:当最后一个项目完全可见时,会调用onLoadMore函数,在这里应该放置添加更多项目的逻辑。
  3. 最近搜索按钮(可选):如果设置isRecentSearch为true,则会在组件右上角添加一个IconButton,默认情况下允许删除旧搜索记录。
  4. 是否为最后一页:通过isLastPage布尔值来判断是否已经显示了所有数据,如果是,则不会展示加载指示器且不触发加载更多操作。
  5. 主布局PaginatedList内部使用的是ListView.builder(),因此可能需要在外层包裹Expanded或者指定尺寸的SizedBox以确保其正确渲染。

示例GIF

app example

Usage

以下是PaginatedList的基本用法示例:

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

class MovieList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return PaginatedList<Movie>(
      loadingIndicator: const Padding(
        padding: EdgeInsets.symmetric(vertical: 20),
        child: Center(
          child: CircularProgressIndicator(color: Colors.black),
        ),
      ),
      items: state.movies, // 假设state.movies是从状态管理中获取的数据
      isRecentSearch: false,
      isLastPage: state.isLastPage, // 假设state.isLastPage是一个布尔变量,表示是否到达了最后一页
      onLoadMore: (index) => context.read<MovieBloc>().loadMore(),
      builder: (movie, index) => ListTile(
        title: Text(movie.title),
        subtitle: Text(movie.overview),
        leading: Image.network(movie.posterPath ?? ''),
      ),
    );
  }
}

对于网格视图,你可以使用PaginatedGrid

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

class MovieGrid extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return PaginatedGrid<Movie>(
      loadingIndicator: const Padding(
        padding: EdgeInsets.symmetric(vertical: 20),
        child: Center(
          child: CircularProgressIndicator(color: Colors.black),
        ),
      ),
      items: state.movies, // 假设state.movies是从状态管理中获取的数据
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        crossAxisSpacing: 20,
        mainAxisSpacing: 20,
        childAspectRatio: 0.7,
      ),
      isLastPage: state.isLastPage, // 假设state.isLastPage是一个布尔变量,表示是否到达了最后一页
      onLoadMore: () => context.read<MovieBloc>().loadMore(),
      builder: (movie, index) => Card(
        child: Column(
          children: [
            Image.network(movie.posterPath ?? ''),
            Text(movie.title),
            Text(movie.overview),
          ],
        ),
      ),
    );
  }
}

完整示例Demo

为了更好地理解如何使用paginated_list插件,下面提供了一个完整的例子,包括应用程序入口点和电影列表页面。

// main.dart
import 'package:flutter/material.dart';
import 'package:paginated_list/paginated_list.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Paginated List Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MovieListScreen(),
    );
  }
}

class MovieListScreen extends StatefulWidget {
  @override
  _MovieListScreenState createState() => _MovieListScreenState();
}

class _MovieListScreenState extends State<MovieListScreen> {
  final List<Movie> movies = [];
  bool isLastPage = false;

  @override
  void initState() {
    super.initState();
    loadMoreMovies();
  }

  Future<void> loadMoreMovies() async {
    // 模拟网络请求
    await Future.delayed(Duration(seconds: 2));

    if (movies.length >= 20) {
      setState(() {
        isLastPage = true;
      });
      return;
    }

    final newMovies = List.generate(10, (index) => Movie(
      title: 'Movie ${movies.length + index + 1}',
      overview: 'Overview of movie ${movies.length + index + 1}',
      posterPath: 'https://via.placeholder.com/150',
    ));

    setState(() {
      movies.addAll(newMovies);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Movies'),
      ),
      body: PaginatedList<Movie>(
        loadingIndicator: const Padding(
          padding: EdgeInsets.symmetric(vertical: 20),
          child: Center(
            child: CircularProgressIndicator(color: Colors.black),
          ),
        ),
        items: movies,
        isRecentSearch: false,
        isLastPage: isLastPage,
        onLoadMore: (_) => loadMoreMovies(),
        builder: (movie, index) => ListTile(
          title: Text(movie.title),
          subtitle: Text(movie.overview),
          leading: Image.network(movie.posterPath),
        ),
      ),
    );
  }
}

class Movie {
  final String title;
  final String overview;
  final String posterPath;

  Movie({required this.title, required this.overview, required this.posterPath});
}

在这个例子中,我们创建了一个简单的电影列表应用。每次滚动到底部时都会加载更多电影,并在达到最后一页后停止加载。


更多关于Flutter分页列表插件paginated_list的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter分页列表插件paginated_list的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用paginated_list插件来实现分页列表的一个示例代码。paginated_list插件可以帮助你轻松实现分页加载数据的功能。

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

dependencies:
  flutter:
    sdk: flutter
  paginated_list: ^x.y.z  # 请替换为最新版本号

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

接下来是一个完整的示例代码,展示如何使用paginated_list插件:

import 'package:flutter/material.dart';
import 'package:paginated_list/paginated_list.dart';
import 'dart:async';

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  final PaginatedListController<int> _controller = PaginatedListController<int>();

  @override
  void initState() {
    super.initState();
    // 初始化分页加载数据
    _loadData();
  }

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

  Future<void> _loadData() async {
    // 模拟分页加载数据
    final Future<List<int>> fetchPage(int page) async {
      await Future.delayed(Duration(seconds: 1)); // 模拟网络延迟
      return List.generate(10, (index) => (page - 1) * 10 + index + 1);
    }

    // 设置分页加载逻辑
    _controller.setLoadMoreItems(() async {
      final int currentPage = _controller.page + 1;
      final List<int> newItems = await fetchPage(currentPage);
      return PaginatedListLoadResult.success(newItems);
    });

    // 初始加载第一页数据
    _controller.setItems(await fetchPage(1));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Paginated List Demo'),
      ),
      body: PaginatedListView<int>(
        controller: _controller,
        itemBuilder: (context, item, index) {
          return ListTile(
            title: Text('Item ${item}'),
          );
        },
        separatorBuilder: (context, index) => Divider(),
        errorWidget: (context, error, retry) {
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Error: $error'),
                SizedBox(height: 10),
                ElevatedButton(
                  onPressed: retry,
                  child: Text('Retry'),
                ),
              ],
            ),
          );
        },
        emptyWidget: Center(child: Text('No data')),
      ),
    );
  }
}

代码解释

  1. 依赖导入

    • 导入flutterpaginated_list包。
  2. 主应用

    • MyApp是一个简单的MaterialApp,设置了主题和主页MyHomePage
  3. 主页

    • MyHomePage是一个StatefulWidget,包含一个PaginatedListController<int>用于管理分页数据。
    • initState中调用_loadData方法初始化分页加载逻辑。
    • dispose中释放PaginatedListController资源。
  4. 数据加载

    • _loadData方法模拟分页加载数据,使用fetchPage函数模拟网络请求。
    • 设置分页加载逻辑,通过_controller.setLoadMoreItems方法。
    • 初始加载第一页数据,通过_controller.setItems方法。
  5. UI构建

    • 使用PaginatedListView构建分页列表,传入controlleritemBuilderseparatorBuildererrorWidgetemptyWidget
    • itemBuilder定义了每个列表项的UI。
    • separatorBuilder定义了列表项之间的分隔符。
    • errorWidget定义了加载数据出错时的UI。
    • emptyWidget定义了数据为空时的UI。

这个示例展示了如何使用paginated_list插件实现一个简单的分页列表功能。你可以根据实际需求调整数据加载逻辑和UI样式。

回到顶部