Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory analyzer fixes #13

Merged
merged 5 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
<application>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Expand Down
2 changes: 2 additions & 0 deletions Sample/VirtualListViewSample/VirtualListViewSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="LiteDb" Version="5.0.17" />
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="chinook.litedb" />
Expand Down
102 changes: 74 additions & 28 deletions VirtualListView/Apple/CvCell.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using CoreGraphics;
using Foundation;
using Microsoft.Maui.Platform;
using System.Diagnostics.CodeAnalysis;
using UIKit;

namespace Microsoft.Maui;
Expand All @@ -9,27 +10,41 @@ internal class CvCell : UICollectionViewCell
{
public VirtualListViewHandler Handler { get; set; }

public NSIndexPath IndexPath { get; set; }
public WeakReference<NSIndexPath> IndexPath { get; set; }

public PositionInfo PositionInfo { get; set; }

public Action<IView> ReuseCallback { get; set; }
public WeakReference<Action<IView>> ReuseCallback { get; set; }

[Export("initWithFrame:")]
public CvCell(CGRect frame) : base(frame)
{
this.ContentView.AddGestureRecognizer(new UITapGestureRecognizer(() => InvokeTap()));
}

public Action<CvCell> TapHandler { get; set; }
public WeakReference<Action<CvCell>> TapHandler { get; set; }

UIKeyCommand[] keyCommands;
WeakReference<UIKeyCommand[]> keyCommands;

public override UIKeyCommand[] KeyCommands => keyCommands ??= new[]
public override UIKeyCommand[] KeyCommands
{
UIKeyCommand.Create(new NSString("\r"), 0, new ObjCRuntime.Selector("keyCommandSelect")),
UIKeyCommand.Create(new NSString(" "), 0, new ObjCRuntime.Selector("keyCommandSelect")),
};
get
{
if (keyCommands?.TryGetTarget(out var commands) ?? false)
return commands;

var v = new[]
{
UIKeyCommand.Create(new NSString("\r"), 0, new ObjCRuntime.Selector("keyCommandSelect")),
UIKeyCommand.Create(new NSString(" "), 0, new ObjCRuntime.Selector("keyCommandSelect")),
};

keyCommands = new WeakReference<UIKeyCommand[]>(v);

return v;
}

}

[Export("keyCommandSelect")]
public void KeyCommandSelect()
Expand All @@ -40,54 +55,85 @@ public void KeyCommandSelect()
void InvokeTap()
{
if (PositionInfo.Kind == PositionKind.Item)
TapHandler?.Invoke(this);
{
if (TapHandler?.TryGetTarget(out var handler) ?? false)
handler?.Invoke(this);
}
}

public void UpdateSelected(bool selected)
{
PositionInfo.IsSelected = selected;

if (VirtualView?.TryGetTarget(out var virtualView) ?? false)
{
if (virtualView is IPositionInfo positionInfo)
{
positionInfo.IsSelected = selected;
virtualView.Handler?.UpdateValue(nameof(PositionInfo.IsSelected));
}
}
}

public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittingAttributes(UICollectionViewLayoutAttributes layoutAttributes)
{
if (NativeView == null || VirtualView == null)
return layoutAttributes;
if ((NativeView is not null && NativeView.TryGetTarget(out var _))
&& (VirtualView is not null && VirtualView.TryGetTarget(out var virtualView)))
{
var measure = virtualView.Measure(layoutAttributes.Size.Width, double.PositiveInfinity);

var measure = VirtualView.Measure(layoutAttributes.Size.Width, double.PositiveInfinity);
layoutAttributes.Frame = new CGRect(0, layoutAttributes.Frame.Y, layoutAttributes.Frame.Width, measure.Height);

layoutAttributes.Frame = new CGRect(0, layoutAttributes.Frame.Y, layoutAttributes.Frame.Width, measure.Height);
return layoutAttributes;
}

return layoutAttributes;
}

public bool NeedsView
=> NativeView == null;
=> NativeView == null || !NativeView.TryGetTarget(out var _);

public IView VirtualView { get; private set; }
public WeakReference<IView> VirtualView { get; set; }

public UIView NativeView { get; private set; }
public WeakReference<UIView> NativeView { get; set; }

public override void PrepareForReuse()
{
base.PrepareForReuse();

// TODO: Recycle
if (VirtualView != null)
ReuseCallback?.Invoke(VirtualView);
if ((VirtualView?.TryGetTarget(out var virtualView) ?? false)
&& (ReuseCallback?.TryGetTarget(out var reuseCallback) ?? false))
{
reuseCallback?.Invoke(virtualView);
}
}

public void SwapView(IView newView)
{
if (VirtualView == null || VirtualView.Handler == null || NativeView == null)
// Create a new platform native view if we don't have one yet
if (!(NativeView?.TryGetTarget(out var nativeView) ?? false))
{
nativeView = newView.ToPlatform(this.Handler.MauiContext);
nativeView.Frame = this.ContentView.Frame;
nativeView.AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth;
this.ContentView.AddSubview(nativeView);
NativeView = new WeakReference<UIView>(nativeView);
}

// Create a new virtual view if we don't have one yet
if (!(VirtualView?.TryGetTarget(out var virtualView) ?? false) || (virtualView?.Handler is null))
{
NativeView = newView.ToPlatform(this.Handler.MauiContext);
VirtualView = newView;
NativeView.Frame = this.ContentView.Frame;
NativeView.AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth;
this.ContentView.AddSubview(NativeView);
virtualView = newView;
VirtualView = new WeakReference<IView>(virtualView);
}
else
{
var handler = VirtualView.Handler;
VirtualView.Handler = null;
var handler = virtualView.Handler;
virtualView.Handler = null;
newView.Handler = handler;
handler.SetVirtualView(newView);
VirtualView = newView;
VirtualView.SetTarget(newView);
}
}
}
}
24 changes: 15 additions & 9 deletions VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ public override UICollectionViewCell GetCell(UICollectionView collectionView, NS
};

var cell = collectionView.DequeueReusableCell(nativeReuseId, indexPath) as CvCell;
cell.TapHandler = TapCellHandler;
cell.TapHandler = new WeakReference<Action<CvCell>>(TapCellHandler);
cell.Handler = Handler;
cell.IndexPath = indexPath;

cell.ReuseCallback = rv =>
Handler.VirtualView.ViewSelector.ViewDetached(info, cell.VirtualView);
cell.IndexPath = new WeakReference<NSIndexPath>(indexPath);

cell.ReuseCallback = new WeakReference<Action<IView>>((rv) =>
{
if (cell?.VirtualView?.TryGetTarget(out var cellVirtualView) ?? false)
Handler.VirtualView.ViewSelector.ViewDetached(info, cellVirtualView);
});

if (info.SectionIndex < 0 || info.ItemIndex < 0)
info.IsSelected = false;
Expand All @@ -60,12 +63,15 @@ public override UICollectionViewCell GetCell(UICollectionView collectionView, NS

cell.PositionInfo = info;

if (cell.VirtualView is IPositionInfo viewPositionInfo)
viewPositionInfo.IsSelected = info.IsSelected;
if (cell.VirtualView.TryGetTarget(out var cellVirtualView))
{
if (cellVirtualView is IPositionInfo viewPositionInfo)
viewPositionInfo.IsSelected = info.IsSelected;

Handler?.PositionalViewSelector?.ViewSelector?.RecycleView(info, data, cell.VirtualView);
Handler?.PositionalViewSelector?.ViewSelector?.RecycleView(info, data, cellVirtualView);

Handler.VirtualView.ViewSelector.ViewAttached(info, cell.VirtualView);
Handler.VirtualView.ViewSelector.ViewAttached(info, cellVirtualView);
}

return cell;
}
Expand Down
13 changes: 8 additions & 5 deletions VirtualListView/Apple/CvDelegate.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ public CvDelegate(VirtualListViewHandler handler, UICollectionView collectionVie
: base()
{
Handler = handler;
NativeCollectionView = collectionView;
NativeCollectionView = new WeakReference<UICollectionView>(collectionView);
}

internal readonly UICollectionView NativeCollectionView;
internal readonly WeakReference<UICollectionView> NativeCollectionView;
internal readonly VirtualListViewHandler Handler;

public Action<NFloat, NFloat> ScrollHandler { get; set; }
public WeakReference<Action<NFloat, NFloat>> ScrollHandler { get; set; }

public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
=> HandleSelection(collectionView, indexPath, true);
Expand All @@ -31,7 +31,7 @@ void HandleSelection(UICollectionView collectionView, NSIndexPath indexPath, boo

if ((selectedCell?.PositionInfo?.Kind ?? PositionKind.Header) == PositionKind.Item)
{
selectedCell.PositionInfo.IsSelected = selected;
selectedCell.UpdateSelected(selected);

var itemPos = new ItemPosition(
selectedCell.PositionInfo.SectionIndex,
Expand All @@ -45,7 +45,10 @@ void HandleSelection(UICollectionView collectionView, NSIndexPath indexPath, boo
}

public override void Scrolled(UIScrollView scrollView)
=> ScrollHandler?.Invoke(scrollView.ContentOffset.X, scrollView.ContentOffset.Y);
{
if (ScrollHandler?.TryGetTarget(out var handler) ?? false)
handler?.Invoke(scrollView.ContentOffset.X, scrollView.ContentOffset.Y);
}

public override bool ShouldSelectItem(UICollectionView collectionView, NSIndexPath indexPath)
=> IsRealItem(indexPath);
Expand Down
Loading
Loading