Skip to content

Commit

Permalink
Merge pull request #16 from MPowerKit/fix_groupable_data_adapter
Browse files Browse the repository at this point in the history
Fix groupable data adapter
  • Loading branch information
Alex-Dobrynin authored Jul 26, 2024
2 parents 0fdd2cb + 245374e commit 6ef7ae6
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 62 deletions.
7 changes: 2 additions & 5 deletions MPowerKit.VirtualizeListView/DataAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,8 @@ public virtual bool IsFooter(DataTemplate template, int position)
return IsOneOf(Control.FooterTemplate, template, position);
}

public virtual void OnBindCell(CellHolder holder, int position)
public virtual void OnBindCell(CellHolder holder, AdapterItem item, int position)
{
var item = Items[position];

holder.BindingContext = item.Data;

if (holder.Children[0] is not VirtualizeListViewCell cell) return;
Expand All @@ -256,9 +254,8 @@ public virtual void OnBindCell(CellHolder holder, int position)
OnItemAppearing(item, position);
}

public virtual void OnCellRecycled(CellHolder holder, int position)
public virtual void OnCellRecycled(CellHolder holder, AdapterItem item, int position)
{
var item = Items[position];
var content = holder.Children[0];

try
Expand Down
30 changes: 19 additions & 11 deletions MPowerKit.VirtualizeListView/GroupableDataAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ namespace MPowerKit.VirtualizeListView;

public class GroupableDataAdapter(VirtualizeListView listView) : DataAdapter(listView)
{
public class GroupItem(object group, object data) : AdapterItem(data)
public class GroupItem(IEnumerable group, object data) : AdapterItem(data)
{
public object Group { get; set; } = group;
}
public class GroupHeaderItem(object group) : GroupItem(group, group) { }
public class GroupFooterItem(object group) : GroupItem(group, group) { }
public class GroupHeaderItem(IEnumerable group) : GroupItem(group, group) { }
public class GroupFooterItem(IEnumerable group) : GroupItem(group, group) { }

protected IEnumerable<IEnumerable> GroupedItems { get; set; } = [];

Expand Down Expand Up @@ -393,27 +393,34 @@ protected virtual void GroupItemsAdd(IEnumerable group, NotifyCollectionChangedE
{
if (e.NewItems?.Count is null or 0) return;

var realGroupItemIndex = e.NewStartingIndex + GetFlattenedGroupIndexOfGroup(group) + HasGroupHeader.ToInt() - HasHeader.ToInt();
var realGroupItemIndex = e.NewStartingIndex + GetFlattenedGroupIndexOfGroup(group) + HasGroupHeader.ToInt();

base.OnCollectionChangedAdd(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, e.NewItems, realGroupItemIndex));
InternalItems.InsertRange(realGroupItemIndex, e.NewItems.Cast<object>().Select(d => new GroupItem(group, d)));
NotifyItemRangeInserted(realGroupItemIndex, e.NewItems.Count);
}

protected virtual void GroupItemsRemoved(IEnumerable group, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems?.Count is null or 0) return;

var realGroupItemIndex = e.OldStartingIndex + GetFlattenedGroupIndexOfGroup(group) + HasGroupHeader.ToInt() - HasHeader.ToInt();
var realGroupItemIndex = e.OldStartingIndex + GetFlattenedGroupIndexOfGroup(group) + HasGroupHeader.ToInt();

base.OnCollectionChangedRemove(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, e.OldItems, realGroupItemIndex));
var count = e.OldItems.Count;

InternalItems.RemoveRange(realGroupItemIndex, count);
NotifyItemRangeRemoved(realGroupItemIndex, count);
}

protected virtual void GroupItemsReplaced(IEnumerable group, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems?.Count is null or 0 || e.OldItems?.Count is null or 0) return;

var realGroupItemIndex = e.NewStartingIndex + GetFlattenedGroupIndexOfGroup(group) + HasGroupHeader.ToInt() - HasHeader.ToInt();
var realGroupItemIndex = e.NewStartingIndex + GetFlattenedGroupIndexOfGroup(group) + HasGroupHeader.ToInt();

InternalItems.RemoveRange(realGroupItemIndex, e.OldItems.Count);
InternalItems.InsertRange(realGroupItemIndex, e.NewItems.Cast<object>().Select(d => new GroupItem(group, d)));

base.OnCollectionChangedReplace(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, e.NewItems, e.OldItems, realGroupItemIndex));
NotifyItemRangeChanged(realGroupItemIndex, e.OldItems.Count, e.NewItems.Count);
}

private void GroupItemsMoved(IEnumerable group, NotifyCollectionChangedEventArgs e)
Expand All @@ -424,12 +431,13 @@ private void GroupItemsMoved(IEnumerable group, NotifyCollectionChangedEventArgs
return;
}

var realGroupStartIndex = GetFlattenedGroupIndexOfGroup(group) + HasGroupHeader.ToInt() - HasHeader.ToInt();
var realGroupStartIndex = GetFlattenedGroupIndexOfGroup(group) + HasGroupHeader.ToInt();

var newIndex = e.NewStartingIndex + realGroupStartIndex;
var oldIndex = e.OldStartingIndex + realGroupStartIndex;

base.OnCollectionChangedMove(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, e.NewItems[0], newIndex, oldIndex));
InternalItems.Move(oldIndex, newIndex);
NotifyItemMoved(oldIndex, newIndex);
}

private void GroupItemsReset(IEnumerable group, NotifyCollectionChangedEventArgs e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>MPowerKit.VirtualizeListView</Title>
<Version>1.2.1</Version>
<Version>1.2.2</Version>
<Authors>MPowerKit,Alex Dobrynin</Authors>
<Description>MAUI Virtualize ListView with smooth scrolling and without platform-specific code</Description>
<Copyright>MPowerKit</Copyright>
Expand Down
82 changes: 37 additions & 45 deletions MPowerKit.VirtualizeListView/VirtualizeItemsLayoutManger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,28 +218,23 @@ public virtual void InvalidateLayout()

if (!DoesScrollHaveSize()) return;

if (Control?.Adapter is null || Control.Adapter.Items.Count == 0) return;
if (Control?.Adapter?.ItemsCount is null or 0) return;

var dataItems = Control.Adapter.Items;
var count = dataItems.Count;
var count = Control.Adapter.ItemsCount;

var availableSpace = AvailableSpace;

for (int i = 0; i < count; i++)
{
var item = CreateItemForPosition(dataItems, i);
var item = CreateItemForPosition(i);

LaidOutItems.Add(item);

ShiftAllItems(LaidOutItems, i, LaidOutItems.Count);

if (!item.IsOnScreen) continue;

ReuseCell(item, true);

Control.Adapter.OnBindCell(item.Cell, item.Position);

ArrangeItem(LaidOutItems, item, AvailableSpace);

item.IsAttached = true;
ReuseCell(item, true, availableSpace);
}

CreateCachePool(CachePoolSize);
Expand Down Expand Up @@ -335,13 +330,11 @@ protected virtual void AdapterItemRangeInserted(object? sender, (int StartingInd
var firstVisibleItem = itemsToRearrange.FirstOrDefault();
var prevVisibleCellBounds = firstVisibleItem?.CellBounds ?? new();

var dataItems = Control.Adapter.Items;

List<VirtualizeListViewItem> newItems = new(e.TotalCount);

for (int index = startingIndex; index < finishIndex; index++)
{
var item = CreateItemForPosition(dataItems, index);
var item = CreateItemForPosition(index);

newItems.Add(item);
}
Expand Down Expand Up @@ -457,8 +450,6 @@ protected virtual void AdapterItemRangeChanged(object? sender, (int StartingInde
throw new ArgumentException("Invalid range");
}

var dataItems = Control.Adapter.Items;

var itemsToRemove = CollectionsMarshal.AsSpan(LaidOutItems[start..oldEnd]);
LaidOutItems.RemoveRange(start, oldCount);

Expand All @@ -478,7 +469,7 @@ protected virtual void AdapterItemRangeChanged(object? sender, (int StartingInde

for (int index = start; index < newEnd; index++)
{
var item = CreateItemForPosition(dataItems, index);
var item = CreateItemForPosition(index);

newItems.Add(item);
}
Expand Down Expand Up @@ -537,7 +528,7 @@ protected virtual void AdapterItemMoved(object? sender, (int OldIndex, int NewIn
var newIndex = e.NewIndex;
var oldIndex = e.OldIndex;

if (Control?.Adapter is null || Control.Adapter.Items.Count == 0
if (Control?.Adapter?.ItemsCount is null or 0
|| count == 0 || newIndex < 0 || newIndex >= count || oldIndex < 0
|| oldIndex >= count || oldIndex == newIndex)
{
Expand Down Expand Up @@ -635,17 +626,11 @@ protected virtual void UpdateItemsLayout(int fromPosition, bool shouldAdjustScro

if (!item.IsOnScreen || item.IsAttached) continue;

ReuseCell(item, true);

reused = true;

var prevBounds = item.Bounds;

control.Adapter.OnBindCell(item.Cell!, item.Position);

ArrangeItem(LaidOutItems, item, availableSpace);
ReuseCell(item, true, availableSpace);

item.IsAttached = true;
reused = true;

if (item.Bounds == prevBounds) continue;

Expand Down Expand Up @@ -678,7 +663,7 @@ protected virtual void DetachCell(VirtualizeListViewItem item)
{
if (!item.IsAttached || item.Cell is null) return;

Control!.Adapter.OnCellRecycled(item.Cell!, item.Position);
Control!.Adapter.OnCellRecycled(item.Cell!, item.AdapterItem, item.Position);
item.IsAttached = false;

CacheCell(item);
Expand All @@ -697,7 +682,7 @@ protected virtual void CacheCell(VirtualizeListViewItem item)
item.Cell = null;
}

protected virtual void ReuseCell(VirtualizeListViewItem item, bool createNewIfNoCached)
protected virtual void ReuseCell(VirtualizeListViewItem item, bool createNewIfNoCached, Size availableSpace)
{
if (item.Cell is not null) return;

Expand All @@ -713,23 +698,30 @@ protected virtual void ReuseCell(VirtualizeListViewItem item, bool createNewIfNo
cell.TranslationX = 0d;
cell.TranslationY = 0d;
#endif
return;
}

var freeItem = LaidOutItems.Find(i =>
(i.Template as IDataTemplateController).Id == (item.Template as IDataTemplateController).Id
&& !i.IsAttached && !i.IsOnScreen && i.Cell is not null);
if (freeItem is not null)
{
var cell = freeItem.Cell;
freeItem.Cell = null;
item.Cell = cell;
}
else if (createNewIfNoCached)
else
{
item.Cell = Control!.Adapter.OnCreateCell(item.Template, item.Position);
this.Add(item.Cell);
var freeItem = LaidOutItems.Find(i =>
(i.Template as IDataTemplateController).Id == (item.Template as IDataTemplateController).Id
&& !i.IsAttached && !i.IsOnScreen && i.Cell is not null);
if (freeItem is not null)
{
var cell = freeItem.Cell;
freeItem.Cell = null;
item.Cell = cell;
}
else if (createNewIfNoCached)
{
item.Cell = Control!.Adapter.OnCreateCell(item.Template, item.Position);
this.Add(item.Cell);
}
}

Control!.Adapter.OnBindCell(item.Cell!, item.AdapterItem, item.Position);

ArrangeItem(LaidOutItems, item, availableSpace);

item.IsAttached = true;
}

protected virtual void DrawAndResize()
Expand Down Expand Up @@ -769,12 +761,12 @@ protected virtual Size GetAvailableSpace()
return new Size(Control!.Width - Control.Padding.HorizontalThickness, Control.Height - Control.Padding.VerticalThickness);
}

protected virtual VirtualizeListViewItem CreateItemForPosition(IReadOnlyList<AdapterItem> dataItems, int position)
protected virtual VirtualizeListViewItem CreateItemForPosition(int position)
{
var item = new VirtualizeListViewItem(this)
{
AdapterItem = dataItems[position],
Template = Control!.Adapter.GetTemplate(position),
AdapterItem = Control!.Adapter.Items[position],
Template = Control.Adapter.GetTemplate(position),
Position = position
};

Expand Down

0 comments on commit 6ef7ae6

Please sign in to comment.