// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/rendering.dart'; import 'framework.dart'; import 'layout_builder.dart'; /// The signature of the [SliverLayoutBuilder] builder function. typedef SliverLayoutWidgetBuilder = Widget Function(BuildContext context, SliverConstraints constraints); /// Builds a sliver widget tree that can depend on its own [SliverConstraints]. /// /// Similar to the [LayoutBuilder] widget except its builder should return a sliver /// widget, and [SliverLayoutBuilder] is itself a sliver. The framework calls the /// [builder] function at layout time and provides the current [SliverConstraints]. /// The [SliverLayoutBuilder]'s final [SliverGeometry] will match the [SliverGeometry] /// of its child. /// /// {@macro flutter.widgets.ConstrainedLayoutBuilder} /// /// See also: /// /// * [LayoutBuilder], the non-sliver version of this widget. class SliverLayoutBuilder extends ConstrainedLayoutBuilder<SliverConstraints> { /// Creates a sliver widget that defers its building until layout. /// /// The [builder] argument must not be null. const SliverLayoutBuilder({ Key? key, required SliverLayoutWidgetBuilder builder, }) : super(key: key, builder: builder); /// Called at layout time to construct the widget tree. /// /// The builder must return a non-null sliver widget. @override SliverLayoutWidgetBuilder get builder => super.builder; @override RenderObject createRenderObject(BuildContext context) => _RenderSliverLayoutBuilder(); } class _RenderSliverLayoutBuilder extends RenderSliver with RenderObjectWithChildMixin<RenderSliver>, RenderConstrainedLayoutBuilder<SliverConstraints, RenderSliver> { @override double childMainAxisPosition(RenderObject child) { assert(child != null); assert(child == this.child); return 0; } @override void performLayout() { rebuildIfNecessary(); child?.layout(constraints, parentUsesSize: true); geometry = child?.geometry ?? SliverGeometry.zero; } @override void applyPaintTransform(RenderObject child, Matrix4 transform) { assert(child != null); assert(child == this.child); // child's offset is always (0, 0), transform.translate(0, 0) does not mutate the transform. } @override void paint(PaintingContext context, Offset offset) { // This renderObject does not introduce additional offset to child's position. if (child?.geometry?.visible == true) context.paintChild(child!, offset); } @override bool hitTestChildren(SliverHitTestResult result, {required double mainAxisPosition, required double crossAxisPosition}) { return child != null && child!.geometry!.hitTestExtent > 0 && child!.hitTest(result, mainAxisPosition: mainAxisPosition, crossAxisPosition: crossAxisPosition); } }