Skip to content

Commit

Permalink
实现GridLayout的ScrollTo
Browse files Browse the repository at this point in the history
  • Loading branch information
xtuzy committed Sep 14, 2023
1 parent 6de2748 commit fae204f
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 178 deletions.
10 changes: 5 additions & 5 deletions DemoTest/Pages/DefaultTestPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public DefaultTestPage()
var headerButton = new Button() { Text = "Header GoTo End", VerticalOptions = LayoutOptions.Center, HorizontalOptions = LayoutOptions.Center };
headerButton.Clicked += (s, e) =>
{
tableView.ScrollToItem(NSIndexPath.FromRowSection(10, ViewModel.Instance.models.Count - 1), ScrollPosition.Top, true);
tableView.ScrollToItem(NSIndexPath.FromRowSection(ViewModel.Instance.models[ViewModel.Instance.models.Count - 1].Count - 10, ViewModel.Instance.models.Count - 1), ScrollPosition.Top, false);
Debug.WriteLine("Clicked Header");
};
var headerView = new MAUICollectionViewViewHolder(headerButton, "Header");
Expand All @@ -85,7 +85,7 @@ public DefaultTestPage()
var footerButton = new Button() { Text = "Footer GoTo Start", VerticalOptions = LayoutOptions.Center, HorizontalOptions = LayoutOptions.Center };
footerButton.Clicked += (s, e) =>
{
tableView.ScrollToItem(NSIndexPath.FromRowSection(10, 0), ScrollPosition.Top, true);
tableView.ScrollToItem(NSIndexPath.FromRowSection(10, 0), ScrollPosition.Top, false);
Debug.WriteLine("Clicked Footer");
};
var footActivityIndicator = new ActivityIndicator() { Color = Colors.Red, IsVisible = false, IsRunning = false, VerticalOptions = LayoutOptions.Center, HorizontalOptions = LayoutOptions.Center };
Expand Down Expand Up @@ -152,10 +152,10 @@ public DefaultTestPage()

ChangeLayout.Clicked += (sender, e) =>
{
if (tableView.ItemsLayout is CollectionViewFlatListLayout)
tableView.ItemsLayout = new CollectionViewGridLayout(tableView);
else
if (tableView.ItemsLayout is CollectionViewGridLayout)
tableView.ItemsLayout = new CollectionViewFlatListLayout(tableView);
else
tableView.ItemsLayout = new CollectionViewGridLayout(tableView);
tableView.ReMeasure();
};

Expand Down
60 changes: 35 additions & 25 deletions MauiUICollectionView/Layouts/CollectionViewFlatListLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,26 @@ public CollectionViewFlatListLayout(MAUICollectionView collectionView) : base(co
{
}

#region Property or Field

/// <summary>
/// When jump to specify position, we use this tag tell <see cref="MeasureItems"/> if remeasure all item.
/// </summary>
protected bool isScrollingTo = false;

/// <summary>
/// store bounds of items at start in list.
/// </summary>
protected List<Rect> StartBoundsCache = new List<Rect> { };

#endregion

#region Method

protected override double MeasureItems(double top, Rect inRect, Rect visibleRect, Dictionary<NSIndexPath, MAUICollectionViewViewHolder> availablePreparedItems)
{
if (CollectionView.IsScrolling &&
isScrollToDirectly == false &&
isScrollingTo == false &&
!HasOperation)
{
//MeasureItemsWhenScroll(inRect, availablePreparedItems);
Expand All @@ -18,8 +34,8 @@ protected override double MeasureItems(double top, Rect inRect, Rect visibleRect
else
{
MeasureItems(top, inRect, availablePreparedItems);
if (isScrollToDirectly)
isScrollToDirectly = false;
if (isScrollingTo)
isScrollingTo = false;
if (BaseLineItemUsually != null)
BaseLineItemUsually = null;
}
Expand Down Expand Up @@ -114,7 +130,7 @@ protected virtual void MeasureItems(double top, Rect inRect, Dictionary<NSIndexP
{
OnLayoutChildren(inRect, new LayoutInfor()
{
StartItem = EstimateItem(CollectionView.ScrollY),
StartItem = EstimateItem(0, CollectionView.ScrollY),
StartBounds = new Rect(0, CollectionView.ScrollY, 0, 0),
}, availablePreparedItems, isRemeasureAll);
}
Expand Down Expand Up @@ -142,9 +158,9 @@ protected virtual double EstimateAverageHeight()
/// <summary>
/// Estimate the item displayed when scrolling to a certain position.
/// </summary>
/// <param name="scrollY"></param>
/// <param name="y"></param>
/// <returns></returns>
protected virtual NSIndexPath EstimateItem(double scrollY)
protected virtual NSIndexPath EstimateItem(double x, double y)
{
var firstItemBounds = StartBoundsCache.First();
double averageHeight = EstimateAverageHeight();
Expand All @@ -154,9 +170,9 @@ protected virtual NSIndexPath EstimateItem(double scrollY)
for (var section = 0; section < numberOfSections; section++)
{
var rowsInSection = CollectionView.NumberOfItemsInSection(section);
if (scrollY - firstItemBounds.Top < allHeight + rowsInSection * averageHeight)
if (y - firstItemBounds.Top < allHeight + rowsInSection * averageHeight)
{
return NSIndexPath.FromRowSection((int)((scrollY - firstItemBounds.Top - allHeight) / averageHeight), section);
return NSIndexPath.FromRowSection((int)((y - firstItemBounds.Top - allHeight) / averageHeight), section);
}
else
{
Expand Down Expand Up @@ -360,17 +376,12 @@ void LayoutFromBottomToTop(LayoutInfor bottomBaselineInfor)
}
}

/// <summary>
/// When jump to specify position, we need this avoid use <see cref="ScrollByOffset"/>.
/// </summary>
bool isScrollToDirectly = false;

/// <summary>
/// Jump to specify item immediately, no animation.
/// </summary>
/// <param name="targetIndexPath"></param>
/// <param name="animated"></param>
void ScrollToItem(NSIndexPath targetIndexPath)
protected virtual void ScrollToItem(NSIndexPath targetIndexPath)
{
/*
* Estimate position of item, and set ScrollY
Expand All @@ -384,7 +395,7 @@ void ScrollToItem(NSIndexPath targetIndexPath)
itemsOffset += CollectionView.ItemCountInRange(lastPreparedItem.Key, targetIndexPath) * lastPreparedItem.Value.ItemBounds.Height;
BaseLineItemUsually = new LayoutInfor()
{
EndBounds = new Rect(0, 0, 0, CollectionView.ScrollY + itemsOffset + CollectionView.Bounds.Height),
EndBounds = new Rect(0, 0, 0, CollectionView.ScrollY + itemsOffset + CollectionView.Bounds.Height), //set this item at bottom of visible area.
EndItem = targetIndexPath
};
CollectionView.ScrollToAsync(0, CollectionView.ScrollY + itemsOffset, false);
Expand All @@ -402,14 +413,8 @@ void ScrollToItem(NSIndexPath targetIndexPath)
};
CollectionView.ScrollToAsync(0, CollectionView.ScrollY - distanceFromTargetToFirstPrepared, false);
}
isScrollToDirectly = true;
}

/// <summary>
/// store bounds of items at start in list.
/// </summary>
protected List<Rect> StartBoundsCache = new List<Rect> { };

/// <summary>
/// this layout support go to, so item's position is not accurate sometimes, we need adjust position to fit header's position.
/// </summary>
Expand Down Expand Up @@ -476,7 +481,7 @@ void FitBoundsWhenCloseHeader(LayoutInfor visibleItems)
StartBounds = new Rect(0, targetBounds.Top, 0, 0),
StartItem = visibleFirst
};
isScrollToDirectly = true;
isScrollingTo = true;
CollectionView.ScrollToAsync(0, targetBounds.Top, false);
}
}
Expand All @@ -489,7 +494,7 @@ void FitBoundsWhenCloseHeader(LayoutInfor visibleItems)
StartBounds = new Rect(0, targetTop, 0, 0),
StartItem = visibleFirst
};
isScrollToDirectly = true;
isScrollingTo = true;
CollectionView.ScrollToAsync(0, targetTop, false);
}
}
Expand All @@ -508,7 +513,7 @@ void FitBoundsWhenCloseHeader(LayoutInfor visibleItems)
StartBounds = new Rect(0, StartBoundsCache[0].Top, 0, 0),
StartItem = firstItem
};
isScrollToDirectly = true;
isScrollingTo = true;
CollectionView.ScrollToAsync(0, StartBoundsCache[0].Top, false);
}
}
Expand All @@ -534,15 +539,18 @@ public override void ScrollTo(NSIndexPath indexPath, ScrollPosition scrollPositi
}
ScrollToItem(target);
isScrollingTo = true;
}, 0, end);
anim.Commit(CollectionView, "ScrollTo", 16, 250, null, (v, b) =>
{
ScrollToItem(indexPath);
isScrollingTo = true;
});
}
else
{
ScrollToItem(indexPath);
isScrollingTo = true;
}
}

Expand All @@ -565,7 +573,7 @@ public override Rect RectForItem(NSIndexPath indexPath)
var itemViewHolder = item.Value;
if (indexPath < itemIndexPath)
{
var count = CollectionView.ItemCountInRange(indexPath, itemIndexPath) + 1;
var count = CollectionView.ItemCountInRange(indexPath, itemIndexPath) + 1;//we need get top, so total height include height of target item, so +1.
double averageHeight = EstimateAverageHeight();
var allItemHeight = count * averageHeight;
return new Rect(0, itemViewHolder.ItemBounds.Top - allItemHeight, itemViewHolder.ItemBounds.Width, averageHeight);
Expand All @@ -585,5 +593,7 @@ public override Rect RectForItem(NSIndexPath indexPath)
}
return rect;
}

#endregion
}
}
Loading

0 comments on commit fae204f

Please sign in to comment.