Skip to content

Commit 70a2858

Browse files
[iOS, Catalyst] Fixed CollectionView items height appears larger in Developer Balance sample (#31902)
* Fixed CollectionView card height appears larger in Developer Balance sample * Issue31897 modified test class * Issue31897 Modified test sample * Issue31897 the fix comment has been updated * Modified the test samppe --------- Co-authored-by: devanathan-vaithiyanathan <[email protected]>
1 parent 0ea6ee1 commit 70a2858

File tree

4 files changed

+378
-8
lines changed

4 files changed

+378
-8
lines changed

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

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,7 @@ protected bool IsIndexPathValid(NSIndexPath indexPath)
186186
public override Size GetDesiredSize(double widthConstraint, double heightConstraint)
187187
{
188188
var contentSize = Controller.GetSize();
189-
190-
// If contentSize comes back null, it means none of the content has been realized yet;
191-
// we need to return the expansive size the collection view wants by default to get
192-
// it to start measuring its content
193-
if (contentSize.Height == 0 || contentSize.Width == 0)
194-
{
195-
return base.GetDesiredSize(widthConstraint, heightConstraint);
196-
}
189+
contentSize = EnsureContentSizeForScrollDirection(widthConstraint, heightConstraint, contentSize);
197190

198191
// Our target size is the smaller of it and the constraints
199192
var width = contentSize.Width <= widthConstraint ? contentSize.Width : widthConstraint;
@@ -206,5 +199,30 @@ public override Size GetDesiredSize(double widthConstraint, double heightConstra
206199

207200
return new Size(width, height);
208201
}
202+
203+
Size EnsureContentSizeForScrollDirection(double widthConstraint, double heightConstraint, Size contentSize)
204+
{
205+
// Get the CollectionView orientation
206+
var scrollDirection = Controller.GetScrollDirection();
207+
208+
// If contentSize is zero in the relevant dimension (height for vertical, width for horizontal),
209+
// it means none of the content has been realized yet; we need to return the expansive size
210+
// the collection view wants by default to get it to start measuring its content
211+
if ((scrollDirection == UICollectionViewScrollDirection.Vertical && contentSize.Height == 0) ||
212+
(scrollDirection == UICollectionViewScrollDirection.Horizontal && contentSize.Width == 0))
213+
{
214+
var desiredSize = base.GetDesiredSize(widthConstraint, heightConstraint);
215+
if (scrollDirection == UICollectionViewScrollDirection.Vertical)
216+
{
217+
contentSize.Height = desiredSize.Height;
218+
}
219+
else
220+
{
221+
contentSize.Width = desiredSize.Width;
222+
}
223+
}
224+
225+
return contentSize;
226+
}
209227
}
210228
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,11 @@ internal Size GetSize()
449449
return CollectionView.CollectionViewLayout.CollectionViewContentSize.ToSize();
450450
}
451451

452+
internal UICollectionViewScrollDirection GetScrollDirection()
453+
{
454+
return ScrollDirection;
455+
}
456+
452457
internal void UpdateView(object view, DataTemplate viewTemplate, ref UIView uiView, ref VisualElement formsElement)
453458
{
454459
// Is view set on the ItemsView?
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
using System.ComponentModel;
2+
3+
namespace Maui.Controls.Sample.Issues;
4+
5+
[Issue(IssueTracker.Github, 31897, "CollectionView card height appears larger in Developer Balance sample", PlatformAffected.iOS | PlatformAffected.macOS)]
6+
public class Issue31897 : ContentPage
7+
{
8+
Button getHeight;
9+
Button addItemsButton;
10+
Button removeItemsButton;
11+
Button updateNewItemsButton;
12+
Label HeightLabel;
13+
Label ItemCountLabel;
14+
CollectionView2 ProjectsCollectionView;
15+
Issue31897ViewModel viewModel;
16+
17+
public Issue31897()
18+
{
19+
var mainGrid = new Grid();
20+
21+
var scrollView = new ScrollView();
22+
23+
// Create the inner grid with padding and row spacing
24+
var innerGrid = new Grid
25+
{
26+
Padding = new Thickness(10),
27+
RowSpacing = 10
28+
};
29+
30+
// Add row definitions
31+
innerGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); // Controls row
32+
innerGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); // Height label
33+
innerGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); // Item count label
34+
innerGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); // CollectionView
35+
36+
// Create a horizontal stack for control buttons
37+
var controlsStack = new HorizontalStackLayout
38+
{
39+
Spacing = 10
40+
};
41+
42+
// Create the "Get CV Height" button
43+
getHeight = new Button
44+
{
45+
Text = "Get CV Height",
46+
AutomationId = "GetHeightButton"
47+
};
48+
49+
getHeight.Clicked += (object sender, EventArgs e) =>
50+
{
51+
HeightLabel.Text = Math.Round(ProjectsCollectionView.Height).ToString();
52+
};
53+
54+
// Create the "Add Items" button
55+
addItemsButton = new Button
56+
{
57+
Text = "Add Items",
58+
AutomationId = "AddItemsButton"
59+
};
60+
61+
addItemsButton.Clicked += (object sender, EventArgs e) =>
62+
{
63+
viewModel.AddItems(1); // Add 1 item
64+
UpdateItemCount();
65+
};
66+
67+
// Create the "Remove Items" button
68+
removeItemsButton = new Button
69+
{
70+
Text = "Remove Items",
71+
AutomationId = "RemoveItemsButton"
72+
};
73+
74+
removeItemsButton.Clicked += (object sender, EventArgs e) =>
75+
{
76+
viewModel.RemoveItems(2); // Remove 2 items
77+
UpdateItemCount();
78+
};
79+
80+
// Create the "Update New Items" button
81+
updateNewItemsButton = new Button
82+
{
83+
Text = "Update New",
84+
AutomationId = "UpdateNewItemsButton"
85+
};
86+
87+
updateNewItemsButton.Clicked += (object sender, EventArgs e) =>
88+
{
89+
viewModel.UpdateWithNewItems();
90+
UpdateItemCount();
91+
};
92+
93+
// Add buttons to horizontal stack
94+
controlsStack.Children.Add(getHeight);
95+
controlsStack.Children.Add(addItemsButton);
96+
controlsStack.Children.Add(removeItemsButton);
97+
controlsStack.Children.Add(updateNewItemsButton);
98+
99+
getHeight.SetValue(SemanticProperties.HeadingLevelProperty, SemanticHeadingLevel.Level1);
100+
Grid.SetRow(controlsStack, 0);
101+
102+
// Create the height label
103+
HeightLabel = new Label();
104+
HeightLabel.AutomationId = "HeightLabel";
105+
HeightLabel.SetValue(SemanticProperties.HeadingLevelProperty, SemanticHeadingLevel.Level1);
106+
Grid.SetRow(HeightLabel, 1);
107+
108+
// Create the item count label
109+
ItemCountLabel = new Label
110+
{
111+
AutomationId = "ItemCountLabel",
112+
Text = "Items: 0"
113+
};
114+
ItemCountLabel.SetValue(SemanticProperties.HeadingLevelProperty, SemanticHeadingLevel.Level1);
115+
Grid.SetRow(ItemCountLabel, 2);
116+
117+
// Create the CollectionView
118+
ProjectsCollectionView = new CollectionView2
119+
{
120+
Margin = new Thickness(-7.5, 0),
121+
MinimumHeightRequest = 250,
122+
SelectionMode = SelectionMode.Single
123+
};
124+
125+
// Set up the ItemsLayout
126+
ProjectsCollectionView.ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal)
127+
{
128+
ItemSpacing = 7.5
129+
};
130+
131+
// Create the DataTemplate for items
132+
var itemTemplate = new DataTemplate(() =>
133+
{
134+
var border = new Border
135+
{
136+
WidthRequest = 200,
137+
Background = Colors.GreenYellow
138+
};
139+
140+
var contentView = new ContentView();
141+
142+
var verticalStackLayout = new VerticalStackLayout
143+
{
144+
Spacing = 15,
145+
Background = Colors.Red,
146+
VerticalOptions = LayoutOptions.Start
147+
};
148+
149+
// Name label
150+
var nameLabel = new Label
151+
{
152+
TextColor = Colors.Gray,
153+
FontSize = 14,
154+
TextTransform = TextTransform.Uppercase
155+
};
156+
nameLabel.SetBinding(Label.TextProperty, "Name");
157+
158+
// Description label
159+
var descriptionLabel = new Label
160+
{
161+
LineBreakMode = LineBreakMode.WordWrap
162+
};
163+
descriptionLabel.SetBinding(Label.TextProperty, "Description");
164+
165+
verticalStackLayout.Children.Add(nameLabel);
166+
verticalStackLayout.Children.Add(descriptionLabel);
167+
contentView.Content = verticalStackLayout;
168+
border.Content = contentView;
169+
170+
return border;
171+
});
172+
173+
ProjectsCollectionView.ItemTemplate = itemTemplate;
174+
175+
// Set up data binding
176+
viewModel = new Issue31897ViewModel();
177+
BindingContext = viewModel;
178+
ProjectsCollectionView.SetBinding(CollectionView.ItemsSourceProperty, "Projects");
179+
180+
Grid.SetRow(ProjectsCollectionView, 3);
181+
182+
// Add all controls to the inner grid
183+
innerGrid.Children.Add(controlsStack);
184+
innerGrid.Children.Add(HeightLabel);
185+
innerGrid.Children.Add(ItemCountLabel);
186+
innerGrid.Children.Add(ProjectsCollectionView);
187+
188+
// Set up the hierarchy
189+
scrollView.Content = innerGrid;
190+
mainGrid.Children.Add(scrollView);
191+
Content = mainGrid;
192+
193+
// Initialize item count display
194+
UpdateItemCount();
195+
}
196+
197+
void UpdateItemCount()
198+
{
199+
ItemCountLabel.Text = $"Items: {viewModel.Projects.Count}";
200+
}
201+
202+
public class Issue31897ViewModel : INotifyPropertyChanged
203+
{
204+
List<Issue31897Project> _projects = new();
205+
int _nextId = 0;
206+
207+
public event PropertyChangedEventHandler PropertyChanged;
208+
209+
protected virtual void OnPropertyChanged(string propertyName)
210+
{
211+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
212+
}
213+
214+
public List<Issue31897Project> Projects
215+
{
216+
get { return _projects; }
217+
set
218+
{
219+
_projects = value;
220+
OnPropertyChanged(nameof(Projects));
221+
}
222+
}
223+
224+
public Issue31897ViewModel()
225+
{
226+
LoadData();
227+
}
228+
229+
void LoadData()
230+
{
231+
var projects = new List<Issue31897Project>();
232+
for (int i = 0; i < 4; i++)
233+
{
234+
projects.Add(new Issue31897Project
235+
{
236+
ID = i,
237+
Name = "Developer balance card view " + (i + 1),
238+
Description = "This is a sample description for project " + (i + 1)
239+
});
240+
_nextId = i + 1;
241+
}
242+
243+
Projects = projects;
244+
}
245+
246+
public void AddItems(int count)
247+
{
248+
var currentProjects = new List<Issue31897Project>(_projects);
249+
250+
for (int i = 0; i < count; i++)
251+
{
252+
currentProjects.Add(new Issue31897Project
253+
{
254+
ID = _nextId,
255+
Name = "Added card view " + (_nextId + 1),
256+
Description = "This is a dynamically added description for project " + (_nextId + 1)
257+
});
258+
_nextId++;
259+
}
260+
261+
Projects = currentProjects;
262+
}
263+
264+
public void RemoveItems(int count)
265+
{
266+
var currentProjects = new List<Issue31897Project>(_projects);
267+
268+
int itemsToRemove = Math.Min(count, currentProjects.Count);
269+
for (int i = 0; i < itemsToRemove; i++)
270+
{
271+
if (currentProjects.Count > 0)
272+
{
273+
currentProjects.RemoveAt(currentProjects.Count - 1);
274+
}
275+
}
276+
277+
if (currentProjects.Count == 0)
278+
{
279+
_nextId = 0; // Reset ID counter if all items are removed
280+
}
281+
282+
Projects = currentProjects;
283+
}
284+
285+
public void ClearItems()
286+
{
287+
Projects = new List<Issue31897Project>();
288+
}
289+
290+
public void UpdateWithNewItems()
291+
{
292+
var projects = new List<Issue31897Project>();
293+
for (int i = 0; i < 6; i++)
294+
{
295+
projects.Add(new Issue31897Project
296+
{
297+
ID = i + 500,
298+
Name = "New updated item " + (i + 1),
299+
Description = "This is a completely new item set with fresh content " + (i + 1)
300+
});
301+
}
302+
Projects = projects;
303+
}
304+
}
305+
306+
public class Issue31897Project
307+
{
308+
public int ID { get; set; }
309+
public string Name { get; set; } = string.Empty;
310+
public string Description { get; set; } = string.Empty;
311+
}
312+
}

0 commit comments

Comments
 (0)