From 8840be963901ede8594b84baf69fd5de2a828d21 Mon Sep 17 00:00:00 2001 From: Jakub Florkowski Date: Mon, 21 Oct 2024 13:30:11 +0200 Subject: [PATCH 1/3] [Android] Fixed RefreshView in a grid --- .../TestCases.HostApp/Issues/Issue25368.xaml | 27 +++++++++++++++++++ .../Issues/Issue25368.xaml.cs | 12 +++++++++ .../Tests/Issues/Issue25368.cs | 26 ++++++++++++++++++ .../RefreshView/RefreshViewHandler.Android.cs | 24 +++++++++++++++++ .../net-android/PublicAPI.Unshipped.txt | 1 + 5 files changed, 90 insertions(+) create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue25368.xaml create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue25368.xaml.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25368.cs diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue25368.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue25368.xaml new file mode 100644 index 000000000000..a2d92003a272 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue25368.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue25368.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue25368.xaml.cs new file mode 100644 index 000000000000..4dc5a3259f81 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue25368.xaml.cs @@ -0,0 +1,12 @@ +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.Github, 25368, "Android RefreshView in a grid can break the grid layout", PlatformAffected.Android)] + public partial class Issue25368 : ContentPage + { + public Issue25368() + { + InitializeComponent(); + cv.ItemsSource = Enumerable.Range(1, 100); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25368.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25368.cs new file mode 100644 index 000000000000..06c14050cdf8 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25368.cs @@ -0,0 +1,26 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues +{ + public class Issue25368 : _IssuesUITest + { + public Issue25368(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "Android RefreshView in a grid can break the grid layout"; + + [Test] + [Category(UITestCategories.RefreshView)] + public void Issue2775Test() + { + App.WaitForElement("1"); + App.ScrollDown("CollectionView", ScrollStrategy.Gesture, swipePercentage: 0.9); + App.ScrollDown("CollectionView", ScrollStrategy.Gesture, swipePercentage: 0.9); + App.ScrollDown("CollectionView", ScrollStrategy.Gesture, swipePercentage: 0.9); + App.WaitForElement("100"); + } + } +} diff --git a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs index 0f5e0f6c6262..f69b80e74961 100644 --- a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs +++ b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs @@ -28,6 +28,30 @@ protected override void DisconnectHandler(MauiSwipeRefreshLayout platformView) base.DisconnectHandler(platformView); } + public override Size GetDesiredSize(double widthConstraint, double heightConstraint) + { + var Context = MauiContext?.Context; + var platformView = PlatformView; + var virtualView = VirtualView; + + if (double.IsInfinity(virtualView.MaximumWidth) || double.IsInfinity(virtualView.MaximumHeight)) + { + if (platformView == null || virtualView == null || Context == null) + return Size.Zero; + + // Create a spec to handle the native measure + var widthSpec = Context.CreateMeasureSpec(widthConstraint, virtualView.Width, virtualView.Frame.Width); + var heightSpec = Context.CreateMeasureSpec(heightConstraint, virtualView.Height, virtualView.Frame.Height); + + platformView.Measure(widthSpec, heightSpec); + + // Convert back to xplat sizes for the return value + return Context.FromPixels(platformView.MeasuredWidth, platformView.MeasuredHeight); + } + + return base.GetDesiredSize(widthConstraint, heightConstraint); + } + static void UpdateContent(IRefreshViewHandler handler) => handler.PlatformView.UpdateContent(handler.VirtualView.Content, handler.MauiContext); diff --git a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt index aebb188dfa83..53187b450de2 100644 --- a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt +++ b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt @@ -52,6 +52,7 @@ Microsoft.Maui.WebProcessTerminatedEventArgs.Sender.get -> Android.Views.View? override Microsoft.Maui.Handlers.HybridWebViewHandler.ConnectHandler(Android.Webkit.WebView! platformView) -> void override Microsoft.Maui.Handlers.HybridWebViewHandler.CreatePlatformView() -> Android.Webkit.WebView! override Microsoft.Maui.Handlers.HybridWebViewHandler.DisconnectHandler(Android.Webkit.WebView! platformView) -> void +override Microsoft.Maui.Handlers.RefreshViewHandler.GetDesiredSize(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size override Microsoft.Maui.Platform.MauiHybridWebViewClient.Dispose(bool disposing) -> void override Microsoft.Maui.Platform.MauiHybridWebViewClient.ShouldInterceptRequest(Android.Webkit.WebView? view, Android.Webkit.IWebResourceRequest? request) -> Android.Webkit.WebResourceResponse? override Microsoft.Maui.Platform.MauiWebViewClient.OnRenderProcessGone(Android.Webkit.WebView? view, Android.Webkit.RenderProcessGoneDetail? detail) -> bool From cebb2b0611920e9dae97df31f99c934adf970590 Mon Sep 17 00:00:00 2001 From: Jakub Florkowski Date: Sun, 27 Oct 2024 17:04:23 +0100 Subject: [PATCH 2/3] Wrapped scroll view inside a container --- .../RefreshView/RefreshViewHandler.Android.cs | 26 ++----------------- .../net-android/PublicAPI.Unshipped.txt | 2 +- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs index f69b80e74961..f1acc8de543a 100644 --- a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs +++ b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs @@ -9,6 +9,8 @@ protected override MauiSwipeRefreshLayout CreatePlatformView() return new MauiSwipeRefreshLayout(Context); } + public override bool NeedsContainer => true; + protected override void ConnectHandler(MauiSwipeRefreshLayout platformView) { base.ConnectHandler(platformView); @@ -28,30 +30,6 @@ protected override void DisconnectHandler(MauiSwipeRefreshLayout platformView) base.DisconnectHandler(platformView); } - public override Size GetDesiredSize(double widthConstraint, double heightConstraint) - { - var Context = MauiContext?.Context; - var platformView = PlatformView; - var virtualView = VirtualView; - - if (double.IsInfinity(virtualView.MaximumWidth) || double.IsInfinity(virtualView.MaximumHeight)) - { - if (platformView == null || virtualView == null || Context == null) - return Size.Zero; - - // Create a spec to handle the native measure - var widthSpec = Context.CreateMeasureSpec(widthConstraint, virtualView.Width, virtualView.Frame.Width); - var heightSpec = Context.CreateMeasureSpec(heightConstraint, virtualView.Height, virtualView.Frame.Height); - - platformView.Measure(widthSpec, heightSpec); - - // Convert back to xplat sizes for the return value - return Context.FromPixels(platformView.MeasuredWidth, platformView.MeasuredHeight); - } - - return base.GetDesiredSize(widthConstraint, heightConstraint); - } - static void UpdateContent(IRefreshViewHandler handler) => handler.PlatformView.UpdateContent(handler.VirtualView.Content, handler.MauiContext); diff --git a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt index 53187b450de2..f82e33f4540d 100644 --- a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt +++ b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt @@ -52,7 +52,7 @@ Microsoft.Maui.WebProcessTerminatedEventArgs.Sender.get -> Android.Views.View? override Microsoft.Maui.Handlers.HybridWebViewHandler.ConnectHandler(Android.Webkit.WebView! platformView) -> void override Microsoft.Maui.Handlers.HybridWebViewHandler.CreatePlatformView() -> Android.Webkit.WebView! override Microsoft.Maui.Handlers.HybridWebViewHandler.DisconnectHandler(Android.Webkit.WebView! platformView) -> void -override Microsoft.Maui.Handlers.RefreshViewHandler.GetDesiredSize(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size +override Microsoft.Maui.Handlers.RefreshViewHandler.NeedsContainer.get -> bool override Microsoft.Maui.Platform.MauiHybridWebViewClient.Dispose(bool disposing) -> void override Microsoft.Maui.Platform.MauiHybridWebViewClient.ShouldInterceptRequest(Android.Webkit.WebView? view, Android.Webkit.IWebResourceRequest? request) -> Android.Webkit.WebResourceResponse? override Microsoft.Maui.Platform.MauiWebViewClient.OnRenderProcessGone(Android.Webkit.WebView? view, Android.Webkit.RenderProcessGoneDetail? detail) -> bool From cc7074446d79d226334a73038e8561a25e1ef858 Mon Sep 17 00:00:00 2001 From: Jakub Florkowski Date: Wed, 30 Oct 2024 00:55:50 +0100 Subject: [PATCH 3/3] Update RefreshViewHandler.Android.cs --- src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs index f1acc8de543a..4fc1b68771e7 100644 --- a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs +++ b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Android.cs @@ -9,6 +9,7 @@ protected override MauiSwipeRefreshLayout CreatePlatformView() return new MauiSwipeRefreshLayout(Context); } + // RefreshView doesn't size itself correctly unless it's in a container public override bool NeedsContainer => true; protected override void ConnectHandler(MauiSwipeRefreshLayout platformView)