@@ -229,6 +229,29 @@ class StackParentData extends ContainerBoxParentData<RenderBox> {
229229 /// children in the stack.
230230 bool get isPositioned => top != null || right != null || bottom != null || left != null || width != null || height != null ;
231231
232+ /// Computes the [BoxConstraints] the stack layout algorithm would give to
233+ /// this child, given the [Size] of the stack.
234+ ///
235+ /// This method should only be called when [isPositioned] is true for the child.
236+ BoxConstraints positionedChildConstraints (Size stackSize) {
237+ assert (isPositioned);
238+ final double ? width = switch ((left, right)) {
239+ (final double left? , final double right? ) => stackSize.width - right - left,
240+ (_, _) => this .width,
241+ };
242+
243+ final double ? height = switch ((top, bottom)) {
244+ (final double top? , final double bottom? ) => stackSize.height - bottom - top,
245+ (_, _) => this .height,
246+ };
247+ assert (height == null || ! height.isNaN);
248+ assert (width == null || ! width.isNaN);
249+ return BoxConstraints .tightFor (
250+ width: width == null ? null : math.max (0.0 , width),
251+ height: height == null ? null : math.max (0.0 , height),
252+ );
253+ }
254+
232255 @override
233256 String toString () {
234257 final List <String > values = < String > [
@@ -354,17 +377,11 @@ class RenderStack extends RenderBox
354377 }
355378 }
356379
357- Alignment ? _resolvedAlignment;
358-
359- void _resolve () {
360- if (_resolvedAlignment != null ) {
361- return ;
362- }
363- _resolvedAlignment = alignment.resolve (textDirection);
364- }
380+ Alignment get _resolvedAlignment => _resolvedAlignmentCache ?? = alignment.resolve (textDirection);
381+ Alignment ? _resolvedAlignmentCache;
365382
366383 void _markNeedResolution () {
367- _resolvedAlignment = null ;
384+ _resolvedAlignmentCache = null ;
368385 markNeedsLayout ();
369386 }
370387
@@ -489,53 +506,59 @@ class RenderStack extends RenderBox
489506 static bool layoutPositionedChild (RenderBox child, StackParentData childParentData, Size size, Alignment alignment) {
490507 assert (childParentData.isPositioned);
491508 assert (child.parentData == childParentData);
509+ final BoxConstraints childConstraints = childParentData.positionedChildConstraints (size);
510+ child.layout (childConstraints, parentUsesSize: true );
492511
493- bool hasVisualOverflow = false ;
494- BoxConstraints childConstraints = const BoxConstraints ();
495-
496- if (childParentData.left != null && childParentData.right != null ) {
497- childConstraints = childConstraints.tighten (width: size.width - childParentData.right! - childParentData.left! );
498- } else if (childParentData.width != null ) {
499- childConstraints = childConstraints.tighten (width: childParentData.width);
500- }
512+ final double x = switch (childParentData) {
513+ StackParentData (: final double left? ) => left,
514+ StackParentData (: final double right? ) => size.width - right - child.size.width,
515+ StackParentData () => alignment.alongOffset (size - child.size as Offset ).dx,
516+ };
501517
502- if (childParentData.top != null && childParentData.bottom != null ) {
503- childConstraints = childConstraints. tighten (height : size.height - childParentData.bottom ! - childParentData. top! );
504- } else if (childParentData .height != null ) {
505- childConstraints = childConstraints. tighten (height : childParentData.height);
506- }
518+ final double y = switch ( childParentData) {
519+ StackParentData ( : final double top ? ) => top,
520+ StackParentData ( : final double bottom ? ) => size .height - bottom - child.size.height,
521+ StackParentData () => alignment. alongOffset (size - child.size as Offset ).dy,
522+ };
507523
508- child.layout (childConstraints, parentUsesSize: true );
524+ childParentData.offset = Offset (x, y);
525+ return x < 0.0 || x + child.size.width > size.width
526+ || y < 0.0 || y + child.size.height > size.height;
527+ }
509528
510- final double x;
511- if (childParentData.left != null ) {
512- x = childParentData.left! ;
513- } else if (childParentData.right != null ) {
514- x = size.width - childParentData.right! - child.size.width;
515- } else {
516- x = alignment.alongOffset (size - child.size as Offset ).dx;
529+ static double ? _baselineForChild (RenderBox child, Size stackSize, BoxConstraints nonPositionedChildConstraints, Alignment alignment, TextBaseline baseline) {
530+ final StackParentData childParentData = child.parentData! as StackParentData ;
531+ final BoxConstraints childConstraints = childParentData.isPositioned
532+ ? childParentData.positionedChildConstraints (stackSize)
533+ : nonPositionedChildConstraints;
534+ final double ? baselineOffset = child.getDryBaseline (childConstraints, baseline);
535+ if (baselineOffset == null ) {
536+ return null ;
517537 }
538+ final double y = switch (childParentData) {
539+ StackParentData (: final double top? ) => top,
540+ StackParentData (: final double bottom? ) => stackSize.height - bottom - child.getDryLayout (childConstraints).height,
541+ StackParentData () => alignment.alongOffset (stackSize - child.getDryLayout (childConstraints) as Offset ).dy,
542+ };
543+ return baselineOffset + y;
544+ }
518545
519- if (x < 0.0 || x + child.size.width > size.width) {
520- hasVisualOverflow = true ;
521- }
546+ @override
547+ double ? computeDryBaseline (BoxConstraints constraints, TextBaseline baseline) {
548+ final BoxConstraints nonPositionedChildConstraints = switch (fit) {
549+ StackFit .loose => constraints.loosen (),
550+ StackFit .expand => BoxConstraints .tight (constraints.biggest),
551+ StackFit .passthrough => constraints,
552+ };
522553
523- final double y;
524- if (childParentData.top != null ) {
525- y = childParentData.top! ;
526- } else if (childParentData.bottom != null ) {
527- y = size.height - childParentData.bottom! - child.size.height;
528- } else {
529- y = alignment.alongOffset (size - child.size as Offset ).dy;
530- }
554+ final Alignment alignment = _resolvedAlignment;
555+ final Size size = getDryLayout (constraints);
531556
532- if (y < 0.0 || y + child.size.height > size.height) {
533- hasVisualOverflow = true ;
557+ BaselineOffset baselineOffset = BaselineOffset .noBaseline;
558+ for (RenderBox ? child = firstChild; child != null ; child = childAfter (child)) {
559+ baselineOffset = baselineOffset.minOf (BaselineOffset (_baselineForChild (child, size, nonPositionedChildConstraints, alignment, baseline)));
534560 }
535-
536- childParentData.offset = Offset (x, y);
537-
538- return hasVisualOverflow;
561+ return baselineOffset.offset;
539562 }
540563
541564 @override
@@ -548,8 +571,6 @@ class RenderStack extends RenderBox
548571 }
549572
550573 Size _computeSize ({required BoxConstraints constraints, required ChildLayouter layoutChild}) {
551- _resolve ();
552- assert (_resolvedAlignment != null );
553574 bool hasNonPositionedChildren = false ;
554575 if (childCount == 0 ) {
555576 return (constraints.biggest.isFinite) ? constraints.biggest : constraints.smallest;
@@ -603,15 +624,15 @@ class RenderStack extends RenderBox
603624 layoutChild: ChildLayoutHelper .layoutChild,
604625 );
605626
606- assert (_resolvedAlignment != null ) ;
627+ final Alignment resolvedAlignment = _resolvedAlignment ;
607628 RenderBox ? child = firstChild;
608629 while (child != null ) {
609630 final StackParentData childParentData = child.parentData! as StackParentData ;
610631
611632 if (! childParentData.isPositioned) {
612- childParentData.offset = _resolvedAlignment ! .alongOffset (size - child.size as Offset );
633+ childParentData.offset = resolvedAlignment .alongOffset (size - child.size as Offset );
613634 } else {
614- _hasVisualOverflow = layoutPositionedChild (child, childParentData, size, _resolvedAlignment ! ) || _hasVisualOverflow;
635+ _hasVisualOverflow = layoutPositionedChild (child, childParentData, size, resolvedAlignment ) || _hasVisualOverflow;
615636 }
616637
617638 assert (child.parentData == childParentData);
@@ -740,6 +761,25 @@ class RenderIndexedStack extends RenderStack {
740761 return offset.offset;
741762 }
742763
764+ @override
765+ double ? computeDryBaseline (BoxConstraints constraints, TextBaseline baseline) {
766+ final RenderBox ? displayedChild = _childAtIndex ();
767+ if (displayedChild == null ) {
768+ return null ;
769+ }
770+ final BoxConstraints nonPositionedChildConstraints = switch (fit) {
771+ StackFit .loose => constraints.loosen (),
772+ StackFit .expand => BoxConstraints .tight (constraints.biggest),
773+ StackFit .passthrough => constraints,
774+ };
775+
776+ final Alignment alignment = _resolvedAlignment;
777+ final Size size = getDryLayout (constraints);
778+
779+ return RenderStack ._baselineForChild (displayedChild, size, nonPositionedChildConstraints, alignment, baseline);
780+ }
781+
782+
743783 @override
744784 bool hitTestChildren (BoxHitTestResult result, { required Offset position }) {
745785 final RenderBox ? displayedChild = _childAtIndex ();
0 commit comments