flutter_deer列表项组件:高度复用的列表元素设计

【免费下载链接】flutter_deer 🦌 Flutter 练习项目(包括集成测试、可访问性测试)。内含完整UI设计图,更贴近真实项目的练习。Flutter practice project (including integration testing and accessibility testing). Contains complete UI design drawings for a more realistic practice project. 【免费下载链接】flutter_deer 项目地址: https://gitcode.com/gh_mirrors/fl/flutter_deer

在移动应用开发中,列表是最常见的UI组件之一。flutter_deer项目通过精心设计的列表项组件,实现了代码复用与视觉一致性的平衡。本文将深入分析项目中的列表项设计模式,包括基础列表容器、商品列表项实现及复用策略。

基础列表容器:DeerListView

项目中封装了通用的下拉刷新列表容器DeerListView,该组件继承自StatefulWidget,整合了下拉刷新、加载更多、空状态展示等常用功能。其核心实现位于lib/widgets/my_refresh_list.dart文件中。

DeerListView的主要特性包括:

  • 内置下拉刷新功能,通过RefreshIndicator实现
  • 支持加载更多,自动监听滚动到底部事件
  • 空状态展示,使用StateLayout组件
  • 安全区域适配,通过SafeArea包裹内容

关键实现代码如下:

class DeerListView extends StatefulWidget {
  const DeerListView({
    super.key,
    required this.itemCount,
    required this.itemBuilder,
    required this.onRefresh,
    this.loadMore,
    this.hasMore = false,
    this.stateType = StateType.empty,
    this.pageSize = 10,
    this.padding,
    this.itemExtent,
  });
  
  // ...属性定义
  
  @override
  _DeerListViewState createState() => _DeerListViewState();
}

在构建方法中,通过条件判断决定展示列表内容还是空状态:

child: widget.itemCount == 0 ? 
  StateLayout(type: widget.stateType) : 
  ListView.builder(
    itemCount: widget.loadMore == null ? widget.itemCount : widget.itemCount + 1,
    padding: widget.padding,
    itemExtent: widget.itemExtent,
    itemBuilder: (BuildContext context, int index) {
      // ...item构建逻辑
    },
  ),

加载更多功能通过监听滚动通知实现:

NotificationListener<ScrollNotification>(
  onNotification: (ScrollNotification note) {
    if (note.metrics.pixels == note.metrics.maxScrollExtent && note.metrics.axis == Axis.vertical) {
      _loadMore();
    }
    return true;
  },
  child: child,
)

商品列表项:GoodsItem实现

商品列表是电商类应用的核心功能,flutter_deer项目在lib/goods/widgets/goods_item.dart中实现了高度定制化的商品列表项组件。

组件结构设计

GoodsItem采用Row作为基础布局容器,包含四个主要部分:

  1. 商品图片:使用Hero组件实现页面间转场动画
  2. 商品信息区:包含标题、标签和价格
  3. 操作按钮区:右侧的菜单按钮
  4. 滑动菜单:通过Stack实现的侧滑操作菜单

商品列表项设计

核心布局代码如下:

final Row child = Row(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: <Widget>[
    ExcludeSemantics(
      child: Hero(
        tag: heroTag,
        child: LoadImage(item.icon, width: 72.0, height: 72.0),
      ),
    ),
    Gaps.hGap8,
    Expanded(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          // 商品标题、标签和价格
        ],
      ),
    ),
    Column(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: <Widget>[
        // 操作菜单按钮
      ],
    )
  ],
);

标签组件设计

商品标签通过_GoodsItemTag私有组件实现,支持不同颜色和文本:

class _GoodsItemTag extends StatelessWidget {
  const _GoodsItemTag({
    required this.color,
    required this.text,
  });

  final Color? color;
  final String text;
  
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 4.0),
      margin: const EdgeInsets.only(right: 4.0),
      decoration: BoxDecoration(
        color: color,
        borderRadius: BorderRadius.circular(2.0),
      ),
      height: 16.0,
      alignment: Alignment.center,
      child: Text(
        text,
        style: TextStyle(
          color: Colors.white,
          fontSize: Dimens.font_sp10,
          height: Device.isAndroid ? 1.1 : null,
        ),
      ),
    );
  }
}

在商品项中灵活使用标签:

Row(
  children: <Widget>[
    Visibility(
      visible: item.type % 3 == 0,
      child: _GoodsItemTag(
        text: '立减',
        color: Theme.of(context).colorScheme.error,
      ),
    ),
    Opacity(
      opacity: item.type % 2 != 0 ? 0.0 : 1.0,
      child: _GoodsItemTag(
        text: '金币抵扣',
        color: Theme.of(context).primaryColor,
      ),
    )
  ],
)

侧滑菜单实现

GoodsItem通过Stack和动画实现了侧滑菜单功能,当用户点击右侧菜单按钮时,会滑出编辑、下架和删除选项。核心实现位于_buildGoodsMenu方法:

Widget _buildGoodsMenu(BuildContext context) {
  return Positioned.fill(
    child: AnimatedBuilder(
      animation: animation,
      child: _buildGoodsMenuContent(context),
      builder: (_, Widget? child) {
        return MenuReveal(
          revealPercent: animation.value,
          child: child!
        );
      }
    ),
  );
}

菜单内容使用Row布局,包含三个操作按钮:

Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: <Widget>[
    Gaps.hGap15,
    MyButton(
      key: Key('goods_edit_item_$index'),
      text: '编辑',
      // ...其他属性
      onPressed: onTapEdit,
    ),
    MyButton(
      key: Key('goods_operation_item_$index'),
      text: '下架',
      // ...其他属性
      onPressed: onTapOperation,
    ),
    MyButton(
      key: Key('goods_delete_item_$index'),
      text: '删除',
      // ...其他属性
      onPressed: onTapDelete,
    ),
    Gaps.hGap15,
  ],
)

列表项复用策略

flutter_deer项目在多个模块中复用了列表相关组件,形成了层次化的复用体系:

  1. 基础组件层

  2. 业务组件层

  3. 页面应用层

以商品列表页为例,其使用DeerListView作为容器,GoodsItem作为列表项:

return DeerListView(
  itemCount: _goodsList.length,
  itemBuilder: (_, index) {
    return GoodsItem(
      item: _goodsList[index],
      index: index,
      // ...其他回调和属性
    );
  },
  onRefresh: _onRefresh,
  loadMore: _loadMore,
  hasMore: _hasMore,
);

列表项设计最佳实践

通过分析flutter_deer项目的列表项实现,我们可以总结出以下最佳实践:

1. 组件职责单一

每个列表相关组件专注于单一职责:

  • DeerListView负责列表容器和数据加载逻辑
  • GoodsItem专注于单个商品项的UI展示
  • _GoodsItemTag处理标签展示

2. 灵活的配置项

通过构造函数参数提供丰富的配置选项,使组件适应不同场景:

const GoodsItem({
  super.key,
  required this.item,
  required this.index,
  required this.selectIndex,
  required this.onTapMenu,
  required this.onTapEdit,
  required this.onTapOperation,
  required this.onTapDelete,
  required this.onTapMenuClose,
  required this.animation,
  required this.heroTag,
});

3. 语义化标签

为提升可访问性,GoodsItem使用了Semantics和ExcludeSemantics组件:

Semantics(
  /// container属性为true,防止上方ExcludeSemantics去除此处语义
  container: true,
  label: '商品操作菜单',
  child: GestureDetector(
    onTap: onTapMenu,
    // ...
  ),
)

4. 动画与过渡效果

通过Hero动画实现页面间转场,通过MenuReveal实现平滑的菜单过渡,提升用户体验。

总结

flutter_deer项目的列表项组件设计展示了如何在Flutter中构建高度复用、功能完善的列表UI。通过DeerListView和GoodsItem等组件的分层设计,项目实现了代码复用与业务定制的平衡。

官方文档中还提供了更多平台相关问题的解决方案,如Android问题汇总iOS问题汇总Web问题汇总,可帮助开发者解决不同平台上的列表展示问题。

建议开发者在实际项目中参考这些设计模式,结合自身需求进行调整,以构建高效、美观的列表界面。项目的测试代码,如goods_accessibility_test.dart,也提供了列表项可访问性测试的参考范例。

【免费下载链接】flutter_deer 🦌 Flutter 练习项目(包括集成测试、可访问性测试)。内含完整UI设计图,更贴近真实项目的练习。Flutter practice project (including integration testing and accessibility testing). Contains complete UI design drawings for a more realistic practice project. 【免费下载链接】flutter_deer 项目地址: https://gitcode.com/gh_mirrors/fl/flutter_deer

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐