From 554de0f0ff8101c5c17a4c8eac5834e2dc32e9d7 Mon Sep 17 00:00:00 2001 From: Dhivya-SF4094 <127717131+Dhivya-SF4094@users.noreply.github.com> Date: Mon, 9 Mar 2026 18:48:04 +0530 Subject: [PATCH 1/3] Fixed Refreshview - Collectionview sizing not working correctly --- .../TestCases.HostApp/Issues/Issue12131.cs | 54 +++++++++++++++++++ .../Tests/Issues/Issue12131.cs | 32 +++++++++++ .../Android/MauiSwipeRefreshLayout.cs | 27 +++++++++- 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue12131.cs diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs new file mode 100644 index 000000000000..1c2eb929c7ba --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs @@ -0,0 +1,54 @@ +using System.Reflection; +using Microsoft.Maui.Controls; + +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.Github, 12131, "RefreshView - CollectionView sizing not working correctly inside VerticalStackLayout", PlatformAffected.Android)] + public class Issue12131 : ContentPage + { + public Issue12131() + { + var items = Enumerable.Range(1, 20).Select(i => $"Item {i}").ToList(); + + var collectionView = new CollectionView + { + AutomationId = "CollectionView12131", + ItemTemplate = new DataTemplate(() => + { + var label = new Label(); + label.SetBinding(Label.TextProperty, "."); + return label; + }), + ItemsSource = items + }; + + var refreshView = new RefreshView + { + AutomationId = "RefreshView12131", + Content = collectionView + }; + + var sizeLabel = new Label + { + AutomationId = "SizeLabel12131", + Text = "Waiting..." + }; + + refreshView.SizeChanged += (s, e) => + { + sizeLabel.Text = $"Height={refreshView.Height:F0}"; + }; + + Content = new VerticalStackLayout + { + Padding = 10, + Children = + { + new Label { Text = "RefreshView inside VerticalStackLayout" }, + sizeLabel, + refreshView + } + }; + } + } +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue12131.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue12131.cs new file mode 100644 index 000000000000..1ae0b8042583 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue12131.cs @@ -0,0 +1,32 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues +{ + public class Issue12131 : _IssuesUITest + { + public Issue12131(TestDevice testDevice) : base(testDevice) { } + + public override string Issue => "RefreshView - CollectionView sizing not working correctly inside VerticalStackLayout"; + + [Test] + [Category(UITestCategories.RefreshView)] + public void RefreshViewHasNonZeroHeightInVerticalStackLayout() + { + App.WaitForElement("RefreshView12131"); + var rect = App.FindElement("RefreshView12131").GetRect(); + Assert.That(rect.Height, Is.GreaterThan(0), "RefreshView should have a non-zero height when placed inside a VerticalStackLayout"); + } + + [Test] + [Category(UITestCategories.RefreshView)] + public void CollectionViewDoesNotExceedAvailableWidth() + { + App.WaitForElement("CollectionView12131"); + var refreshRect = App.FindElement("RefreshView12131").GetRect(); + var collectionRect = App.FindElement("CollectionView12131").GetRect(); + Assert.That(collectionRect.Width, Is.LessThanOrEqualTo(refreshRect.Width + 1), "CollectionView width should not exceed RefreshView width"); + } + } +} diff --git a/src/Core/src/Platform/Android/MauiSwipeRefreshLayout.cs b/src/Core/src/Platform/Android/MauiSwipeRefreshLayout.cs index 3f9734bb143a..1d2553dde335 100644 --- a/src/Core/src/Platform/Android/MauiSwipeRefreshLayout.cs +++ b/src/Core/src/Platform/Android/MauiSwipeRefreshLayout.cs @@ -39,6 +39,9 @@ public ICrossPlatformLayout? CrossPlatformLayout public override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Always call base.OnMeasure — unlike ContentViewGroup/LayoutViewGroup, + // SwipeRefreshLayout.onMeasure internally measures its spinner indicator + // (mCircleView). Skipping this leaves the spinner at 0x0, making it invisible. base.OnMeasure(widthMeasureSpec, heightMeasureSpec); if (CrossPlatformLayout is null) @@ -49,11 +52,33 @@ public override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec) var deviceIndependentWidth = widthMeasureSpec.ToDouble(_context); var deviceIndependentHeight = heightMeasureSpec.ToDouble(_context); - CrossPlatformLayout?.CrossPlatformMeasure(deviceIndependentWidth, deviceIndependentHeight); + var widthMode = MeasureSpec.GetMode(widthMeasureSpec); + var heightMode = MeasureSpec.GetMode(heightMeasureSpec); + + var measure = CrossPlatformLayout.CrossPlatformMeasure(deviceIndependentWidth, deviceIndependentHeight); + + // Unlike ContentViewGroup/LayoutViewGroup, SwipeRefreshLayout internally positions + // its spinner at getMeasuredWidth()/2. We must use the full spec size for both + // Exactly and AtMost modes (matching View.getDefaultSize behavior) so the spinner + // is centered correctly. Only for Unspecified do we use the cross-platform measure. + var width = widthMode == MeasureSpecMode.Unspecified ? measure.Width : deviceIndependentWidth; + var height = heightMode == MeasureSpecMode.Unspecified ? measure.Height : deviceIndependentHeight; + + var platformWidth = _context.ToPixels(width); + var platformHeight = _context.ToPixels(height); + + // Minimum values win over everything + platformWidth = Math.Max(MinimumWidth, platformWidth); + platformHeight = Math.Max(MinimumHeight, platformHeight); + + SetMeasuredDimension((int)platformWidth, (int)platformHeight); } protected override void OnLayout(bool changed, int left, int top, int right, int bottom) { + // Always call base.OnLayout — SwipeRefreshLayout.onLayout positions the + // spinner indicator (mCircleView) centered horizontally. Without this, + // the spinner won't appear or will be mispositioned. base.OnLayout(changed, left, top, right, bottom); if (CrossPlatformLayout is null) { From e8e824b34d68687a345c779ad8d2ba28a8051e91 Mon Sep 17 00:00:00 2001 From: Dhivya-SF4094 <127717131+Dhivya-SF4094@users.noreply.github.com> Date: Mon, 9 Mar 2026 18:53:56 +0530 Subject: [PATCH 2/3] Updated label text --- src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs index 1c2eb929c7ba..e4b0b1c7ca1e 100644 --- a/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs @@ -44,7 +44,7 @@ public Issue12131() Padding = 10, Children = { - new Label { Text = "RefreshView inside VerticalStackLayout" }, + new Label { Text = "CollectionView wrapped within RefreshView." }, sizeLabel, refreshView } From 36629c388d304f2c1dcfdbf66191f96a4eb99c77 Mon Sep 17 00:00:00 2001 From: Dhivya-SF4094 <127717131+Dhivya-SF4094@users.noreply.github.com> Date: Tue, 10 Mar 2026 18:00:36 +0530 Subject: [PATCH 3/3] Removed Unused import --- src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs index e4b0b1c7ca1e..333272103b1b 100644 --- a/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue12131.cs @@ -1,6 +1,3 @@ -using System.Reflection; -using Microsoft.Maui.Controls; - namespace Maui.Controls.Sample.Issues { [Issue(IssueTracker.Github, 12131, "RefreshView - CollectionView sizing not working correctly inside VerticalStackLayout", PlatformAffected.Android)]