Prevent application hang when rotating CollectionView with HTML Labels (#10622)
Fixes #8870
This commit is contained in:
Родитель
c986b70194
Коммит
21cb2595f6
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.Forms.Core.UITests;
|
||||
using Xamarin.UITest;
|
||||
using NUnit.Framework;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
#if UITEST
|
||||
[Category(UITestCategories.CollectionView)]
|
||||
#endif
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 8870, "[Bug] CollectionView with HTML Labels Freeze the Screen on Rotation",
|
||||
PlatformAffected.iOS)]
|
||||
public class Issue8870 : TestContentPage
|
||||
{
|
||||
public const string Success = "Success";
|
||||
public const string CheckResult = "Check";
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
#if APP
|
||||
var instructions = new Label { Text = "Rotate the device, then rotate it back 3 times. If the application crashes or hangs, this test has failed." };
|
||||
|
||||
var button = new Button { Text = CheckResult, AutomationId = CheckResult };
|
||||
button.Clicked += (sender, args) => { instructions.Text = Success; };
|
||||
|
||||
var source = new List<string>();
|
||||
for (int n = 0; n < 100; n++)
|
||||
{
|
||||
source.Add($"Item: {n}");
|
||||
}
|
||||
|
||||
var template = new DataTemplate(() => {
|
||||
var label = new Label
|
||||
{
|
||||
TextType = TextType.Html
|
||||
};
|
||||
|
||||
label.SetBinding(Label.TextProperty, new Binding(".", stringFormat: "<p style='background-color:red;'>{0}</p>"));
|
||||
|
||||
return label;
|
||||
});
|
||||
|
||||
var cv = new CollectionView()
|
||||
{
|
||||
ItemsSource = source,
|
||||
ItemTemplate = template
|
||||
};
|
||||
|
||||
var layout = new StackLayout();
|
||||
|
||||
layout.Children.Add(instructions);
|
||||
layout.Children.Add(button);
|
||||
layout.Children.Add(cv);
|
||||
|
||||
Content = layout;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UITEST
|
||||
[Test]
|
||||
public async Task RotatingCollectionViewWithHTMLShouldNotHangOrCrash()
|
||||
{
|
||||
int delay = 3000;
|
||||
|
||||
RunningApp.WaitForElement(CheckResult);
|
||||
|
||||
RunningApp.SetOrientationPortrait();
|
||||
await Task.Delay(delay);
|
||||
|
||||
RunningApp.SetOrientationLandscape();
|
||||
await Task.Delay(delay);
|
||||
|
||||
RunningApp.SetOrientationPortrait();
|
||||
await Task.Delay(delay);
|
||||
|
||||
RunningApp.SetOrientationLandscape();
|
||||
await Task.Delay(delay);
|
||||
|
||||
RunningApp.SetOrientationPortrait();
|
||||
await Task.Delay(delay);
|
||||
|
||||
RunningApp.WaitForElement(CheckResult);
|
||||
RunningApp.Tap(CheckResult);
|
||||
|
||||
RunningApp.WaitForElement(Success);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@
|
|||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8766.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8801.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8870.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue9428.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue9419.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8262.cs" />
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
|
@ -10,8 +11,10 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
protected readonly CarouselView Carousel;
|
||||
|
||||
bool _initialPositionSet;
|
||||
bool _viewInitialized;
|
||||
List<View> _oldViews;
|
||||
int _gotoPosition = -1;
|
||||
CGSize _size;
|
||||
|
||||
public CarouselViewController(CarouselView itemsView, ItemsViewLayout layout) : base(itemsView, layout)
|
||||
{
|
||||
|
@ -33,9 +36,27 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return cell;
|
||||
}
|
||||
|
||||
public override void ViewWillLayoutSubviews()
|
||||
{
|
||||
base.ViewWillLayoutSubviews();
|
||||
if (!_viewInitialized)
|
||||
{
|
||||
_viewInitialized = true;
|
||||
_size = CollectionView.Bounds.Size;
|
||||
}
|
||||
|
||||
UpdateVisualStates();
|
||||
}
|
||||
|
||||
public override void ViewDidLayoutSubviews()
|
||||
{
|
||||
base.ViewDidLayoutSubviews();
|
||||
if (CollectionView.Bounds.Size != _size)
|
||||
{
|
||||
_size = CollectionView.Bounds.Size;
|
||||
BoundsSizeChanged();
|
||||
}
|
||||
|
||||
UpdateInitialPosition();
|
||||
}
|
||||
|
||||
|
@ -83,9 +104,13 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return itemsSource;
|
||||
}
|
||||
|
||||
protected override void BoundsSizeChanged()
|
||||
protected void BoundsSizeChanged()
|
||||
{
|
||||
base.BoundsSizeChanged();
|
||||
ItemsViewLayout.ConstrainTo(CollectionView.Bounds.Size);
|
||||
|
||||
//We call ReloadData so our VisibleCells also update their size
|
||||
CollectionView.ReloadData();
|
||||
|
||||
Carousel.ScrollTo(Carousel.Position, position: Xamarin.Forms.ScrollToPosition.Center, animate: false);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
}
|
||||
}
|
||||
|
||||
internal void UpdateConstraints(CGSize size)
|
||||
internal override void UpdateConstraints(CGSize size)
|
||||
{
|
||||
ConstrainTo(size);
|
||||
UpdateCellConstraints();
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
kind, VerticalDefaultSupplementalView.ReuseId);
|
||||
}
|
||||
|
||||
public override UICollectionReusableView GetViewForSupplementaryElement(UICollectionView collectionView,
|
||||
public override UICollectionReusableView GetViewForSupplementaryElement(UICollectionView collectionView,
|
||||
NSString elementKind, NSIndexPath indexPath)
|
||||
{
|
||||
var reuseId = DetermineViewReuseId(elementKind);
|
||||
|
@ -132,6 +132,11 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
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)
|
||||
|
@ -140,6 +145,11 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
internal CGSize GetReferenceSizeForFooter(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
|
||||
{
|
||||
if (!_isGrouped)
|
||||
{
|
||||
return CGSize.Empty;
|
||||
}
|
||||
|
||||
return GetReferenceSizeForheaderOrFooter(collectionView, ItemsView.GroupFooterTemplate, UICollectionElementKindSectionKey.Footer, section);
|
||||
}
|
||||
|
||||
|
@ -207,21 +217,21 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
if (scrollDirection == UICollectionViewScrollDirection.Horizontal)
|
||||
{
|
||||
return new UIEdgeInsets(itemSpacing + uIEdgeInsets.Top, lineSpacing + uIEdgeInsets.Left,
|
||||
return new UIEdgeInsets(itemSpacing + uIEdgeInsets.Top, lineSpacing + uIEdgeInsets.Left,
|
||||
uIEdgeInsets.Bottom, uIEdgeInsets.Right);
|
||||
}
|
||||
|
||||
return new UIEdgeInsets(lineSpacing + uIEdgeInsets.Top, itemSpacing + uIEdgeInsets.Left,
|
||||
return new UIEdgeInsets(lineSpacing + uIEdgeInsets.Top, itemSpacing + uIEdgeInsets.Left,
|
||||
uIEdgeInsets.Bottom, uIEdgeInsets.Right);
|
||||
}
|
||||
|
||||
if (scrollDirection == UICollectionViewScrollDirection.Horizontal)
|
||||
{
|
||||
return new UIEdgeInsets(uIEdgeInsets.Top, lineSpacing + uIEdgeInsets.Left,
|
||||
return new UIEdgeInsets(uIEdgeInsets.Top, lineSpacing + uIEdgeInsets.Left,
|
||||
uIEdgeInsets.Bottom, uIEdgeInsets.Right);
|
||||
}
|
||||
|
||||
return new UIEdgeInsets(lineSpacing + uIEdgeInsets.Top, uIEdgeInsets.Left,
|
||||
return new UIEdgeInsets(lineSpacing + uIEdgeInsets.Top, uIEdgeInsets.Left,
|
||||
uIEdgeInsets.Bottom, uIEdgeInsets.Right);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
public override void ConstrainTo(CGSize constraint)
|
||||
{
|
||||
base.ConstrainTo(constraint);
|
||||
|
||||
ClearConstraints();
|
||||
ConstrainedDimension = constraint.Height;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
|
@ -12,6 +13,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
public HorizontalDefaultCell(CGRect frame) : base(frame)
|
||||
{
|
||||
Constraint = Label.HeightAnchor.ConstraintEqualTo(Frame.Height);
|
||||
Constraint.Priority = (float)UILayoutPriority.DefaultHigh;
|
||||
Constraint.Active = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
Label.Font = UIFont.PreferredHeadline;
|
||||
|
||||
Constraint = Label.HeightAnchor.ConstraintEqualTo(Frame.Height);
|
||||
Constraint.Priority = (float)UILayoutPriority.DefaultHigh;
|
||||
Constraint.Active = true;
|
||||
}
|
||||
|
||||
|
@ -28,5 +29,4 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return new CGSize(Label.IntrinsicContentSize.Width, Constraint.Constant);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -18,8 +18,6 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
bool _emptyViewDisplayed;
|
||||
bool _disposed;
|
||||
|
||||
CGSize _size;
|
||||
|
||||
UIView _emptyUIView;
|
||||
VisualElement _emptyViewFormsElement;
|
||||
|
||||
|
@ -144,15 +142,14 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
public override void ViewWillLayoutSubviews()
|
||||
{
|
||||
base.ViewWillLayoutSubviews();
|
||||
|
||||
|
||||
// We can't set this constraint up on ViewDidLoad, because Forms does other stuff that resizes the view
|
||||
// and we end up with massive layout errors. And View[Will/Did]Appear do not fire for this controller
|
||||
// reliably. So until one of those options is cleared up, we set this flag so that the initial constraints
|
||||
// are set up the first time this method is called.
|
||||
if (!_initialConstraintsSet)
|
||||
{
|
||||
_size = CollectionView.Bounds.Size;
|
||||
ItemsViewLayout.ConstrainTo(_size);
|
||||
ItemsViewLayout.SetInitialConstraints(CollectionView.Bounds.Size);
|
||||
UpdateEmptyView();
|
||||
_initialConstraintsSet = true;
|
||||
}
|
||||
|
@ -162,26 +159,6 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public override void ViewDidLayoutSubviews()
|
||||
{
|
||||
base.ViewDidLayoutSubviews();
|
||||
if (CollectionView.Bounds.Size != _size)
|
||||
{
|
||||
_size = CollectionView.Bounds.Size;
|
||||
BoundsSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void BoundsSizeChanged()
|
||||
{
|
||||
//We are changing orientation and we need to tell our layout
|
||||
//to update based on new size constrains
|
||||
ItemsViewLayout.ConstrainTo(CollectionView.Bounds.Size);
|
||||
//We call ReloadData so our VisibleCells also update their size
|
||||
CollectionView.ReloadData();
|
||||
}
|
||||
|
||||
protected virtual UICollectionViewDelegateFlowLayout CreateDelegator()
|
||||
{
|
||||
return new ItemsViewDelegator<TItemsView, ItemsViewController<TItemsView>>(ItemsViewLayout, this);
|
||||
|
@ -225,7 +202,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
ItemsViewLayout.PrepareCellForLayout(cell);
|
||||
}
|
||||
|
||||
|
||||
public virtual NSIndexPath GetIndexForItem(object item)
|
||||
{
|
||||
return ItemsSource.GetIndexForItem(item);
|
||||
|
@ -411,5 +388,6 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
_emptyViewDisplayed = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
public abstract class ItemsViewLayout : UICollectionViewFlowLayout
|
||||
{
|
||||
readonly ItemsLayout _itemsLayout;
|
||||
bool _determiningCellSize;
|
||||
bool _disposed;
|
||||
bool _adjustContentOffset;
|
||||
CGSize _adjustmentSize0;
|
||||
CGSize _adjustmentSize1;
|
||||
CGSize _currentSize;
|
||||
|
||||
public ItemsUpdatingScrollMode ItemsUpdatingScrollMode { get; set; }
|
||||
|
||||
|
@ -81,6 +81,27 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
}
|
||||
}
|
||||
|
||||
internal virtual void UpdateConstraints(CGSize size)
|
||||
{
|
||||
if (size == _currentSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_currentSize = size;
|
||||
|
||||
var newSize = new CGSize(Math.Floor(size.Width), Math.Floor(size.Height));
|
||||
ConstrainTo(newSize);
|
||||
|
||||
UpdateCellConstraints();
|
||||
}
|
||||
|
||||
internal void SetInitialConstraints(CGSize size)
|
||||
{
|
||||
_currentSize = size;
|
||||
ConstrainTo(size);
|
||||
}
|
||||
|
||||
public abstract void ConstrainTo(CGSize size);
|
||||
|
||||
public virtual UIEdgeInsets GetInsetForSection(UICollectionView collectionView, UICollectionViewLayout layout,
|
||||
|
@ -138,11 +159,6 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
public void PrepareCellForLayout(ItemsViewCell cell)
|
||||
{
|
||||
if (_determiningCellSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (EstimatedItemSize == CGSize.Empty)
|
||||
{
|
||||
cell.ConstrainTo(ItemSize);
|
||||
|
@ -153,18 +169,6 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
}
|
||||
}
|
||||
|
||||
public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds)
|
||||
{
|
||||
var shouldInvalidate = base.ShouldInvalidateLayoutForBoundsChange(newBounds);
|
||||
|
||||
if (shouldInvalidate)
|
||||
{
|
||||
UpdateConstraints(newBounds.Size);
|
||||
}
|
||||
|
||||
return shouldInvalidate;
|
||||
}
|
||||
|
||||
public override bool ShouldInvalidateLayout(UICollectionViewLayoutAttributes preferredAttributes, UICollectionViewLayoutAttributes originalAttributes)
|
||||
{
|
||||
if (ItemSizingStrategy == ItemSizingStrategy.MeasureAllItems)
|
||||
|
@ -198,8 +202,6 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return;
|
||||
}
|
||||
|
||||
_determiningCellSize = true;
|
||||
|
||||
// We set the EstimatedItemSize here for two reasons:
|
||||
// 1. If we don't set it, iOS versions below 10 will crash
|
||||
// 2. If GetPrototype() cannot return a cell because the items source is empty, we need to have
|
||||
|
@ -208,15 +210,25 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
// If GetPrototype() _can_ return a cell, this estimate will be updated once that cell is measured
|
||||
EstimatedItemSize = new CGSize(1, 1);
|
||||
|
||||
if (!(GetPrototype() is ItemsViewCell prototype))
|
||||
ItemsViewCell prototype = null;
|
||||
|
||||
if (CollectionView?.VisibleCells.Length > 0)
|
||||
{
|
||||
prototype = CollectionView.VisibleCells[0] as ItemsViewCell;
|
||||
}
|
||||
|
||||
if (prototype == null)
|
||||
{
|
||||
prototype = GetPrototype() as ItemsViewCell;
|
||||
}
|
||||
|
||||
if (prototype == null)
|
||||
{
|
||||
_determiningCellSize = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Constrain and measure the prototype cell
|
||||
prototype.ConstrainTo(ConstrainedDimension);
|
||||
|
||||
var measure = prototype.Measure();
|
||||
|
||||
if (ItemSizingStrategy == ItemSizingStrategy.MeasureFirstItem)
|
||||
|
@ -232,18 +244,6 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
// Autolayout is now enabled, and this is the size used to guess scrollbar size and progress
|
||||
EstimatedItemSize = measure;
|
||||
}
|
||||
|
||||
_determiningCellSize = false;
|
||||
}
|
||||
|
||||
bool ConstraintsMatchScrollDirection(CGSize size)
|
||||
{
|
||||
if (ScrollDirection == UICollectionViewScrollDirection.Vertical)
|
||||
{
|
||||
return ConstrainedDimension == size.Width;
|
||||
}
|
||||
|
||||
return ConstrainedDimension == size.Height;
|
||||
}
|
||||
|
||||
void Initialize(UICollectionViewScrollDirection scrollDirection)
|
||||
|
@ -251,10 +251,15 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
ScrollDirection = scrollDirection;
|
||||
}
|
||||
|
||||
internal void UpdateCellConstraints()
|
||||
protected void UpdateCellConstraints()
|
||||
{
|
||||
var cells = CollectionView.VisibleCells;
|
||||
PrepareCellsForLayout(CollectionView.VisibleCells);
|
||||
PrepareCellsForLayout(CollectionView.GetVisibleSupplementaryViews(UICollectionElementKindSectionKey.Header));
|
||||
PrepareCellsForLayout(CollectionView.GetVisibleSupplementaryViews(UICollectionElementKindSectionKey.Footer));
|
||||
}
|
||||
|
||||
void PrepareCellsForLayout(UICollectionReusableView[] cells)
|
||||
{
|
||||
for (int n = 0; n < cells.Length; n++)
|
||||
{
|
||||
if (cells[n] is ItemsViewCell constrainedCell)
|
||||
|
@ -264,17 +269,6 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
}
|
||||
}
|
||||
|
||||
void UpdateConstraints(CGSize size)
|
||||
{
|
||||
if (ConstraintsMatchScrollDirection(size))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ConstrainTo(size);
|
||||
UpdateCellConstraints();
|
||||
}
|
||||
|
||||
public override CGPoint TargetContentOffset(CGPoint proposedContentOffset, CGPoint scrollingVelocity)
|
||||
{
|
||||
var snapPointsType = _itemsLayout.SnapPointsType;
|
||||
|
@ -384,43 +378,31 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
public override UICollectionViewLayoutInvalidationContext GetInvalidationContext(UICollectionViewLayoutAttributes preferredAttributes, UICollectionViewLayoutAttributes originalAttributes)
|
||||
{
|
||||
if (Forms.IsiOS11OrNewer)
|
||||
if (preferredAttributes.RepresentedElementKind != UICollectionElementKindSectionKey.Header
|
||||
&& preferredAttributes.RepresentedElementKind != UICollectionElementKindSectionKey.Footer)
|
||||
{
|
||||
return base.GetInvalidationContext(preferredAttributes, originalAttributes);
|
||||
}
|
||||
|
||||
|
||||
// Ensure that if this invalidation was triggered by header/footer changes, the header/footer are being invalidated
|
||||
|
||||
UICollectionViewFlowLayoutInvalidationContext invalidationContext = new UICollectionViewFlowLayoutInvalidationContext();
|
||||
var indexPath = preferredAttributes.IndexPath;
|
||||
|
||||
try
|
||||
if (preferredAttributes.RepresentedElementKind == UICollectionElementKindSectionKey.Header)
|
||||
{
|
||||
UICollectionViewLayoutInvalidationContext invalidationContext =
|
||||
base.GetInvalidationContext(preferredAttributes, originalAttributes);
|
||||
|
||||
// Ensure that if this invalidation was triggered by header/footer changes, the header/footer
|
||||
// are being invalidated
|
||||
if (preferredAttributes.RepresentedElementKind == UICollectionElementKindSectionKey.Header)
|
||||
{
|
||||
invalidationContext.InvalidateSupplementaryElements(UICollectionElementKindSectionKey.Header,
|
||||
new[] { indexPath });
|
||||
}
|
||||
else if (preferredAttributes.RepresentedElementKind == UICollectionElementKindSectionKey.Footer)
|
||||
{
|
||||
invalidationContext.InvalidateSupplementaryElements(UICollectionElementKindSectionKey.Footer,
|
||||
new[] { indexPath });
|
||||
}
|
||||
|
||||
return invalidationContext;
|
||||
invalidationContext.InvalidateSupplementaryElements(UICollectionElementKindSectionKey.Header, new[] { indexPath });
|
||||
}
|
||||
catch (MonoTouchException)
|
||||
else if (preferredAttributes.RepresentedElementKind == UICollectionElementKindSectionKey.Footer)
|
||||
{
|
||||
// This happens on iOS 10 if we have any empty groups in our ItemsSource. Catching here and
|
||||
// returning a UICollectionViewFlowLayoutInvalidationContext means that the application does not
|
||||
// crash, though any group headers/footers will initially draw in the wrong location. It's possible to
|
||||
// work around this problem by forcing a full layout update after the headers/footers have been
|
||||
// drawn in the wrong places
|
||||
invalidationContext.InvalidateSupplementaryElements(UICollectionElementKindSectionKey.Footer, new[] { indexPath });
|
||||
}
|
||||
|
||||
return new UICollectionViewFlowLayoutInvalidationContext();
|
||||
return invalidationContext;
|
||||
|
||||
// On iOS 10 though any group headers/footers will initially draw in the wrong location. It's possible to
|
||||
// work around this problem by forcing a full layout update after the headers/footers have been
|
||||
// drawn in the wrong places
|
||||
}
|
||||
|
||||
public override UICollectionViewLayoutAttributes LayoutAttributesForSupplementaryView(NSString kind, NSIndexPath indexPath)
|
||||
|
@ -574,5 +556,21 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds)
|
||||
{
|
||||
if (newBounds.Size == _currentSize)
|
||||
{
|
||||
return base.ShouldInvalidateLayoutForBoundsChange(newBounds);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void InvalidateLayout()
|
||||
{
|
||||
UpdateConstraints(CollectionView.Frame.Size);
|
||||
base.InvalidateLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,16 +30,20 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
public override void ConstrainTo(CGSize constraint)
|
||||
{
|
||||
ClearConstraints();
|
||||
ConstrainedSize = constraint;
|
||||
}
|
||||
|
||||
public override void ConstrainTo(nfloat constant)
|
||||
{
|
||||
ClearConstraints();
|
||||
ConstrainedDimension = constant;
|
||||
|
||||
// Reset constrained size in case ItemSizingStrategy changes
|
||||
// and we want to measure each item
|
||||
ConstrainedSize = default(CGSize);
|
||||
}
|
||||
|
||||
protected void ClearConstraints()
|
||||
{
|
||||
ConstrainedSize = default;
|
||||
ConstrainedDimension = default;
|
||||
}
|
||||
|
||||
public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittingAttributes(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
|
@ -12,6 +13,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
public VerticalDefaultCell(CGRect frame) : base(frame)
|
||||
{
|
||||
Constraint = Label.WidthAnchor.ConstraintEqualTo(Frame.Width);
|
||||
Constraint.Priority = (float)UILayoutPriority.DefaultHigh;
|
||||
Constraint.Active = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
Label.Font = UIFont.PreferredHeadline;
|
||||
|
||||
Constraint = Label.WidthAnchor.ConstraintEqualTo(Frame.Width);
|
||||
Constraint.Priority = (float)UILayoutPriority.DefaultHigh;
|
||||
Constraint.Active = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
public override void ConstrainTo(CGSize constraint)
|
||||
{
|
||||
base.ConstrainTo(constraint);
|
||||
|
||||
ClearConstraints();
|
||||
ConstrainedDimension = constraint.Width;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
#if __MOBILE__
|
||||
|
@ -90,7 +91,7 @@ namespace Xamarin.Forms.Platform.MacOS
|
|||
Performance.Start(out string reference);
|
||||
if (CompressedLayout.GetIsHeadless(view))
|
||||
{
|
||||
var packager = new VisualElementPackager(Renderer, view, isHeadless:true);
|
||||
var packager = new VisualElementPackager(Renderer, view, isHeadless: true);
|
||||
view.IsPlatformEnabled = true;
|
||||
packager.Load();
|
||||
}
|
||||
|
@ -107,6 +108,7 @@ namespace Xamarin.Forms.Platform.MacOS
|
|||
|
||||
EnsureChildrenOrder();
|
||||
}
|
||||
|
||||
Performance.Stop(reference);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче