Flutter.源码分析 flutter/packages/flutter/lib/src/widgets/scroll_view.dart/BoxScrollView

简介: Flutter.源码分析 flutter/packages/flutter/lib/src/widgets/scroll_view.dart/BoxScrollView

Flutter.源码分析BoxScrollViewflutter/packages/flutter/lib/src/widgets/scroll_view.dart/BoxScrollView


1. 类注释部分

/// 使用单一子布局模型的 [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 {
  // ...
}

2. 构造方法部分

/// 创建一个使用单一子布局模型的 [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, // 内容超出滚动视图的可视区域时的剪裁行为
});

3. padding属性

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

4. buildSlivers方法部分

@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 的子类中实现,例如 ListViewGridView
  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。

5. buildChildLayout方法部分

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

参见《Flutter.源码分析.ScrollView》 buildChildLayout 部分,地址 https://blog.csdn.net/qq_28550263/article/details/134377965

6. 其它代码

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

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

目录
相关文章
|
21天前
|
Dart JavaScript 前端开发
Flutter 的 Widget 概述与常用 Widgets 与鸿蒙 Next 的对比
Flutter 是 Google 开发的开源 UI 框架,用于快速构建高性能的移动、Web 和桌面应用。Flutter 通过 Widget 构建 UI,每个 UI 元素都是 Widget,包括文本、按钮、图片等。Widget 不仅描述外观,还描述行为,是不可变的。常见的 Widget 包括结构型(Container、Column、Row)、呈现型(Text、Image)、交互型(ElevatedButton)和状态管理型(StatefulWidget)。Flutter 与鸿蒙 Next 在组件化架构、开发语言、布局系统、性能和跨平台支持方面各有优势
68 0
|
3月前
|
开发者 Windows
Flutter笔记:Widgets Easier组件库(9)使用弹窗
Flutter笔记:Widgets Easier组件库(9)使用弹窗
112 3
|
3月前
|
数据安全/隐私保护 Android开发 开发者
Flutter笔记:Widgets Easier组件库-使用隐私守卫
Flutter笔记:Widgets Easier组件库-使用隐私守卫
51 2
|
3月前
|
UED 开发者
Flutter笔记:Widgets Easier组件库(13)- 使用底部弹窗
Flutter笔记:Widgets Easier组件库(13)- 使用底部弹窗
62 2
|
3月前
|
开发者
Flutter笔记:Widgets Easier组件库(5)使用加减器
Flutter笔记:Widgets Easier组件库(5)使用加减器
88 2
|
3月前
|
开发者 容器
Flutter笔记:Widgets Easier组件库(4)使用按钮组
Flutter笔记:Widgets Easier组件库(4)使用按钮组
34 2
|
3月前
|
开发者
Flutter笔记:Widgets Easier组件库(11)- 使用提示吐丝(Tip Toasts)
Flutter笔记:Widgets Easier组件库(11)- 使用提示吐丝(Tip Toasts)
52 1
|
3月前
|
开发者
Flutter笔记:Widgets Easier组件库 - 使用标签(Tag)
Flutter笔记:Widgets Easier组件库 - 使用标签(Tag)
118 0
|
3月前
|
开发者
Flutter笔记:Widgets Easier组件库(12)使用消息吐丝(Notify Toasts)
Flutter笔记:Widgets Easier组件库(12)使用消息吐丝(Notify Toasts)
75 0
|
3月前
|
数据安全/隐私保护 UED 开发者
Flutter笔记:Widgets Easier组件库(10)快速处理承若型对话
Flutter笔记:Widgets Easier组件库(10)快速处理承若型对话
35 0
下一篇
无影云桌面