Skip to content

Commit

Permalink
feat(scrollviewer): Add support of touch scrolling in managed ScrollV…
Browse files Browse the repository at this point in the history
…iewer (no inertia yet)
  • Loading branch information
dr1rrb committed Mar 12, 2021
1 parent d233337 commit 5697db6
Showing 1 changed file with 45 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
using System.Text;
using Windows.Foundation;
using System.IO;
using Windows.Devices.Input;
using Windows.System;
using Windows.UI.Composition;
using Windows.UI.Xaml.Input;
using Uno.UI.Media;

namespace Windows.UI.Xaml.Controls
Expand Down Expand Up @@ -119,8 +122,15 @@ public ScrollContentPresenter()

_strategy.Initialize(this);

// Mouse wheel support
PointerWheelChanged += ScrollContentPresenter_PointerWheelChanged;

// Touch scroll support
ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;
ManipulationStarted += BeginTouchScroll;
ManipulationDelta += UpdateTouchScroll;
ManipulationCompleted += CompleteTouchScroll;

// On Skia and macOS (as UWP), the Scrolling is managed by the ScrollContentPresenter, not the ScrollViewer.
// Note: This as direct consequences in UIElement.GetTransform and VisualTreeHelper.SearchDownForTopMostElementAt
RegisterAsScrollPort(this);
Expand Down Expand Up @@ -152,7 +162,8 @@ protected override void OnContentChanged(object oldValue, object newValue)
double? horizontalOffset = null,
double? verticalOffset = null,
float? zoomFactor = null,
bool disableAnimation = true)
bool disableAnimation = true,
bool isIntermediate = false)
{
var success = true;

Expand Down Expand Up @@ -184,19 +195,19 @@ protected override void OnContentChanged(object oldValue, object newValue)
}
}

Apply(disableAnimation: true);
Apply(disableAnimation, isIntermediate);

return success;
}

private void Apply(bool disableAnimation)
private void Apply(bool disableAnimation, bool isIntermediate)
{
if (Content is UIElement contentElt)
{
_strategy.Update(contentElt, HorizontalOffset, VerticalOffset, 1, disableAnimation);
}

Scroller?.OnScrollInternal(HorizontalOffset, VerticalOffset, isIntermediate: false);
Scroller?.OnScrollInternal(HorizontalOffset, VerticalOffset, isIntermediate);

// Note: We do not capture the offset so if they are altered in the OnScrollInternal,
// we will apply only the final ScrollOffsets and only once.
Expand Down Expand Up @@ -224,7 +235,11 @@ private void ScrollContentPresenter_PointerWheelChanged(object sender, Input.Poi
var canScrollHorizontally = HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled;
var canScrollVertically = VerticalScrollBarVisibility != ScrollBarVisibility.Disabled;

if (!canScrollVertically || properties.IsHorizontalMouseWheel || e.KeyModifiers.HasFlag(global::Windows.System.VirtualKeyModifiers.Shift))
if (e.KeyModifiers == VirtualKeyModifiers.Control)
{
// TODO: Handle zoom
}
else if (!canScrollVertically || properties.IsHorizontalMouseWheel || e.KeyModifiers == VirtualKeyModifiers.Shift)
{
if (canScrollHorizontally)
{
Expand All @@ -238,6 +253,31 @@ private void ScrollContentPresenter_PointerWheelChanged(object sender, Input.Poi
}
}

private void BeginTouchScroll(object sender, ManipulationStartedRoutedEventArgs e)
{
if (e.PointerDeviceType != PointerDeviceType.Touch)
{
e.Complete();
return;
}
}

private void UpdateTouchScroll(object sender, ManipulationDeltaRoutedEventArgs e)
=> Set(
horizontalOffset: HorizontalOffset - e.Delta.Translation.X,
verticalOffset: VerticalOffset - e.Delta.Translation.Y,
isIntermediate: true);

private void CompleteTouchScroll(object sender, ManipulationCompletedRoutedEventArgs e)
{
if (e.PointerDeviceType != PointerDeviceType.Touch)
{
return;
}

Set(isIntermediate: false);
}

bool ICustomClippingElement.AllowClippingToLayoutSlot => true;
bool ICustomClippingElement.ForceClippingToLayoutSlot => true; // force scrollviewer to always clip
}
Expand Down

0 comments on commit 5697db6

Please sign in to comment.