Skip to content

Widget 链式扩展 ​

FlutterKit 在 lib/core/design_system/extensions/widget/ 为 Flutter Widget、List<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.dart 等toRow、toColumnStretch、toStack、toWrapRow、Column、Stack、Wrap
尺寸与约束size_extension.dartwidth、height、size、tight、constrained、aspectRatioSizedBox、ConstrainedBox、AspectRatio
对齐与布局layout_extension.dartcenter、alignment、expanded、flexible、positioned、safeAreaCenter、Align、Flex、SafeArea
间距padding_extension.dartpad、padAll、padSymmetric、padHorizontal、padVerticalPadding
装饰decoration_extension.dartbackgroundColor、backgroundGradient、border、boxShadow、elevationDecoratedBox、Material
裁剪clip_extension.dartclipRRect、clipRadius、clipCircle、clipPathClipRRect、ClipOval、ClipPath
滚动scroll_extension.dartscrollable、verticalScroll、horizontalScroll、bouncingScrollSingleChildScrollView
手势gesture_extension.dartonTap、onLongPress、gestures、onScaleGestureDetector
列表与网格list_view_extension.dart、grid_view_extension.darttoListView、toListViewSeparated、toGridViewListView、GridView
文本text_extension.dart、text_span_extension.dartbold、fontSize、textColor、textStyleText.copyWith
变换与效果transform_extension.dart、effect_extension.dartrotate、scale、translate、opacity、blur、rippleTransform、Opacity、ImageFiltered、InkWell
语义与工具utility_extension.dart、icon_extension.dart、keep_alive_extension.dartvisibility、semantics、图标样式、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。
  • 需要精确管理 Key、RenderObject、动画状态或调试 Widget 树。
  • 链条超过三到四层且阅读负担大时,拆成有变量名的原生 Widget 树。
  • 团队 API 未覆盖的 Flutter 能力,直接使用官方 Widget,不要临时在页面复制扩展实现。

性能边界 ​

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

关联阅读 ​