Skip to content

Commit

Permalink
fix(calendar): Fix scrolling issues on iOS (inc. allow ChangeView on …
Browse files Browse the repository at this point in the history
…SV when not yet arranged)
  • Loading branch information
dr1rrb committed Jun 1, 2021
1 parent 278c4e8 commit f9f463d
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,13 @@ private Size base_MeasureOverride(Size availableSize)
}

var viewport = GetLayoutViewport(availableSize);
if (Rows > 0 && Cols > 0)
{
// Uno: This SetViewportSize should be done in the CalendarPanel_Partial.ArrangeOverride of the Panel(not the 'base_'),
// but (due to invalid layouting event sequence in uno?) it would cause a second layout pass.
// Invoking it here makes sure that the ItemSize is valid for this measure pass.
_layoutStrategy.SetViewportSize(viewport.Size, out _);
}

_layoutStrategy.BeginMeasure();
#if __ANDROID__ // TODO: IOS
Expand All @@ -488,6 +495,7 @@ private Size base_MeasureOverride(Size availableSize)
ShouldInterceptInvalidate = true;
#endif
var index = -1;
var bottom = 0.0;
try
{
// Gets the index of the first element to render and the actual viewport to use
Expand Down Expand Up @@ -530,7 +538,9 @@ private Size base_MeasureOverride(Size availableSize)
var itemSize = _layoutStrategy.GetElementMeasureSize(ElementType.ItemContainer, index, renderWindow); // Note: It's actually the same for all items
var itemBounds = _layoutStrategy.GetElementBounds(ElementType.ItemContainer, index + StartIndex, itemSize, layout, renderWindow);

if (itemSize.Width < _minCellSize.Width && itemSize.Height < _minCellSize.Height || Cols == 0 || Rows == 0)
bottom = itemBounds.Bottom;

if ((itemSize.Width < _minCellSize.Width && itemSize.Height < _minCellSize.Height) || Cols == 0 || Rows == 0)
{
// We don't have any valid cell size yet (This measure pass has been caused by DetermineTheBiggestItemSize),
// so we stop right after having inserted the first child in the Children collection.
Expand Down Expand Up @@ -610,6 +620,12 @@ private Size base_MeasureOverride(Size availableSize)
default /* not used by CalendarLayoutStrategyImpl */,
out var desiredSize);

// When the StartIndex is greater than 0, the desiredSize might ignore the last line.
if (desiredSize.Height < bottom)
{
desiredSize.Height = bottom;
}

return desiredSize;
}

Expand Down Expand Up @@ -646,7 +662,7 @@ private static void OnEffectiveViewportChanged(FrameworkElement sender, Effectiv
{
that._effectiveViewport = args.EffectiveViewport;

if (that._host is null || that._layoutStrategy is null)
if (that._host is null || that._layoutStrategy is null || that.Cols == 0 || that.Rows == 0)
{
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,19 @@ partial class NativeScrollContentPresenter : UIScrollView, DependencyObject
/// </summary>
private bool _isInAnimatedScroll;

internal CGPoint UpperScrollLimit => (CGPoint)(ContentSize - Frame.Size);
CGPoint IUIScrollView.UpperScrollLimit => UpperScrollLimit;
internal CGPoint UpperScrollLimit
{
get
{
var extent = ContentSize;
var viewport = Frame.Size;

return new CGPoint(
Math.Max(0, extent.Width - viewport.Width),
Math.Max(0, extent.Height - viewport.Height));
}
}

internal NativeScrollContentPresenter(ScrollViewer scroller) : this()
{
Expand Down
32 changes: 27 additions & 5 deletions src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,46 @@ private void SetScrollableContainer()
}
}

private (double? horizontal, double? vertical, bool disableAnimation)? _pendingChangeView;

protected override void OnAfterArrange()
{
base.OnAfterArrange();

if (_pendingChangeView is {} req)
{
var success = ChangeViewNative(req.horizontal, req.vertical, null, req.disableAnimation);
if (success || !IsArrangeDirty)
{
_pendingChangeView = default;
}
}
}

private bool ChangeViewNative(double? horizontalOffset, double? verticalOffset, float? zoomFactor, bool disableAnimation)
{
if (_scrollableContainer != null)
{
// iOS doesn't limit the offset to the scrollable bounds by itself
var newOffset = new CGPoint(horizontalOffset ?? HorizontalOffset, verticalOffset ?? VerticalOffset)
.Clamp(CGPoint.Empty, _scrollableContainer.UpperScrollLimit);
var limit = _scrollableContainer.UpperScrollLimit;
var desiredOffsets = new Foundation.Point(horizontalOffset ?? HorizontalOffset, verticalOffset ?? VerticalOffset);
var clampedOffsets = new Foundation.Point(MathEx.Clamp(desiredOffsets.X, 0, limit.X), MathEx.Clamp(desiredOffsets.Y, 0, limit.Y));

var success = desiredOffsets == clampedOffsets;
if (!success && IsArrangeDirty)
{
_pendingChangeView = (horizontalOffset, verticalOffset, disableAnimation);
}

_scrollableContainer.SetContentOffset(newOffset, !disableAnimation);
_scrollableContainer.SetContentOffset(desiredOffsets, !disableAnimation);

if(zoomFactor is { } zoom)
{
ChangeViewZoom(zoom, disableAnimation);
}

// Return true if successfully scrolled to asked offsets
return (horizontalOffset == null || horizontalOffset == newOffset.X) &&
(verticalOffset == null || verticalOffset == newOffset.Y);
return success;
}

return false;
Expand Down

0 comments on commit f9f463d

Please sign in to comment.