diff --git a/src/Core/src/Platform/iOS/ActivityIndicatorExtensions.cs b/src/Core/src/Platform/iOS/ActivityIndicatorExtensions.cs index b812e9ee19f2..e02529b88c55 100644 --- a/src/Core/src/Platform/iOS/ActivityIndicatorExtensions.cs +++ b/src/Core/src/Platform/iOS/ActivityIndicatorExtensions.cs @@ -7,7 +7,7 @@ public static class ActivityIndicatorExtensions public static void UpdateIsRunning(this UIActivityIndicatorView activityIndicatorView, IActivityIndicator activityIndicator) { // Since Visibility and IsRunning are dependent on each other, we handle Visibility explicitly. - // Only show and animate if both IsRunning AND Visibility == Visible + // Only show and animate if both IsRunning AND Visibility == Visible. if (activityIndicator.IsRunning && activityIndicator.Visibility == Visibility.Visible) { activityIndicatorView.Inflate(); @@ -18,19 +18,20 @@ public static void UpdateIsRunning(this UIActivityIndicatorView activityIndicato { if (activityIndicatorView.IsAnimating) activityIndicatorView.StopAnimating(); - - // Collapsed requires layout constraint (CollapseConstraint) to zero out size; - // Hidden only sets Hidden = true (preserving layout space). - if (activityIndicator.Visibility == Visibility.Collapsed) - { - activityIndicatorView.Hidden = true; - activityIndicatorView.Collapse(); - } - else - { - activityIndicatorView.Inflate(); - activityIndicatorView.Hidden = activityIndicator.Visibility != Visibility.Visible; - } + + // Collapsed requires layout constraint (CollapseConstraint) to zero out size; + // Hidden only sets Hidden = true (preserving layout space). + if (activityIndicator.Visibility == Visibility.Collapsed) + { + activityIndicatorView.Hidden = true; + activityIndicatorView.Collapse(); + } + else + { + activityIndicatorView.Inflate(); + // Always hide when not (IsRunning && Visible) — avoids frozen static frame. + activityIndicatorView.Hidden = true; + } } } diff --git a/src/Core/tests/DeviceTests/Handlers/ActivityIndicator/ActivityIndicatorHandlerTests.iOS.cs b/src/Core/tests/DeviceTests/Handlers/ActivityIndicator/ActivityIndicatorHandlerTests.iOS.cs index 0a9f1429e5a6..95e6784a5849 100644 --- a/src/Core/tests/DeviceTests/Handlers/ActivityIndicator/ActivityIndicatorHandlerTests.iOS.cs +++ b/src/Core/tests/DeviceTests/Handlers/ActivityIndicator/ActivityIndicatorHandlerTests.iOS.cs @@ -1,9 +1,11 @@ using System; using System.Threading.Tasks; +using Microsoft.Maui.DeviceTests.Stubs; using Microsoft.Maui.Graphics; using Microsoft.Maui.Handlers; using ObjCRuntime; using UIKit; +using Xunit; namespace Microsoft.Maui.DeviceTests { @@ -14,5 +16,34 @@ UIActivityIndicatorView GetNativeActivityIndicator(ActivityIndicatorHandler acti bool GetNativeIsRunning(ActivityIndicatorHandler activityIndicatorHandler) => GetNativeActivityIndicator(activityIndicatorHandler).IsAnimating; + + [Fact(DisplayName = "Setting IsRunning False While Visible Should Hide Native View")] + public async Task SettingIsRunningFalseWhileVisibleShouldHideNativeView() + { + var activityIndicator = new ActivityIndicatorStub + { + IsRunning = true, + Visibility = Visibility.Visible + }; + + bool isAnimating = true; + bool isHidden = false; + + await InvokeOnMainThreadAsync(() => + { + var handler = CreateHandler(activityIndicator); + + activityIndicator.IsRunning = false; + handler.UpdateValue(nameof(IActivityIndicator.IsRunning)); + + var nativeView = GetNativeActivityIndicator(handler); + isAnimating = nativeView.IsAnimating; + isHidden = nativeView.Hidden; + }); + + Assert.False(isAnimating, "ActivityIndicator should stop animating when IsRunning is false."); + Assert.True(isHidden, "ActivityIndicator should be hidden when IsRunning is false."); + } + } } \ No newline at end of file