Skip to content

Commit eb72a58

Browse files
committed
Revert [iOS] Fix memory leak in CarouselViewHandler2 #29719
1 parent 239fb5f commit eb72a58

File tree

3 files changed

+132
-188
lines changed

3 files changed

+132
-188
lines changed

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

Lines changed: 113 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,121 @@ protected override CarouselViewController2 CreateController(CarouselView newElem
4040
protected override UICollectionViewLayout SelectLayout()
4141
{
4242
bool isHorizontal = VirtualView.ItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal;
43-
var peekInsets = VirtualView.PeekAreaInsets;
4443

45-
var weakItemsView = new WeakReference<CarouselView>(ItemsView);
46-
var weakController = new WeakReference<CarouselViewController2>((CarouselViewController2)Controller);
44+
NSCollectionLayoutDimension itemWidth = NSCollectionLayoutDimension.CreateFractionalWidth(1);
45+
NSCollectionLayoutDimension itemHeight = NSCollectionLayoutDimension.CreateFractionalHeight(1);
46+
NSCollectionLayoutDimension groupWidth = NSCollectionLayoutDimension.CreateFractionalWidth(1);
47+
NSCollectionLayoutDimension groupHeight = NSCollectionLayoutDimension.CreateFractionalHeight(1);
48+
nfloat itemSpacing = 0;
49+
NSCollectionLayoutGroup group = null;
4750

48-
return LayoutFactory2.CreateCarouselLayout(
49-
isHorizontal,
50-
peekInsets,
51-
weakItemsView,
52-
weakController);
51+
var layout = new UICollectionViewCompositionalLayout((sectionIndex, environment) =>
52+
{
53+
if (VirtualView is null)
54+
{
55+
return null;
56+
}
57+
double sectionMargin = 0.0;
58+
if (!isHorizontal)
59+
{
60+
sectionMargin = VirtualView.PeekAreaInsets.VerticalThickness / 2;
61+
var newGroupHeight = environment.Container.ContentSize.Height - VirtualView.PeekAreaInsets.VerticalThickness;
62+
groupHeight = NSCollectionLayoutDimension.CreateAbsolute((nfloat)newGroupHeight);
63+
groupWidth = NSCollectionLayoutDimension.CreateFractionalWidth(1);
64+
}
65+
else
66+
{
67+
sectionMargin = VirtualView.PeekAreaInsets.HorizontalThickness / 2;
68+
var newGroupWidth = environment.Container.ContentSize.Width - VirtualView.PeekAreaInsets.HorizontalThickness;
69+
groupWidth = NSCollectionLayoutDimension.CreateAbsolute((nfloat)newGroupWidth);
70+
groupHeight = NSCollectionLayoutDimension.CreateFractionalHeight(1);
71+
}
72+
73+
// Each item has a size
74+
var itemSize = NSCollectionLayoutSize.Create(itemWidth, itemHeight);
75+
// Create the item itself from the size
76+
var item = NSCollectionLayoutItem.Create(layoutSize: itemSize);
77+
78+
//item.ContentInsets = new NSDirectionalEdgeInsets(0, itemInset, 0, 0);
79+
80+
var groupSize = NSCollectionLayoutSize.Create(groupWidth, groupHeight);
81+
82+
if (OperatingSystem.IsIOSVersionAtLeast(16))
83+
{
84+
group = isHorizontal ? NSCollectionLayoutGroup.GetHorizontalGroup(groupSize, item, 1) :
85+
NSCollectionLayoutGroup.GetVerticalGroup(groupSize, item, 1);
86+
}
87+
else
88+
{
89+
group = isHorizontal ? NSCollectionLayoutGroup.CreateHorizontal(groupSize, item, 1) :
90+
NSCollectionLayoutGroup.CreateVertical(groupSize, item, 1);
91+
}
92+
93+
// Create our section layout
94+
var section = NSCollectionLayoutSection.Create(group: group);
95+
section.InterGroupSpacing = itemSpacing;
96+
section.OrthogonalScrollingBehavior = isHorizontal ? UICollectionLayoutSectionOrthogonalScrollingBehavior.GroupPagingCentered : UICollectionLayoutSectionOrthogonalScrollingBehavior.None;
97+
section.VisibleItemsInvalidationHandler = (items, offset, env) =>
98+
{
99+
//This will allow us to SetPosition when we are scrolling the items
100+
//based on the current page
101+
var page = (offset.X + sectionMargin) / env.Container.ContentSize.Width;
102+
103+
// Check if we not are at the beginning or end of the page and if we have items
104+
if (Math.Abs(page % 1) > (double.Epsilon * 100) || Controller.ItemsSource.ItemCount <= 0)
105+
{
106+
return;
107+
}
108+
109+
var pageIndex = (int)page;
110+
var carouselPosition = pageIndex;
111+
112+
var cv2Controller = (CarouselViewController2)Controller;
113+
114+
//If we are looping, we need to get the correct position
115+
if (ItemsView.Loop)
116+
{
117+
var maxIndex = (Controller.ItemsSource as ILoopItemsViewSource).LoopCount - 1;
118+
119+
//To mimic looping, we needed to modify the ItemSource and inserted a new item at the beginning and at the end
120+
if (pageIndex == maxIndex)
121+
{
122+
//When at last item, we need to change to 2nd item, so we can scroll right or left
123+
pageIndex = 1;
124+
}
125+
else if (pageIndex == 0)
126+
{
127+
//When at first item, need to change to one before last, so we can scroll right or left
128+
pageIndex = maxIndex - 1;
129+
}
130+
131+
//since we added one item at the beginning of our ItemSource, we need to subtract one
132+
carouselPosition = pageIndex - 1;
133+
134+
if (ItemsView.Position != carouselPosition)
135+
{
136+
//If we are updating the ItemsSource, we don't want to scroll the CollectionView
137+
if (cv2Controller.IsUpdating())
138+
{
139+
return;
140+
}
141+
142+
var goToIndexPath = cv2Controller.GetScrollToIndexPath(carouselPosition);
143+
144+
//This will move the carousel to fake the loop
145+
Controller.CollectionView.ScrollToItem(NSIndexPath.FromItemSection(pageIndex, 0), UICollectionViewScrollPosition.Left, false);
146+
147+
}
148+
}
149+
150+
//Update the CarouselView position
151+
cv2Controller?.SetPosition(carouselPosition);
152+
153+
};
154+
return section;
155+
});
156+
157+
return layout;
53158
}
54159

55160
protected override void ScrollToRequested(object sender, ScrollToRequestEventArgs args)

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

Lines changed: 0 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
using System.Collections.Generic;
33
using System.Runtime.InteropServices;
44
using CoreGraphics;
5-
using Foundation;
6-
using Microsoft.Maui.Controls.Handlers.Items;
75
using UIKit;
86

97
namespace Microsoft.Maui.Controls.Handlers.Items2;
@@ -263,136 +261,6 @@ public static UICollectionViewLayout CreateHorizontalGrid(GridItemsLayout gridIt
263261
gridItemsLayout.Span);
264262

265263

266-
#nullable disable
267-
public static UICollectionViewLayout CreateCarouselLayout(
268-
bool isHorizontal,
269-
Thickness peekAreaInsets,
270-
WeakReference<CarouselView> weakItemsView,
271-
WeakReference<CarouselViewController2> weakController)
272-
{
273-
NSCollectionLayoutDimension itemWidth = NSCollectionLayoutDimension.CreateFractionalWidth(1);
274-
NSCollectionLayoutDimension itemHeight = NSCollectionLayoutDimension.CreateFractionalHeight(1);
275-
NSCollectionLayoutDimension groupWidth = NSCollectionLayoutDimension.CreateFractionalWidth(1);
276-
NSCollectionLayoutDimension groupHeight = NSCollectionLayoutDimension.CreateFractionalHeight(1);
277-
nfloat itemSpacing = 0;
278-
NSCollectionLayoutGroup group = null;
279-
280-
var layout = new UICollectionViewCompositionalLayout((sectionIndex, environment) =>
281-
{
282-
if (!weakItemsView.TryGetTarget(out var itemsView) || !weakController.TryGetTarget(out var controller))
283-
{
284-
return null;
285-
}
286-
287-
double sectionMargin = 0.0;
288-
289-
if (!isHorizontal)
290-
{
291-
sectionMargin = peekAreaInsets.VerticalThickness / 2;
292-
var newGroupHeight = environment.Container.ContentSize.Height - peekAreaInsets.VerticalThickness;
293-
groupHeight = NSCollectionLayoutDimension.CreateAbsolute((nfloat)newGroupHeight);
294-
groupWidth = NSCollectionLayoutDimension.CreateFractionalWidth(1);
295-
}
296-
else
297-
{
298-
sectionMargin = peekAreaInsets.HorizontalThickness / 2;
299-
var newGroupWidth = environment.Container.ContentSize.Width - peekAreaInsets.HorizontalThickness;
300-
groupWidth = NSCollectionLayoutDimension.CreateAbsolute((nfloat)newGroupWidth);
301-
groupHeight = NSCollectionLayoutDimension.CreateFractionalHeight(1);
302-
}
303-
304-
// Each item has a size
305-
var itemSize = NSCollectionLayoutSize.Create(itemWidth, itemHeight);
306-
// Create the item itself from the size
307-
var item = NSCollectionLayoutItem.Create(layoutSize: itemSize);
308-
309-
//item.ContentInsets = new NSDirectionalEdgeInsets(0, itemInset, 0, 0);
310-
311-
var groupSize = NSCollectionLayoutSize.Create(groupWidth, groupHeight);
312-
313-
if (OperatingSystem.IsIOSVersionAtLeast(16))
314-
{
315-
group = isHorizontal
316-
? NSCollectionLayoutGroup.GetHorizontalGroup(groupSize, item, 1)
317-
: NSCollectionLayoutGroup.GetVerticalGroup(groupSize, item, 1);
318-
}
319-
else
320-
{
321-
group = isHorizontal
322-
? NSCollectionLayoutGroup.CreateHorizontal(groupSize, item, 1)
323-
: NSCollectionLayoutGroup.CreateVertical(groupSize, item, 1);
324-
}
325-
326-
var section = NSCollectionLayoutSection.Create(group: group);
327-
section.InterGroupSpacing = itemSpacing;
328-
section.OrthogonalScrollingBehavior = isHorizontal
329-
? UICollectionLayoutSectionOrthogonalScrollingBehavior.GroupPagingCentered
330-
: UICollectionLayoutSectionOrthogonalScrollingBehavior.None;
331-
332-
section.VisibleItemsInvalidationHandler = (items, offset, env) =>
333-
{
334-
if (!weakItemsView.TryGetTarget(out var itemsView) || !weakController.TryGetTarget(out var cv2Controller))
335-
{
336-
return;
337-
}
338-
339-
var page = (offset.X + sectionMargin) / env.Container.ContentSize.Width;
340-
341-
if (Math.Abs(page % 1) > (double.Epsilon * 100) || cv2Controller.ItemsSource.ItemCount <= 0)
342-
{
343-
return;
344-
}
345-
346-
var pageIndex = (int)page;
347-
var carouselPosition = pageIndex;
348-
349-
if (itemsView.Loop && cv2Controller.ItemsSource is ILoopItemsViewSource loopSource)
350-
{
351-
var maxIndex = loopSource.LoopCount - 1;
352-
353-
//To mimic looping, we needed to modify the ItemSource and inserted a new item at the beginning and at the end
354-
if (pageIndex == maxIndex)
355-
{
356-
//When at last item, we need to change to 2nd item, so we can scroll right or left
357-
pageIndex = 1;
358-
}
359-
else if (pageIndex == 0)
360-
{
361-
//When at first item, need to change to one before last, so we can scroll right or left
362-
pageIndex = maxIndex - 1;
363-
}
364-
365-
//since we added one item at the beginning of our ItemSource, we need to subtract one
366-
carouselPosition = pageIndex - 1;
367-
368-
if (itemsView.Position != carouselPosition)
369-
{
370-
//If we are updating the ItemsSource, we don't want to scroll the CollectionView
371-
if (cv2Controller.IsUpdating())
372-
{
373-
return;
374-
}
375-
376-
var goToIndexPath = cv2Controller.GetScrollToIndexPath(carouselPosition);
377-
378-
//This will move the carousel to fake the loop
379-
cv2Controller.CollectionView.ScrollToItem(
380-
NSIndexPath.FromItemSection(pageIndex, 0),
381-
UICollectionViewScrollPosition.Left,
382-
false);
383-
}
384-
}
385-
386-
//Update the CarouselView position
387-
cv2Controller?.SetPosition(carouselPosition);
388-
};
389-
390-
return section;
391-
});
392-
393-
return layout;
394-
}
395-
#nullable enable
396264
class CustomUICollectionViewCompositionalLayout : UICollectionViewCompositionalLayout
397265
{
398266
LayoutSnapInfo _snapInfo;

0 commit comments

Comments
 (0)