Skip to content

Commit

Permalink
Merge pull request #13 from Redth/memory-analyzer-fixes
Browse files Browse the repository at this point in the history
Memory analyzer fixes
  • Loading branch information
Redth committed Nov 28, 2023
2 parents 1939772 + 3fb3bd8 commit 6191fcc
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 100 deletions.
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

0 comments on commit 6191fcc

Please sign in to comment.