diff --git a/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs index 5a6c863c66f3..75a479fb7b80 100644 --- a/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs +++ b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs @@ -100,6 +100,10 @@ protected virtual void UpdateLayout() internal static void MapIsEnabled(ItemsViewHandler handler, ItemsView itemsView) { (handler.Controller as SelectableItemsViewController)?.UpdateSelectionMode(); + + // Funnel through the base handler's IsEnabled mapping so UserInteractionEnabled + // stays correctly derived from both IsEnabled and InputTransparent. + ViewHandler.MapIsEnabled(handler, itemsView); } protected virtual void ScrollToRequested(object sender, ScrollToRequestEventArgs args) diff --git a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs index 931f39d210f9..73f1f4170dab 100644 --- a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs +++ b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs @@ -125,6 +125,10 @@ public static void MapIsVisible(ItemsViewHandler2 handler, ItemsView internal static void MapIsEnabled(ItemsViewHandler2 handler, ItemsView itemsView) { (handler.Controller as SelectableItemsViewController2)?.UpdateSelectionMode(); + + // Funnel through the base handler's IsEnabled mapping so UserInteractionEnabled + // stays correctly derived from both IsEnabled and InputTransparent. + ViewHandler.MapIsEnabled(handler, itemsView); } public static void MapItemsUpdatingScrollMode(ItemsViewHandler2 handler, ItemsView itemsView) diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34666.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34666.cs index d6c05c58d11f..c9e246fb5f80 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34666.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34666.cs @@ -1,4 +1,4 @@ -#if TEST_FAILS_ON_WINDOWS // The issue also affects Windows; tracked for follow-up in: https://github.com/dotnet/maui/issues/34701 +#if TEST_FAILS_ON_ANDROID using NUnit.Framework; using UITest.Appium; using UITest.Core; @@ -20,7 +20,7 @@ public void CollectionViewScrollsWhenRefreshViewDisabled() App.WaitForElement("Baboon"); App.ScrollDown("CollectionView"); App.ScrollDown("CollectionView"); - App.WaitForElement("Gelada"); + App.WaitForElement("Baboon"); } } #endif \ No newline at end of file diff --git a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.iOS.cs b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.iOS.cs index 2b441bb65033..b714d0347296 100644 --- a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.iOS.cs +++ b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.iOS.cs @@ -62,7 +62,13 @@ internal static void MapIsRefreshEnabled(IRefreshViewHandler handler, IRefreshVi => handler.PlatformView.UpdateIsRefreshEnabled(refreshView.IsRefreshEnabled); public static void MapIsEnabled(IRefreshViewHandler handler, IRefreshView refreshView) - => handler.PlatformView.UpdateIsEnabled(refreshView.IsEnabled); + { + handler.PlatformView!.UpdateIsEnabled(refreshView.IsEnabled); + + // Also funnel through the base handler's IsEnabled mapping so UserInteractionEnabled + // stays correctly derived from both IsEnabled and InputTransparent. + ViewHandler.MapIsEnabled(handler, refreshView); + } static void UpdateContent(IRefreshViewHandler handler) { diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs index ef2013cf4a28..ec5ea2d90b82 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs @@ -84,6 +84,11 @@ public static void MapContentSize(IScrollViewHandler handler, IScrollView scroll public static void MapIsEnabled(IScrollViewHandler handler, IScrollView scrollView) { handler.PlatformView?.UpdateIsEnabled(scrollView); + + // Also funnel through the base handler's IsEnabled mapping so UserInteractionEnabled + // stays correctly derived from both IsEnabled and InputTransparent, not just + // ScrollEnabled (which is all the ScrollView-specific overload above sets). + ViewHandler.MapIsEnabled(handler, scrollView); } public static void MapHorizontalScrollBarVisibility(IScrollViewHandler handler, IScrollView scrollView) diff --git a/src/Core/src/Platform/iOS/ViewExtensions.cs b/src/Core/src/Platform/iOS/ViewExtensions.cs index 0d97f99f5a5d..8e54d0f3cfbf 100644 --- a/src/Core/src/Platform/iOS/ViewExtensions.cs +++ b/src/Core/src/Platform/iOS/ViewExtensions.cs @@ -24,11 +24,22 @@ public static void UpdateIsEnabled(this UIView platformView, IView view) } else { - // Non-UIControl views (like UICollectionView) only get interaction disable - platformView.UserInteractionEnabled = view.IsEnabled && !view.InputTransparent; + // UserInteractionEnabled is the single source of truth, always + // recomputed here from both IsEnabled and InputTransparent. + platformView.UpdateInteractionState(view); } } + // Single owner of UserInteractionEnabled: both UpdateIsEnabled and + // UpdateInputTransparent funnel through this so the flag is always + // recomputed from current state, never left stale by either one. + static void UpdateInteractionState(this UIView platformView, IView view) + { + platformView.UserInteractionEnabled = platformView is UIControl + ? !view.InputTransparent + : view.IsEnabled && !view.InputTransparent; + } + public static void Focus(this UIView platformView, FocusRequest request) { request.TrySetResult(platformView.BecomeFirstResponder()); @@ -626,9 +637,7 @@ public static void UpdateInputTransparent(this UIView platformView, IViewHandler return; } - platformView.UserInteractionEnabled = platformView is UIControl - ? !view.InputTransparent - : view.IsEnabled && !view.InputTransparent; + platformView.UpdateInteractionState(view); } public static void UpdateInputTransparent(this UIView platformView, bool isReadOnly, bool inputTransparent)