Flutter.源码分析 BoxScrollView flutter/packages/flutter/lib/src/widgets/scroll_view.dart/BoxScrollView
李俊才 的个人博客:blog.csdn.net/qq_28550263
本文地址 :blog.csdn.net/qq_28550263...
本文提供 Flutter 框架中 BoxScrollView 类源码注释的中文翻译以及必要的分析解说。
目 录
1. 类注释部分
scala
/// 使用单一子布局模型的 [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. 构造方法部分
kotlin
/// 创建一个使用单一子布局模型的 [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属性
arduino
/// 插入子项的空间量。
final EdgeInsetsGeometry? padding;
4. buildSlivers方法部分
ini
@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。
- 首先,它调用
buildChildLayout
(context) 方法来构建滚动视图的子组件,这个方法在 BoxScrollView 的子类中实现,例如 ListView 或 GridView。 - 然后,它检查是否已经设置了 padding。如果没有设置 padding,它会尝试从 MediaQuery 获取 padding。如果 MediaQuery 存在,它会根据滚动方向分别获取垂直和水平的 padding。
- 如果 MediaQuery 存在,它会创建一个新的 MediaQuery 组件,将 MediaQuery 的 padding 设置为根据滚动方向得到的 padding,并将原始的子组件作为新的 MediaQuery 组件的子组件。
- 如果
effectivePadding
(可能是从 MediaQuery 获取的padding
或者是直接设置的padding
)存在,它会创建一个 SliverPadding 组件,将 effectivePadding 设置为 SliverPadding 的 padding,并将原始的子组件(可能已经被包装在 MediaQuery 组件中)作为 SliverPadding 的子组件。 - 最后,它返回一个只包含一个组件(可能是 SliverPadding 或 MediaQuery 或原始的子组件)的列表。
这个实现确保了滚动视图的子组件可以正确地处理 padding,并且如果存在 MediaQuery,还可以自动适应 MediaQuery 的 padding。
5. buildChildLayout方法部分
less
/// 子类应重写此方法以构建布局模型。
@protected
Widget buildChildLayout(BuildContext context);
参见《Flutter.源码分析.ScrollView》 buildChildLayout 部分,地址 blog.csdn.net/qq_28550263...
6. 其它代码
typescript
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
}
这里的 debugFillProperties 方法是用于支持 Flutter 的诊断工具的。当开发者要求查看 BoxScrollView 的属性时,这个方法会被调用。在这个方法中,BoxScrollView 将自己的 padding 属性添加到了诊断属性中。这样,开发者就可以看到 padding 属性的值,以及它是否被设置了默认值。