@@ -35,6 +35,13 @@ public abstract class MauiView : UIView, ICrossPlatformLayoutBacking, IVisualTre
3535 /// </summary>
3636 double _lastMeasureWidth = double . NaN ;
3737
38+ /// <summary>
39+ /// Cached measured cross-platform size from the last measure operation tight to <see cref="_lastMeasureWidth"/> and <see cref="_lastMeasureHeight"/>.
40+ /// Used to avoid redundant measure calls when constraints haven't changed.
41+ /// NaN indicates no previous measure has been performed.
42+ /// </summary>
43+ Size ? _lastMeasuredSize ;
44+
3845 /// <summary>
3946 /// Current safe area padding values (top, left, bottom, right) in device-independent units.
4047 /// These values represent the insets needed to avoid system UI elements like status bars,
@@ -348,15 +355,34 @@ SafeAreaPadding GetAdjustedSafeAreaInsets()
348355 /// <returns>True if the cached measure is still valid, false otherwise</returns>
349356 protected bool IsMeasureValid ( double widthConstraint , double heightConstraint )
350357 {
351- return ! HasFixedConstraints
352- && widthConstraint == _lastMeasureWidth
358+ return widthConstraint == _lastMeasureWidth
353359 && heightConstraint == _lastMeasureHeight ;
354360 }
355361
362+ /// <summary>
363+ /// Caches the measure constraints and the resulting measured size from the last measure operation.
364+ /// </summary>
365+ /// <param name="widthConstraint">The width constraint used.</param>
366+ /// <param name="heightConstraint">The height constraint used.</param>
367+ [ Obsolete ( "Use CacheMeasureConstraints(double widthConstraint, double heightConstraint, Size measuredSize) instead." ) ]
356368 protected void CacheMeasureConstraints ( double widthConstraint , double heightConstraint )
357369 {
358370 _lastMeasureWidth = widthConstraint ;
359371 _lastMeasureHeight = heightConstraint ;
372+ _lastMeasuredSize = null ;
373+ }
374+
375+ /// <summary>
376+ /// Caches the measure constraints and the resulting measured size from the last measure operation.
377+ /// </summary>
378+ /// <param name="widthConstraint">The width constraint used.</param>
379+ /// <param name="heightConstraint">The height constraint used.</param>
380+ /// <param name="measuredSize">The resulting measured cross-platform size.</param>
381+ protected void CacheMeasureConstraints ( double widthConstraint , double heightConstraint , Size measuredSize )
382+ {
383+ _lastMeasureWidth = widthConstraint ;
384+ _lastMeasureHeight = heightConstraint ;
385+ _lastMeasuredSize = measuredSize ;
360386 }
361387
362388 /// <summary>
@@ -366,7 +392,7 @@ protected void CacheMeasureConstraints(double widthConstraint, double heightCons
366392 /// <returns>True if the view has been measured, false otherwise</returns>
367393 bool HasBeenMeasured ( )
368394 {
369- return ! double . IsNaN ( _lastMeasureWidth ) && ! double . IsNaN ( _lastMeasureHeight ) ;
395+ return _lastMeasuredSize . HasValue ;
370396 }
371397
372398 /// <summary>
@@ -378,6 +404,7 @@ protected void InvalidateConstraintsCache()
378404 {
379405 _lastMeasureWidth = double . NaN ;
380406 _lastMeasureHeight = double . NaN ;
407+ _lastMeasuredSize = null ;
381408 }
382409
383410 public ICrossPlatformLayout ? CrossPlatformLayout
@@ -446,9 +473,14 @@ public override CGSize SizeThatFits(CGSize size)
446473 var widthConstraint = ( double ) size . Width ;
447474 var heightConstraint = ( double ) size . Height ;
448475
449- var crossPlatformSize = CrossPlatformMeasure ( widthConstraint , heightConstraint ) ;
476+ if ( IsMeasureValid ( widthConstraint , heightConstraint ) && _lastMeasuredSize is { } crossPlatformSize )
477+ {
478+ return crossPlatformSize . ToCGSize ( ) ;
479+ }
480+
481+ crossPlatformSize = CrossPlatformMeasure ( widthConstraint , heightConstraint ) ;
450482
451- CacheMeasureConstraints ( widthConstraint , heightConstraint ) ;
483+ CacheMeasureConstraints ( widthConstraint , heightConstraint , crossPlatformSize ) ;
452484
453485 return crossPlatformSize . ToCGSize ( ) ;
454486 }
@@ -499,11 +531,16 @@ public override void LayoutSubviews()
499531 // imposed by the parent (i.e. scroll view) with the current bounds, except when our bounds are fixed by constraints.
500532 // But we _do_ need LayoutSubviews to make a measurement pass if the parent is something else (for example,
501533 // the window); there's no guarantee that SizeThatFits has been called in that case.
502- if ( ! IsMeasureValid ( widthConstraint , heightConstraint ) && ! this . IsFinalMeasureHandledBySuperView ( ) ||
503- ! HasBeenMeasured ( ) && HasFixedConstraints )
534+ var needsMeasure = HasFixedConstraints switch
535+ {
536+ true => ! HasBeenMeasured ( ) || ! this . IsFinalMeasureHandledBySuperView ( ) ,
537+ false => ! IsMeasureValid ( widthConstraint , heightConstraint ) && ! this . IsFinalMeasureHandledBySuperView ( )
538+ } ;
539+
540+ if ( needsMeasure )
504541 {
505- CrossPlatformMeasure ( widthConstraint , heightConstraint ) ;
506- CacheMeasureConstraints ( widthConstraint , heightConstraint ) ;
542+ var crossPlatformSize = CrossPlatformMeasure ( widthConstraint , heightConstraint ) ;
543+ CacheMeasureConstraints ( widthConstraint , heightConstraint , crossPlatformSize ) ;
507544 }
508545
509546 CrossPlatformArrange ( bounds ) ;
0 commit comments