Flutter.源码分析flutter/packages/flutter/lib/src/wid...BoxScrollView

举报
jcLee95 发表于 2023/11/13 20:50:20 2023/11/13
【摘要】 本文提供 Flutter 框架中 BoxScrollView 类源码注释的中文翻译以及必要的分析解说。
Flutter.源码分析
BoxScrollView
flutter/packages/flutter/lib/src/widgets/scroll_view.dart/BoxScrollView

本文提供 Flutter 框架中 BoxScrollView 类源码注释的中文翻译以及必要的分析解说。




/// 使用单一子布局模型的 [ScrollView]。
///
/// {@template flutter.widgets.BoxScroll.scrollBehaviour}
/// [ScrollView] 通常会装饰有 [Scrollbar] 和过度滚动指示器,
/// 这些都由继承的 [ScrollBehavior] 管理。在 ScrollView 上方放置一个
/// [ScrollConfiguration] 可以修改该 ScrollView 的这些行为,
/// 或者可以通过向 [MaterialApp.scrollBehavior] 或 [CupertinoApp.scrollBehavior]
/// 提供 ScrollBehavior 来在应用范围内管理这些行为。
/// {@endtemplate}
///
/// 另请参阅:
///
///  * [ListView],这是一个使用线性布局模型的 [BoxScrollView]。
///  * [GridView],这是一个使用二维布局模型的 [BoxScrollView]。
///  * [CustomScrollView],它可以将多个子布局模型组合成一个单一的滚动视图。
abstract class BoxScrollView extends ScrollView {
  // ...
}

/// 创建一个使用单一子布局模型的 [ScrollView]。
///
/// 如果 [primary] 参数为 true,则 [controller] 必须为 null。
const BoxScrollView({
  super.key, // 用于控制是否应替换现有的同类型的 widget
  super.scrollDirection, // 滚动方向
  super.reverse, // 是否反转滚动方向
  super.controller, // 控制滚动位置的对象
  super.primary, // 是否使用主滚动控制器
  super.physics, // 如何应对用户停止拖动后的滚动
  super.shrinkWrap, // 是否根据子项的总长度来设置滚动视图的长度
  this.padding, // 插入子项的空间量
  super.cacheExtent, // 预缓存超出滚动视图的区域的长度
  super.semanticChildCount, // 用于语义通知的子项数量
  super.dragStartBehavior, // 拖动开始行为
  super.keyboardDismissBehavior, // 键盘消失行为
  super.restorationId, // 用于保存滚动位置的 ID
  super.clipBehavior, // 内容超出滚动视图的可视区域时的剪裁行为
});

/// 插入子项的空间量。
final EdgeInsetsGeometry? padding;

@override
List<Widget> buildSlivers(BuildContext context) {
  Widget sliver = buildChildLayout(context);
  EdgeInsetsGeometry? effectivePadding = padding;
  if (padding == null) {
    final MediaQueryData? mediaQuery = MediaQuery.maybeOf(context);
    if (mediaQuery != null) {
      // 使用 MediaQuery 的 padding 自动填充 sliver。
      final EdgeInsets mediaQueryHorizontalPadding =
          mediaQuery.padding.copyWith(top: 0.0, bottom: 0.0);
      final EdgeInsets mediaQueryVerticalPadding =
          mediaQuery.padding.copyWith(left: 0.0, right: 0.0);
      // 使用 SliverPadding 消耗主轴 padding。
      effectivePadding = scrollDirection == Axis.vertical
          ? mediaQueryVerticalPadding
          : mediaQueryHorizontalPadding;
      // 留下交叉轴 padding。
      sliver = MediaQuery(
        data: mediaQuery.copyWith(
          padding: scrollDirection == Axis.vertical
              ? mediaQueryHorizontalPadding
              : mediaQueryVerticalPadding,
        ),
        child: sliver,
      );
    }
  }

  if (effectivePadding != null) {
    sliver = SliverPadding(padding: effectivePadding, sliver: sliver);
  }
  return <Widget>[ sliver ];
}

可以看出 buildSlivers 方法主要负责构建滚动视图的子组件,并处理可能存在的 padding。

  1. 首先,它调用 buildChildLayout(context) 方法来构建滚动视图的子组件,这个方法在 BoxScrollView 的子类中实现,例如 ListView  GridView

  2. 然后,它检查是否已经设置了 padding。如果没有设置 padding,它会尝试从 MediaQuery 获取 padding。如果 MediaQuery 存在,它会根据滚动方向分别获取垂直和水平的 padding。

  3. 如果 MediaQuery 存在,它会创建一个新的 MediaQuery 组件,将 MediaQuery 的 padding 设置为根据滚动方向得到的 padding,并将原始的子组件作为新的 MediaQuery 组件的子组件。

  4. 如果 effectivePadding(可能是从 MediaQuery 获取的 padding 或者是直接设置的 padding)存在,它会创建一个 SliverPadding 组件,将 effectivePadding 设置为 SliverPadding 的 padding,并将原始的子组件(可能已经被包装在 MediaQuery 组件中)作为 SliverPadding 的子组件。

  5. 最后,它返回一个只包含一个组件(可能是 SliverPadding 或 MediaQuery 或原始的子组件)的列表。

这个实现确保了滚动视图的子组件可以正确地处理 padding,并且如果存在 MediaQuery,还可以自动适应 MediaQuery 的 padding。


/// 子类应重写此方法以构建布局模型。
@protected
Widget buildChildLayout(BuildContext context);

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
  super.debugFillProperties(properties);
  properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
}

这里的 debugFillProperties 方法是用于支持 Flutter 的诊断工具的。当开发者要求查看 BoxScrollView 的属性时,这个方法会被调用。在这个方法中,BoxScrollView 将自己的 padding 属性添加到了诊断属性中。这样,开发者就可以看到 padding 属性的值,以及它是否被设置了默认值。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。