@@ -55,6 +55,13 @@ public override bool NeedsContainer
5555
5656 public override Size GetDesiredSize ( double widthConstraint , double heightConstraint )
5757 {
58+ // When the height constraint is infinite, the handler substitutes a finite value.
59+ // This flag tracks whether the substitute came from SizeThatFits (a content measurement,
60+ // not a real bound). If so, the cap at the bottom must be skipped — the base already
61+ // returns the correct size. When the substitute is Bounds.Height (a real frame bound),
62+ // the flag stays false and the cap applies to preserve scrollability.
63+ bool heightSubstitutedFromSizeThatFits = false ;
64+
5865 if ( double . IsInfinity ( widthConstraint ) || double . IsInfinity ( heightConstraint ) )
5966 {
6067 // If we drop an infinite value into base.GetDesiredSize for the Editor, we'll
@@ -72,31 +79,29 @@ public override Size GetDesiredSize(double widthConstraint, double heightConstra
7279 {
7380 var currentHeight = ( double ) PlatformView . Bounds . Height ;
7481
75- // NOTE: Bounds and ContentSize reflect the pre-rotation frame at this point.
76- // The check is intentionally based on the previous layout state to detect
77- // scrollable Editors that should not grow after cache invalidation (#35114).
78- // When content overflows the frame and auto-growth is off, cap the height
79- // to the current frame height to preserve scrollability after rotation (#35114).
80- // Skip when AllowAutoGrowth is set (AutoSize=TextChanges) — Editor should grow freely.
82+ // When content overflows the current frame and auto-growth is disabled,
83+ // use Bounds.Height as the constraint to preserve scrollability after rotation.
84+ // Editors with AutoSize=TextChanges (AllowAutoGrowth=true) are exempt.
8185 if ( ! PlatformView . AllowAutoGrowth
8286 && currentHeight > 0
8387 && PlatformView . ContentSize . Height > currentHeight )
8488 {
85- heightConstraint = currentHeight ;
89+ heightConstraint = currentHeight ; // real bound — cap will apply
8690 }
8791 else
8892 {
8993 heightConstraint = sizeThatFits . Height ;
94+ heightSubstitutedFromSizeThatFits = true ; // not a real bound — cap will be skipped
9095 }
9196 }
9297 }
9398
9499 var result = base . GetDesiredSize ( widthConstraint , heightConstraint ) ;
95100
96- // Cap applies even for finite constraints: UITextView.SizeThatFits (UIScrollView subclass)
97- // ignores the height argument and always returns full content height.
98- // Capping here ensures GetDesiredSize honours the caller's constraint .
99- if ( result . Height > heightConstraint )
101+ // Clamp the result to the constraint only when it represents a real upper bound.
102+ // UITextView (a UIScrollView subclass) ignores the height in SizeThatFits and always
103+ // returns full content height, so clamping is needed for caller- or frame-derived bounds .
104+ if ( ! heightSubstitutedFromSizeThatFits && result . Height > heightConstraint )
100105 {
101106 return new Size ( result . Width , heightConstraint ) ;
102107 }
0 commit comments