Skip to content

Commit

Permalink
Merge pull request #7412 from unoplatform/mergify/bp/release/beta/3.1…
Browse files Browse the repository at this point in the history
…1/pr-7402

fix(calendar): Fix miscs scrolling issues (backport #7402)
  • Loading branch information
jeromelaban authored Nov 1, 2021
2 parents 1eaf7c7 + 614fe55 commit d3cc1d4
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1120,12 +1120,12 @@ public EVPTreeListener(FrameworkElement root, FrameworkElement leaf)
_root = root;
_leaf = leaf;

leaf.Loaded += ElementLoaded;
leaf.Loading += ElementLoading;
}

private void ElementLoaded(object sender, RoutedEventArgs e)
private void ElementLoading(object sender, object args)
{
_leaf.Loaded -= ElementLoaded;
_leaf.Loading -= ElementLoading;

Subscribe(sender);

Expand Down Expand Up @@ -1155,7 +1155,7 @@ public EVPListener Of<T>()

public void Dispose()
{
_leaf.Loaded -= ElementLoaded;
_leaf.Loading -= ElementLoading;
foreach (var listener in _listeners.Values)
{
listener.Dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,6 @@ private void TryProcessScrollTo()

private void OnScroll(object sender, EventArgs args)
{
if (IsArrangeDirty && _pendingScrollTo.HasValue)
{
// When the native element of the SCP is becoming "valid" with a non 0 offset, it will raise a scroll event.
// But if we have a manual scroll request pending, we need to mute it and wait for the next layout updated.
return;
}

_pendingScrollTo = default;

// We don't have any information from the DOM 'scroll' event about the intermediate vs. final state.
// We could try to rely on the IsPointerPressed state to detect when the user is scrolling and use it.
// This would however not include scrolling due to the inertia which should also be flagged as intermediate.
Expand All @@ -262,6 +253,21 @@ private void OnScroll(object sender, EventArgs args)
var horizontalOffset = GetNativeHorizontalOffset();
var verticalOffset = GetNativeVerticalOffset();

if (IsArrangeDirty
&& _pendingScrollTo is { } pending
&& (
pending.horizontal is { } hOffset && Math.Abs(horizontalOffset - hOffset) > 1
|| pending.vertical is { } vOffset && Math.Abs(verticalOffset - vOffset) > 1)
)
{
// When the native element of the SCP is becoming "valid" with a non 0 offset, it will raise a scroll event.
// But if we have a manual scroll request pending, we need to mute it and wait for the next layout updated.

return;
}

_pendingScrollTo = default;

HorizontalOffset = horizontalOffset;
VerticalOffset = verticalOffset;

Expand Down
17 changes: 16 additions & 1 deletion src/Uno.UI/UI/Xaml/FrameworkElement.EffectiveViewport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ partial class FrameworkElement : IFrameworkElement_EffectiveViewport
{
private static readonly RoutedEventHandler ReconfigureViewportPropagationOnLoad = (snd, e) => ((_This)snd).ReconfigureViewportPropagation();
private event TypedEventHandler<_This, EffectiveViewportChangedEventArgs>? _effectiveViewportChanged;
private bool _hasNewHandler;
private int _childrenInterestedInViewportUpdates;
private IDisposable? _parentViewportUpdatesSubscription;
private ViewportInfo _parentViewport = ViewportInfo.Empty; // WARNING: Stored in parent's coordinates space, use GetParentViewport()
Expand All @@ -45,6 +46,7 @@ public event TypedEventHandler<_This, EffectiveViewportChangedEventArgs> Effecti
{
add
{
_hasNewHandler = true;
_effectiveViewportChanged += value;
ReconfigureViewportPropagation(isInternal: true);
}
Expand Down Expand Up @@ -74,6 +76,13 @@ private void ReconfigureViewportPropagation(bool isInternal = false, IFrameworkE
{
if (IsLoaded && IsEffectiveViewportEnabled)
{
#if CHECK_LAYOUTED
if (IsLoaded)
{
_isLayouted = true;
}
#endif

if (_parentViewportUpdatesSubscription == null)
{
TRACE_EFFECTIVE_VIEWPORT("Enabling effective viewport propagation.");
Expand Down Expand Up @@ -314,8 +323,14 @@ private void PropagateEffectiveViewportChange(
+ $"| reason: {caller} "
+ $"| children: {_childrenInterestedInViewportUpdates}");

if (!isInternal && viewportUpdated) // We don't want to raise the event when we are only initializing the tree due to a new event handler
if (viewportUpdated
&& (
!isInternal // We don't want to raise the event when we are only initializing the tree due to a new event handler somewhere in sub tree
|| _hasNewHandler // but if we have a new local handler, we do need to raise the event!
))
{
_hasNewHandler = false;

// Note: The event only notify about the parentViewport (expressed in local coordinate space!),
// the "local effective viewport" is used only by our children.
_effectiveViewportChanged?.Invoke(this, new EffectiveViewportChangedEventArgs(parentViewport.Effective));
Expand Down

0 comments on commit d3cc1d4

Please sign in to comment.