Flutter分页搜索栏插件paginated_search_bar的使用

Flutter分页搜索栏插件paginated_search_bar的使用

paginated_search_bar 是一个用于在结果列表中搜索和分页项目的库。默认情况下,它看起来像这样:

Basic demo gif

它支持广泛的自定义功能,包括自定义样式、头部、占位符、尾部等,并且基于 Endless 无限滚动视图库。

Advanced demo gif

基本用法

首先,我们来看一个基本的用法示例。在这个示例中,你需要提供一个用于获取数据的 onSearch 函数和一个用于显示搜索结果的 itemBuilder

class ExampleItem {
  final String title;

  ExampleItem({
    required this.title,
  });
}

PaginatedSearchBar<ExampleItem>(
  onSearch: ({
    required pageIndex,
    required pageSize,
    required searchQuery,
  }) async {
    // 调用你的搜索API以返回一个项目列表
    return [
      ExampleItem(title: 'Item 0'),
      ExampleItem(title: 'Item 1'),
    ];
  },
  itemBuilder: (
    context, {
    required item,
    required index,
  }) {
    return Text(item.title);
  },
);

在基本用法中,你只需要提供一个 onSearch 函数来获取数据和一个 itemBuilder 来指定如何在搜索结果列表中显示每个项目。

高级用法

接下来,我们来看一个更高级的用法示例。在这个示例中,我们提供了更多的定制选项,例如 emptyBuilderheaderBuilderState

PaginatedSearchBar<ExampleItem>(
  maxHeight: 300,
  hintText: 'Search',
  headerBuilderState: PaginatedSearchBarBuilderStateProperty.empty((context) {
    return const Text("我是一个仅在结果为空时显示的头部!");
  }),
  emptyBuilder: (context) {
    return const Text("我是一个空状态!");
  },
  paginationDelegate: EndlessPaginationDelegate(
    pageSize: 20,
    maxPages: 3,
  ),
  onSearch: ({
    required pageIndex,
    required pageSize,
    required searchQuery,
  }) async {
    return Future.delayed(const Duration(milliseconds: 1000), () {
      if (searchQuery == "empty") {
        return [];
      }

      return [
        ExampleItem(title: '第 $pageIndex 页项目 1'),
        ExampleItem(title: '第 $pageIndex 页项目 2'),
      ];
    });
  },
  itemBuilder: (
    context, {
    required item,
    required index,
  }) {
    return Text(item.title);
  },
);

在这个更高级的示例中,我们提供了一些更多的定制选项,包括 emptyBuilderheaderBuilderState。所有这些构建器函数都提供当前的 BuildContext 并返回要显示的 widget。每个构建器函数还有一个对应的 StateProperty 构建器,如我们在 headerBuilderState 中看到的那样。PaginatedSearchBar 库使用 State property 模式来根据系统的状态自定义 widget 的显示。

PaginatedSearchBar 的完整状态列表如下:

enum PaginatedSearchBarState {
  /// 当搜索栏正在搜索项目时出现。当用户更新他们的搜索查询时触发。
  searching,

  /// 当搜索栏正在获取项目页面时出现。这可能是由于修改了搜索查询或通过滚动到列表视图底部并触发下一页加载。
  loading,

  /// 当搜索栏没有与当前搜索查询匹配的项目时出现。
  empty,

  /// 当搜索栏没有更多项目可以获取时出现。当 `[PaginatedSearchBar.onSearch]` 函数返回少于 `[PaginatedSearchBar.pageLimit]` 个项目或 `[EndlessPaginationDelegate.maxPage]` 已达到且无法获取更多项目时触发。
  done,

  /// 当输入框当前处于焦点状态时出现。
  focused,
}

状态属性构建器让我们可以根据这些状态自定义构建的内容。在上面的例子中,我们使用 headerBuilderState 指定了只有在搜索结果为空时才构建该 widget。

如果我们想要在搜索结果为空或完成时显示该 widget,我们可以使用 resolveWith 构建器:

PaginatedSearchBar<ExampleItem>(
  headerBuilderState: PaginatedSearchBarBuilderStateProperty.resolveWith((context, states) {
    if (states.contains(PaginatedSearchBarState.empty) || states.contains(PaginatedSearchBarState.done)) {
      return const Text("我是一个仅在结果为空或完成时显示的头部!");
    }
  }),
  onSearch: ({
    required pageIndex,
    required pageSize,
    required searchQuery,
  }) async {
    return Future.delayed(const Duration(milliseconds: 1000), () {
      if (searchQuery == "empty") {
        return [];
      }

      return [
        ExampleItem(title: '第 $pageIndex 页项目 1'),
        ExampleItem(title: '第 $pageIndex 页项目 2'),
      ];
    });
  },
  itemBuilder: (
    context, {
    required item,
    required index,
  }) {
    return Text(item.title);
  },
);

状态属性可用于 [PaginatedSearchBar] 的构建器和样式属性。

完整示例

下面是完整的示例代码,展示了如何使用 paginated_search_bar 插件。

import 'package:flutter/material.dart';
import 'package:paginated_search_bar/paginated_search_bar.dart';
import 'package:endless/endless.dart';

class ExampleItem {
  final String title;

  ExampleItem({
    required this.title,
  });
}

class ExampleItemPager {
  int pageIndex = 0;
  final int pageSize;

  ExampleItemPager({
    this.pageSize = 20,
  });

  List<ExampleItem> nextBatch() {
    List<ExampleItem> batch = [];

    for (int i = 0; i < pageSize; i++) {
      batch.add(ExampleItem(title: 'Item ${pageIndex * pageSize + i}'));
    }

    pageIndex += 1;

    return batch;
  }
}

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

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

  // This widget is the root of your application.
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    ExampleItemPager pager = ExampleItemPager();

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          Container(
            padding: const EdgeInsets.only(top: 200),
            alignment: Alignment.topCenter,
            child: SizedBox(
              width: 600,
              child: PaginatedSearchBar<ExampleItem>(
                maxHeight: 300,
                hintText: 'Search',
                emptyBuilder: (context) {
                  return const Text("我是一个空状态!");
                },
                placeholderBuilder: (context) {
                  return const Text("我是一个占位符状态!");
                },
                paginationDelegate: EndlessPaginationDelegate(
                  pageSize: 20,
                  maxPages: 3,
                ),
                onSearch: ({
                  required pageIndex,
                  required pageSize,
                  required searchQuery,
                }) async {
                  return Future.delayed(const Duration(milliseconds: 1300), () {
                    if (searchQuery == "empty") {
                      return [];
                    }

                    if (pageIndex == 0) {
                      pager = ExampleItemPager();
                    }

                    return pager.nextBatch();
                  });
                },
                itemBuilder: (
                  context, {
                  required item,
                  required index,
                }) {
                  return Text(item.title);
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

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

1 回复

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


当然,下面是一个关于如何在Flutter应用中使用paginated_search_bar插件的简单代码示例。paginated_search_bar插件允许你实现分页搜索功能,非常适合用于大数据集的搜索场景。

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

dependencies:
  flutter:
    sdk: flutter
  paginated_search_bar: ^最新版本号 # 替换为实际最新版本号

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

以下是一个简单的示例代码,展示了如何使用paginated_search_bar插件:

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

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  final List<String> items = List.generate(1000, (index) => 'Item $index');
  String searchQuery = '';
  int currentPage = 1;
  int itemsPerPage = 20;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Paginated Search Bar Example'),
      ),
      body: Column(
        children: [
          PaginatedSearchBar<String>(
            onSearchChanged: (query) {
              setState(() {
                searchQuery = query;
                currentPage = 1; // Reset to first page when search query changes
              });
            },
            onPageChanged: (page) {
              setState(() {
                currentPage = page;
              });
            },
            itemsPerPage: itemsPerPage,
            key: ValueKey(searchQuery), // Important to avoid bugs when search query changes
            itemFinder: (String query) {
              return items
                  .where((item) => item.toLowerCase().contains(query.toLowerCase()))
                  .toList();
            },
            itemBuilder: (_, item) {
              return ListTile(
                title: Text(item),
              );
            },
          ),
          if (searchQuery.isNotEmpty)
            Expanded(
              child: ListView.builder(
                itemCount: calculateItemsCount(),
                itemBuilder: (_, index) {
                  final int itemIndex = (currentPage - 1) * itemsPerPage + index;
                  if (itemIndex >= filteredItems.length) return null;
                  return ListTile(
                    title: Text(filteredItems[itemIndex]),
                  );
                },
              ),
            )
          else
            Expanded(
              child: Center(
                child: Text('Please enter a search query'),
              ),
            ),
        ],
      ),
    );
  }

  List<String> get filteredItems {
    return items
        .where((item) => item.toLowerCase().contains(searchQuery.toLowerCase()))
        .toList();
  }

  int calculateItemsCount() {
    final int start = (currentPage - 1) * itemsPerPage;
    final int end = start + itemsPerPage;
    return min(end, filteredItems.length) - start;
  }
}

代码解释:

  1. 依赖添加:在pubspec.yaml中添加paginated_search_bar依赖。

  2. 基本结构:创建一个简单的Flutter应用,包含一个ScaffoldAppBar和一个ColumnColumn中包含了PaginatedSearchBar和一个ListView

  3. 数据:定义一个包含1000个字符串项的列表items

  4. 状态管理:使用searchQuerycurrentPageitemsPerPage来管理搜索查询、当前页码和每页显示的项数。

  5. PaginatedSearchBar

    • onSearchChanged:当搜索查询改变时,更新searchQuery并重置页码。
    • onPageChanged:当页码改变时,更新currentPage
    • itemsPerPage:设置每页显示的项数。
    • key:使用ValueKey避免搜索查询改变时的bug。
    • itemFinder:根据搜索查询过滤项。
    • itemBuilder:构建搜索建议项的UI。
  6. ListView:如果searchQuery不为空,显示过滤后的项。使用calculateItemsCount方法计算当前页应显示的项数。

  7. 过滤和分页逻辑filteredItems方法返回过滤后的项列表,calculateItemsCount方法计算当前页应显示的项数。

这个示例展示了如何使用paginated_search_bar插件实现分页搜索功能。你可以根据实际需求进一步定制和扩展这个示例。

回到顶部