Skip to content

Commit

Permalink
Apply iOS 10 9686 fixes from 4.7 to 4.6 (xamarin#10963)
Browse files Browse the repository at this point in the history
  • Loading branch information
hartez authored Jun 5, 2020
1 parent 9093591 commit 173803d
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ public class GroupableItemsViewController<TItemsView> : SelectableItemsViewContr
// BindableProperty all the time
bool _isGrouped;

// Keep out header measurement cells for iOS handy so we don't have to
// create new ones all the time. For other versions, the reusable cells
// queueing mechanism does this for us.
TemplatedCell _measurementCellTemplated;
DefaultCell _measurementCellDefault;

Action _scrollAnimationEndedCallback;

public GroupableItemsViewController(TItemsView groupableItemsView, ItemsViewLayout layout)
Expand Down Expand Up @@ -132,6 +138,11 @@ string DetermineViewReuseId(DataTemplate template)

internal CGSize GetReferenceSizeForHeader(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
{
if (!_isGrouped)
{
return CGSize.Empty;
}

// Currently we explicitly measure all of the headers/footers
// Long-term, we might want to look at performance hints (similar to ItemSizingStrategy) for
// headers/footers (if the dev knows for sure they'll all the be the same size)
Expand All @@ -140,6 +151,11 @@ internal CGSize GetReferenceSizeForHeader(UICollectionView collectionView, UICol

internal CGSize GetReferenceSizeForFooter(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
{
if (!_isGrouped)
{
return CGSize.Empty;
}

return GetReferenceSizeForheaderOrFooter(collectionView, ItemsView.GroupFooterTemplate, UICollectionElementKindSectionKey.Footer, section);
}

Expand All @@ -150,11 +166,18 @@ internal CGSize GetReferenceSizeForheaderOrFooter(UICollectionView collectionVie
return CGSize.Empty;
}

if (ItemsSource.GroupCount < 1)
if (ItemsSource.GroupCount < 1 || section > ItemsSource.GroupCount - 1)
{
return CGSize.Empty;
}

if (!Forms.IsiOS11OrNewer)
{
// iOS 10 crashes if we try to dequeue a cell for measurement
// so we'll use an alternate method
return MeasureSupplementaryView(elementKind, section);
}

var cell = GetViewForSupplementaryElement(collectionView, elementKind,
NSIndexPath.FromItemSection(0, section)) as ItemsViewCell;

Expand Down Expand Up @@ -224,5 +247,71 @@ internal UIEdgeInsets GetInsetForSection(ItemsViewLayout itemsViewLayout,
return new UIEdgeInsets(lineSpacing + uIEdgeInsets.Top, uIEdgeInsets.Left,
uIEdgeInsets.Bottom, uIEdgeInsets.Right);
}


// These measurement methods are only necessary for iOS 10 and lower

CGSize MeasureTemplatedSupplementaryCell(NSString elementKind, nint section, NSString reuseId)
{


if (_measurementCellTemplated == null)
{
if (reuseId == HorizontalSupplementaryView.ReuseId)
{
_measurementCellTemplated = new HorizontalSupplementaryView(CGRect.Empty);
}
else if (reuseId == VerticalSupplementaryView.ReuseId)
{
_measurementCellTemplated = new VerticalSupplementaryView(CGRect.Empty);
}
}

if (_measurementCellTemplated == null)
{
return CGSize.Empty;
}

UpdateTemplatedSupplementaryView(_measurementCellTemplated, elementKind, NSIndexPath.FromItemSection(0, section));
return _measurementCellTemplated.Measure();
}

CGSize MeasureDefaultSupplementaryCell(NSString elementKind, nint section, NSString reuseId)
{
if (_measurementCellDefault == null)
{
if (reuseId == HorizontalDefaultSupplementalView.ReuseId)
{
_measurementCellDefault = new HorizontalDefaultSupplementalView(CGRect.Empty);
}
else if (reuseId == VerticalDefaultSupplementalView.ReuseId)
{
_measurementCellDefault = new VerticalDefaultSupplementalView(CGRect.Empty);
}
}

if (_measurementCellDefault == null)
{
return CGSize.Empty;
}

UpdateDefaultSupplementaryView(_measurementCellDefault, elementKind, NSIndexPath.FromItemSection(0, section));
return _measurementCellDefault.Measure();
}

CGSize MeasureSupplementaryView(NSString elementKind, nint section)
{
var reuseId = (NSString)DetermineViewReuseId(elementKind);

if (reuseId == HorizontalDefaultSupplementalView.ReuseId
|| reuseId == VerticalDefaultSupplementalView.ReuseId)
{
return MeasureDefaultSupplementaryCell(elementKind, section, reuseId);
}

return MeasureTemplatedSupplementaryCell(elementKind, section, reuseId);
}

// end of iOS 10 workaround stuff
}
}
25 changes: 0 additions & 25 deletions Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,19 +175,6 @@ public override bool ShouldInvalidateLayout(UICollectionViewLayoutAttributes pre
}
}

if (Forms.IsiOS11OrNewer)
{
return base.ShouldInvalidateLayout(preferredAttributes, originalAttributes);
}

// For iOS 10 and lower, we have to invalidate on header/footer changes here; otherwise, all of the
// headers and footers will draw on top of one another
if (preferredAttributes.RepresentedElementKind == UICollectionElementKindSectionKey.Header
|| preferredAttributes.RepresentedElementKind == UICollectionElementKindSectionKey.Footer)
{
return true;
}

return base.ShouldInvalidateLayout(preferredAttributes, originalAttributes);
}

Expand Down Expand Up @@ -423,18 +410,6 @@ public override UICollectionViewLayoutInvalidationContext GetInvalidationContext
return new UICollectionViewFlowLayoutInvalidationContext();
}

public override UICollectionViewLayoutAttributes LayoutAttributesForSupplementaryView(NSString kind, NSIndexPath indexPath)
{
if (Forms.IsiOS11OrNewer)
{
return base.LayoutAttributesForSupplementaryView(kind, indexPath);
}

// iOS 10 and lower doesn't create these and will throw an exception in GetViewForSupplementaryElement
// without them, so we need to do it manually here
return UICollectionViewLayoutAttributes.CreateForSupplementaryView(kind, indexPath);
}

public override void PrepareLayout()
{
base.PrepareLayout();
Expand Down

0 comments on commit 173803d

Please sign in to comment.