Skip to content

Widget 链式扩展

FlutterKit 在 lib/core/design_system/extensions/widget/ 为 Flutter WidgetList<Widget>List<T>int 提供了链式扩展。统一入口是:

dart
import 'package:flutter_kit/core/design_system/extensions/extensions.dart';

扩展的本质是将当前对象包装进标准 Flutter Widget,不会改变原组件。它用于让常见页面结构更紧凑;复杂约束、需要命名 key 或团队成员不熟悉链式顺序时,直接写 Flutter 原生 Widget 更清晰。

分类与 API

分类源码常用 API底层包装
Row / Column / Stack / Wraprow_extension.darttoRowtoColumnStretchtoStacktoWrapRowColumnStackWrap
尺寸与约束size_extension.dartwidthheightsizetightconstrainedaspectRatioSizedBoxConstrainedBoxAspectRatio
对齐与布局layout_extension.dartcenteralignmentexpandedflexiblepositionedsafeAreaCenterAlign、Flex、SafeArea
间距padding_extension.dartpadpadAllpadSymmetricpadHorizontalpadVerticalPadding
装饰decoration_extension.dartbackgroundColorbackgroundGradientborderboxShadowelevationDecoratedBoxMaterial
裁剪clip_extension.dartclipRRectclipRadiusclipCircleclipPathClipRRectClipOvalClipPath
滚动scroll_extension.dartscrollableverticalScrollhorizontalScrollbouncingScrollSingleChildScrollView
手势gesture_extension.dartonTaponLongPressgesturesonScaleGestureDetector
列表与网格list_view_extension.dartgrid_view_extension.darttoListViewtoListViewSeparatedtoGridViewListViewGridView
文本text_extension.darttext_span_extension.dartboldfontSizetextColortextStyleText.copyWith
变换与效果transform_extension.darteffect_extension.dartrotatescaletranslateopacityblurrippleTransformOpacityImageFilteredInkWell
语义与工具utility_extension.darticon_extension.dartkeep_alive_extension.dartvisibilitysemantics、图标样式、keepAliveFlutter 对应组件与 KeepAlive 包装

链式顺序决定 Widget 树

每次调用都把前一项作为 child。因此调用从左到右,外层包装逐渐增加;这会直接影响背景、裁剪和点击区域。

dart
/// 圆角背景卡片,背景本身被裁剪。
Widget buildClippedCard(AppTheme theme) {
  return const Text('内容')
      // 第一步:文字外层加内边距。
      .padAll(spacePaddingLarge)
      // 第二步:Padding 外层绘制容器背景。
      .backgroundColor(theme.backgroundContainer)
      // 第三步:裁剪最外层背景和内容,圆角真正生效。
      .clipRadius(radiusLarge);
}

上例对应概念树:ClipRRect(DecoratedBox(Padding(Text)))。若写成 .clipRadius(...).backgroundColor(...),得到 DecoratedBox(ClipRRect(Padding(Text))),背景不会被圆角裁剪。需要涟漪点击时,ripple() 应包在有 Material 背景和明确裁剪范围的合适层级,避免水波溢出卡片。

常用组合

列表页面

dart
/// 使用 List<Widget> 扩展构建标准纵向页面。
Widget buildPage(AppTheme theme) {
  return <Widget>[
    TDText('标题', font: theme.fontTitleLarge),
    const SpaceVerticalLarge(),
    const Text('正文内容'),
  ]
      // 纵向拉伸,保证每个子项占据可用宽度。
      .toColumnStretch()
      // 可滚动容器统一补页面边距。
      .scrollable(padding: pagePadding)
      .backgroundColor(theme.backgroundPage);
}

点击卡片

dart
/// 点击区域包住完整卡片,不只包住文本。
Widget buildActionCard(AppTheme theme, VoidCallback onTap) {
  return const Text('打开详情')
      .padAll(spacePaddingLarge)
      .backgroundColor(theme.backgroundContainer)
      .clipRadius(radiusDefault)
      // GestureDetector 放在最外层,整张卡片都可响应点击。
      .onTap(onTap);
}

数据列表和网格

dart
/// 数据集合扩展自动提供 itemBuilder 的 index 与元素。
Widget buildGoodsGrid(List<Goods> goods) {
  return goods.toGridView(
    crossAxisCount: 2,
    // 业务只描述每个商品项,GridView 配置由扩展处理。
    itemBuilder: (context, index, item) => GoodsListCard(goods: item),
  );
}

何时使用原生 Widget

  • 父子约束需要一眼可见,例如复杂 CustomScrollView、Sliver、嵌套滚动和 LayoutBuilder
  • 需要精确管理 KeyRenderObject、动画状态或调试 Widget 树。
  • 链条超过三到四层且阅读负担大时,拆成有变量名的原生 Widget 树。
  • 团队 API 未覆盖的 Flutter 能力,直接使用官方 Widget,不要临时在页面复制扩展实现。

性能边界

链式方法会增加包装 Widget;单个静态页面通常无感,但大量列表项中堆叠装饰、裁剪、模糊与 Intrinsic 系列尺寸方法会产生布局或合成成本。列表项优先复用稳定 Widget,避免在 itemBuilder 中创建不必要的 IntrinsicWidth、大面积 BackdropFilter 或多层裁剪。

关联阅读