Skip to content

Commit affd989

Browse files
committed
Fix iOS CollectionView not reacting properly to orientation changes
1 parent e49e46a commit affd989

9 files changed

Lines changed: 85 additions & 44 deletions

File tree

src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin
9999
{
100100
// Measure this cell (including the Forms element) if there is no constrained size
101101
var size = ConstrainedSize == default ? Measure() : ConstrainedSize;
102+
if (size != _size)
103+
{
104+
// While the platform view Frame is set via auto-layout constraints,
105+
// We have to force a layout pass on the platform view to ensure it's correctly laid out.
106+
ContentView.Subviews.FirstOrDefaultNoLinq()?.SetNeedsLayout();
107+
}
102108

103109
_size = size.ToSize();
104110
_measureInvalidated = false;
@@ -112,23 +118,6 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin
112118
return preferredAttributes;
113119
}
114120

115-
public override void LayoutSubviews()
116-
{
117-
if (PlatformHandler?.VirtualView is { } virtualView)
118-
{
119-
// While the platform view Frame is set via auto-layout constraints,
120-
// we have to set the Frame on the virtual view manually.
121-
// Subviews will eventually be arranged via LayoutSubviews once the cell comes into play.
122-
var frame = new Rect(Point.Zero, Bounds.Size.ToSize());
123-
if (virtualView.Frame != frame)
124-
{
125-
virtualView.Arrange(frame);
126-
}
127-
}
128-
129-
base.LayoutSubviews();
130-
}
131-
132121
[Obsolete]
133122
[EditorBrowsable(EditorBrowsableState.Never)]
134123
protected void Layout(CGSize constraints)

src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin
9292
if (_measureInvalidated || _cachedConstraints != constraints)
9393
{
9494
var measure = virtualView.Measure(constraints.Width, constraints.Height);
95+
if (_measuredSize != measure)
96+
{
97+
// While the platform view Frame is set via auto-layout constraints,
98+
// We have to force a layout pass on the platform view to ensure it's correctly laid out.
99+
ContentView.Subviews.FirstOrDefaultNoLinq()?.SetNeedsLayout();
100+
}
101+
95102
_cachedConstraints = constraints;
96103
_measuredSize = measure;
97104
}
@@ -109,23 +116,6 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin
109116
return preferredAttributes;
110117
}
111118

112-
public override void LayoutSubviews()
113-
{
114-
if (PlatformHandler?.VirtualView is { } virtualView)
115-
{
116-
// While the platform view Frame is set via auto-layout constraints,
117-
// we have to set the Frame on the virtual view manually.
118-
// Subviews will eventually be arranged via LayoutSubviews once the cell comes into play.
119-
var frame = new Rect(Point.Zero, Bounds.Size.ToSize());
120-
if (virtualView.Frame != frame)
121-
{
122-
virtualView.Arrange(frame);
123-
}
124-
}
125-
126-
base.LayoutSubviews();
127-
}
128-
129119
public override void PrepareForReuse()
130120
{
131121
//Unbind();

src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#nullable enable
22
Microsoft.Maui.Controls.StyleableElement.Style.get -> Microsoft.Maui.Controls.Style?
3-
override Microsoft.Maui.Controls.Handlers.Items.TemplatedCell.LayoutSubviews() -> void
4-
override Microsoft.Maui.Controls.Handlers.Items2.TemplatedCell2.LayoutSubviews() -> void
53
override Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.GetDesiredSize(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
64
~abstract Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.CreateController(TItemsView newElement, UIKit.UICollectionViewLayout layout) -> Microsoft.Maui.Controls.Handlers.Items2.ItemsViewController2<TItemsView>
75
~abstract Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.SelectLayout() -> UIKit.UICollectionViewLayout

src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#nullable enable
22
Microsoft.Maui.Controls.StyleableElement.Style.get -> Microsoft.Maui.Controls.Style?
3-
override Microsoft.Maui.Controls.Handlers.Items.TemplatedCell.LayoutSubviews() -> void
4-
override Microsoft.Maui.Controls.Handlers.Items2.TemplatedCell2.LayoutSubviews() -> void
53
override Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.GetDesiredSize(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
64
~abstract Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.CreateController(TItemsView newElement, UIKit.UICollectionViewLayout layout) -> Microsoft.Maui.Controls.Handlers.Items2.ItemsViewController2<TItemsView>
75
~abstract Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2<TItemsView>.SelectLayout() -> UIKit.UICollectionViewLayout
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
namespace Controls.TestCases.HostApp.Issues;
2+
3+
[Issue(IssueTracker.Github, 28657, "iOS - Rotating the simulator would cause clipping on the description text", PlatformAffected.iOS)]
4+
class Issue28657 : ContentPage
5+
{
6+
public Issue28657()
7+
{
8+
var cv = new CollectionView();
9+
cv.ItemTemplate = new DataTemplate(() =>
10+
{
11+
var label = new Label();
12+
label.BackgroundColor = Colors.DeepSkyBlue;
13+
label.LineBreakMode = LineBreakMode.CharacterWrap;
14+
label.SetBinding(Label.TextProperty, ".");
15+
var vsl = new VerticalStackLayout { Padding = 8 };
16+
vsl.Add(label);
17+
vsl.BackgroundColor = Colors.SlateBlue;
18+
return vsl;
19+
});
20+
cv.ItemsSource = Enumerable.Range(0, 30)
21+
.Select(x => x + ": Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit.")
22+
.ToList();
23+
var label = new Label
24+
{
25+
AutomationId = "StubLabel",
26+
Text = "Rotate the device until you get back to portrait mode. The text should wrap normally on each row.",
27+
};
28+
var grid = new Grid
29+
{
30+
RowDefinitions = new RowDefinitionCollection(
31+
new RowDefinition(GridLength.Auto),
32+
new RowDefinition(GridLength.Star))
33+
};
34+
grid.Add(label);
35+
grid.Add(cv, 0, 1);
36+
Content = grid;
37+
}
38+
}

src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25671.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ public async Task LayoutPassesShouldNotIncrease()
4343

4444
#if IOS
4545
var maxMeasurePasses = 221;
46-
var maxArrangePasses = 237;
46+
var maxArrangePasses = 186;
4747

4848
if (App.FindElement("HeadingLabel").GetText() == "CollectionViewHandler2")
4949
{
50-
maxMeasurePasses = 362;
51-
maxArrangePasses = 398;
50+
maxMeasurePasses = 340;
51+
maxArrangePasses = 310;
5252
}
5353
#elif ANDROID
5454
const int maxMeasurePasses = 353;
@@ -64,9 +64,9 @@ public async Task LayoutPassesShouldNotIncrease()
6464
TestContext.AddTestAttachment(logFile, "LayoutPasses.log");
6565

6666
// Then assert that the measure passes and arrange passes are less than the expected values.
67-
// Let's give a 5% margin of error.
68-
ClassicAssert.LessOrEqual(measurePasses, maxMeasurePasses * 1.05);
69-
ClassicAssert.LessOrEqual(arrangePasses, maxArrangePasses * 1.05);
67+
// Let's give a 10% margin of error due to CI variability.
68+
ClassicAssert.LessOrEqual(measurePasses, maxMeasurePasses * 1.1);
69+
ClassicAssert.LessOrEqual(arrangePasses, maxArrangePasses * 1.1);
7070
}
7171

7272
async Task ScrollDown()
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#if IOS
2+
using NUnit.Framework;
3+
using UITest.Appium;
4+
using UITest.Core;
5+
6+
namespace Microsoft.Maui.TestCases.Tests.Issues;
7+
8+
public class Issue28657 : _IssuesUITest
9+
{
10+
public override string Issue => "iOS - Rotating the simulator would cause clipping on the description text";
11+
public Issue28657(TestDevice device) : base(device)
12+
{
13+
}
14+
15+
[Test]
16+
[Category(UITestCategories.CollectionView)]
17+
public void CellLayoutUpdatesCorrectlyAfterDeviceOrientationChanges()
18+
{
19+
App.WaitForElement("StubLabel");
20+
App.SetOrientationLandscape();
21+
Thread.Sleep(400);
22+
VerifyScreenshot("Issue28657_Landscape");
23+
App.SetOrientationPortrait();
24+
Thread.Sleep(400);
25+
VerifyScreenshot("Issue28657_Portrait");
26+
}
27+
}
28+
#endif
158 KB
Loading
266 KB
Loading

0 commit comments

Comments
 (0)