1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:flutter/rendering.dart'; |
6 | |
7 | import 'framework.dart'; |
8 | import 'layout_builder.dart'; |
9 | |
10 | /// The signature of the [SliverLayoutBuilder] builder function. |
11 | typedef SliverLayoutWidgetBuilder = Widget Function(BuildContext context, SliverConstraints constraints); |
12 | |
13 | /// Builds a sliver widget tree that can depend on its own [SliverConstraints]. |
14 | /// |
15 | /// Similar to the [LayoutBuilder] widget except its builder should return a sliver |
16 | /// widget, and [SliverLayoutBuilder] is itself a sliver. The framework calls the |
17 | /// [builder] function at layout time and provides the current [SliverConstraints]. |
18 | /// The [SliverLayoutBuilder]'s final [SliverGeometry] will match the [SliverGeometry] |
19 | /// of its child. |
20 | /// |
21 | /// {@macro flutter.widgets.ConstrainedLayoutBuilder} |
22 | /// |
23 | /// See also: |
24 | /// |
25 | /// * [LayoutBuilder], the non-sliver version of this widget. |
26 | class SliverLayoutBuilder extends ConstrainedLayoutBuilder<SliverConstraints> { |
27 | /// Creates a sliver widget that defers its building until layout. |
28 | const SliverLayoutBuilder({ |
29 | super.key, |
30 | required super.builder, |
31 | }); |
32 | |
33 | @override |
34 | RenderObject createRenderObject(BuildContext context) => _RenderSliverLayoutBuilder(); |
35 | } |
36 | |
37 | class _RenderSliverLayoutBuilder extends RenderSliver with RenderObjectWithChildMixin<RenderSliver>, RenderConstrainedLayoutBuilder<SliverConstraints, RenderSliver> { |
38 | @override |
39 | double childMainAxisPosition(RenderObject child) { |
40 | assert(child == this.child); |
41 | return 0; |
42 | } |
43 | |
44 | @override |
45 | void performLayout() { |
46 | rebuildIfNecessary(); |
47 | child?.layout(constraints, parentUsesSize: true); |
48 | geometry = child?.geometry ?? SliverGeometry.zero; |
49 | } |
50 | |
51 | @override |
52 | void applyPaintTransform(RenderObject child, Matrix4 transform) { |
53 | assert(child == this.child); |
54 | // child's offset is always (0, 0), transform.translate(0, 0) does not mutate the transform. |
55 | } |
56 | |
57 | @override |
58 | void paint(PaintingContext context, Offset offset) { |
59 | // This renderObject does not introduce additional offset to child's position. |
60 | if (child?.geometry?.visible ?? false) { |
61 | context.paintChild(child!, offset); |
62 | } |
63 | } |
64 | |
65 | @override |
66 | bool hitTestChildren(SliverHitTestResult result, {required double mainAxisPosition, required double crossAxisPosition}) { |
67 | return child != null |
68 | && child!.geometry!.hitTestExtent > 0 |
69 | && child!.hitTest(result, mainAxisPosition: mainAxisPosition, crossAxisPosition: crossAxisPosition); |
70 | } |
71 | } |
72 | |