Widgets

CollectionView

简介

CollectionView 组件是一个强大的、类型安全的包装器,用于在您的 Nylo Website 项目中显示数据列表。它简化了 ListViewListView.separated 和网格布局的使用,同时提供内置支持:

  • 异步数据加载与自动加载状态
  • 下拉刷新和分页
  • 带有位置辅助方法的类型安全项目构建器
  • 空状态处理
  • 数据排序和转换

基本用法

以下是显示项目列表的简单示例:

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: CollectionView<String>(
      data: () => ['Item 1', 'Item 2', 'Item 3'],
      builder: (context, item) {
        return ListTile(
          title: Text(item.data),
        );
      },
    ),
  );
}

使用来自 API 的异步数据:

CollectionView<Todo>(
  data: () async {
    return await api<ApiService>((request) =>
      request.get('https://jsonplaceholder.typicode.com/todos')
    );
  },
  builder: (context, item) {
    return ListTile(
      title: Text(item.data.title),
      subtitle: Text(item.data.completed ? 'Done' : 'Pending'),
    );
  },
)

CollectionItem 辅助类

builder 回调接收一个 CollectionItem<T> 对象,该对象用有用的位置辅助方法包装您的数据:

CollectionView<String>(
  data: () => ['First', 'Second', 'Third', 'Fourth'],
  builder: (context, item) {
    return Container(
      color: item.isEven ? Colors.grey[100] : Colors.white,
      child: ListTile(
        title: Text('${item.data} (index: ${item.index})'),
        subtitle: Text('Progress: ${(item.progress * 100).toInt()}%'),
      ),
    );
  },
)

CollectionItem 属性

属性 类型 描述
data T 实际的项目数据
index int 在列表中的当前索引
totalItems int 项目总数
isFirst bool 是否为第一个项目
isLast bool 是否为最后一个项目
isOdd bool 索引是否为奇数
isEven bool 索引是否为偶数
progress double 列表进度(0.0 到 1.0)

CollectionItem 方法

方法 描述
isAt(int position) 检查项目是否在特定位置
isInRange(int start, int end) 检查索引是否在范围内(包含端点)
isMultipleOf(int divisor) 检查索引是否为除数的倍数

CollectionView

默认构造函数创建标准列表视图:

CollectionView<Map<String, dynamic>>(
  data: () async {
    return [
      {"title": "Clean Room"},
      {"title": "Go shopping"},
      {"title": "Buy groceries"},
    ];
  },
  builder: (context, item) {
    return ListTile(title: Text(item.data['title']));
  },
  spacing: 8.0, // Add spacing between items
  padding: EdgeInsets.all(16),
)

CollectionView.separated

创建带有项目之间分隔符的列表:

CollectionView<User>.separated(
  data: () async => await fetchUsers(),
  builder: (context, item) {
    return ListTile(
      title: Text(item.data.name),
      subtitle: Text(item.data.email),
    );
  },
  separatorBuilder: (context, index) {
    return Divider(height: 1);
  },
)

CollectionView.grid

使用交错网格创建网格布局:

CollectionView<Product>.grid(
  data: () async => await fetchProducts(),
  builder: (context, item) {
    return ProductCard(product: item.data);
  },
  crossAxisCount: 2,
  mainAxisSpacing: 8.0,
  crossAxisSpacing: 8.0,
  padding: EdgeInsets.all(16),
)

CollectionView.pullable

创建带有下拉刷新和无限滚动分页的列表:

CollectionView<Post>.pullable(
  data: (int iteration) async {
    // iteration starts at 1 and increments on each load
    return await api<ApiService>((request) =>
      request.get('/posts?page=$iteration')
    );
  },
  builder: (context, item) {
    return PostCard(post: item.data);
  },
  onRefresh: () {
    print('List was refreshed!');
  },
  headerStyle: 'WaterDropHeader', // Pull indicator style
)

头部样式

headerStyle 参数接受:

  • 'WaterDropHeader'(默认)- 水滴动画
  • 'ClassicHeader' - 经典下拉指示器
  • 'MaterialClassicHeader' - Material 设计风格
  • 'WaterDropMaterialHeader' - Material 水滴效果
  • 'BezierHeader' - 贝塞尔曲线动画

分页回调

回调 描述
beforeRefresh 刷新开始前调用
onRefresh 刷新完成时调用
afterRefresh 数据加载后调用,接收数据用于转换

CollectionView.pullableSeparated

将下拉刷新与分隔列表结合:

CollectionView<Message>.pullableSeparated(
  data: (iteration) async => await fetchMessages(page: iteration),
  builder: (context, item) {
    return MessageTile(message: item.data);
  },
  separatorBuilder: (context, index) => Divider(),
)

CollectionView.pullableGrid

将下拉刷新与网格布局结合:

CollectionView<Photo>.pullableGrid(
  data: (iteration) async => await fetchPhotos(page: iteration),
  builder: (context, item) {
    return Image.network(item.data.url);
  },
  crossAxisCount: 3,
  mainAxisSpacing: 4,
  crossAxisSpacing: 4,
)

加载样式

使用 loadingStyle 自定义加载指示器:

// Normal loading with custom widget
CollectionView<Item>(
  data: () async => await fetchItems(),
  builder: (context, item) => ItemTile(item: item.data),
  loadingStyle: LoadingStyle.normal(
    child: Text("Loading items..."),
  ),
)

// Skeletonizer loading effect
CollectionView<User>(
  data: () async => await fetchUsers(),
  builder: (context, item) => UserCard(user: item.data),
  loadingStyle: LoadingStyle.skeletonizer(
    child: UserCard(user: User.placeholder()),
    effect: SkeletonizerEffect.shimmer,
  ),
)

空状态

当列表为空时显示自定义组件:

CollectionView<Item>(
  data: () async => await fetchItems(),
  builder: (context, item) => ItemTile(item: item.data),
  empty: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Icon(Icons.inbox, size: 64, color: Colors.grey),
        SizedBox(height: 16),
        Text('No items found'),
      ],
    ),
  ),
)

排序和转换数据

排序

在显示之前对项目排序:

CollectionView<Task>(
  data: () async => await fetchTasks(),
  builder: (context, item) => TaskTile(task: item.data),
  sort: (List<Task> items) {
    items.sort((a, b) => a.dueDate.compareTo(b.dueDate));
    return items;
  },
)

转换

加载后转换数据:

CollectionView<User>(
  data: () async => await fetchUsers(),
  builder: (context, item) => UserTile(user: item.data),
  transform: (List<User> users) {
    // Filter to only active users
    return users.where((u) => u.isActive).toList();
  },
)

更新状态

您可以通过给 CollectionView 一个 stateName 来更新或重置它:

CollectionView<Todo>(
  stateName: "my_todo_list",
  data: () async => await fetchTodos(),
  builder: (context, item) => TodoTile(todo: item.data),
)

重置列表

// Resets and reloads data from scratch
CollectionView.stateReset("my_todo_list");

移除项目

// Remove item at index 2
CollectionView.removeFromIndex("my_todo_list", 2);

触发一般更新

// Using the global updateState helper
updateState("my_todo_list");

参数参考

通用参数

参数 类型 描述
data Function() 返回 List<T>Future<List<T>> 的函数
builder CollectionItemBuilder<T> 每个项目的构建函数
empty Widget? 列表为空时显示的组件
loadingStyle LoadingStyle? 自定义加载指示器
header Widget? 列表上方的头部组件
stateName String? 状态管理名称
sort Function(List<T>)? 项目排序函数
transform Function(List<T>)? 数据转换函数
spacing double? 项目之间的间距

可拉动特有参数

参数 类型 描述
data Function(int iteration) 分页数据函数
onRefresh Function()? 刷新完成时的回调
beforeRefresh Function()? 刷新前的回调
afterRefresh Function(dynamic)? 数据加载后的回调
headerStyle String? 下拉指示器样式
footerLoadingIcon Widget? 分页的自定义加载指示器

网格特有参数

参数 类型 描述
crossAxisCount int 列数(默认:2)
mainAxisSpacing double 项目之间的垂直间距
crossAxisSpacing double 项目之间的水平间距

ListView 参数

所有标准 ListView 参数也受支持:scrollDirectionreversecontrollerphysicsshrinkWrappaddingcacheExtent 等。