Skip to content

Commit

Permalink
fix(drawer): manipulation canceled in uno4 & eatten by scrollable/swi…
Browse files Browse the repository at this point in the history
…pable elements (#266)
  • Loading branch information
Xiaoy312 committed Jul 20, 2022
1 parent 792866d commit b98ad87
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,22 @@
<sample:ControlExample>
<sample:ControlExample.Content>
<utu:DrawerControl x:Name="SampleDrawerControl"
Content="Content"
DrawerContent="DrawerContent"
IsOpen="{Binding ElementName=OptionIsOpen, Path=IsChecked, Mode=TwoWay}"
OpenDirection="{Binding ElementName=OptionOpenDirection, Path=SelectedItem}"
IsGestureEnabled="{Binding ElementName=OptionIsGestureEnabled, Path=IsChecked}"
FitToDrawerContent="{Binding ElementName=OptionFitToDrawerContent, Path=IsChecked}"
MinHeight="300" />
MinHeight="300">

<TextBlock Text="Main Content" />

<utu:DrawerControl.DrawerContent>
<StackPanel>
<ToggleButton Content="IsOpen" IsChecked="{Binding ElementName=SampleDrawerControl, Path=IsOpen}" />
<TextBlock Text="Drawer Content" />
</StackPanel>
</utu:DrawerControl.DrawerContent>

</utu:DrawerControl>
</sample:ControlExample.Content>

<sample:ControlExample.Options>
Expand Down
93 changes: 88 additions & 5 deletions src/Uno.Toolkit.UI/Controls/DrawerControl/DrawerControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,21 @@
namespace Uno.Toolkit.UI
{
/// <summary>
/// Represents a container with two views; one view for the main content,
/// Represents a container with two views; one view for the main content,
/// and another view that can be revealed with swipe gesture.
/// </summary>
[TemplatePart(Name = TemplateParts.MainContentPresenterName, Type = typeof(ContentPresenter))]
[TemplatePart(Name = TemplateParts.DrawerContentControlName, Type = typeof(ContentControl))]
[TemplatePart(Name = TemplateParts.LightDismissOverlayName, Type = typeof(Border))]
[TemplatePart(Name = TemplateParts.GestureInterceptorName, Type = typeof(Border))]
public partial class DrawerControl : ContentControl
{
public static class TemplateParts
{
public const string MainContentPresenterName = "MainContentPresenter";
public const string DrawerContentControlName = "DrawerContentControl";
public const string LightDismissOverlayName = "LightDismissOverlay";
public const string GestureInterceptorName = "GestureInterceptor";
}

private const double DragToggleThresholdRatio = 1.0 / 3;
Expand All @@ -50,11 +52,12 @@ public static class TemplateParts
private ContentPresenter? _mainContentPresenter;
private ContentControl? _drawerContentControl;
private Border? _lightDismissOverlay;
private Border? _gestureInterceptor;

// references
private TranslateTransform? _drawerContentPresenterTransform;
private Storyboard _storyboard = new Storyboard();
private DoubleAnimation? _translateAnimation, _opacityAnimation;
private TranslateTransform? _drawerContentPresenterTransform;

// states
private bool _isReady = false;
Expand All @@ -77,6 +80,7 @@ protected override void OnApplyTemplate()
_mainContentPresenter = GetTemplateChild(TemplateParts.MainContentPresenterName) as ContentPresenter;
_drawerContentControl = GetTemplateChild(TemplateParts.DrawerContentControlName) as ContentControl;
_lightDismissOverlay = GetTemplateChild(TemplateParts.LightDismissOverlayName) as Border;
_gestureInterceptor = GetTemplateChild(TemplateParts.GestureInterceptorName) as Border;

if (_drawerContentControl != null)
{
Expand Down Expand Up @@ -115,6 +119,12 @@ protected override void OnApplyTemplate()
_lightDismissOverlay.Tapped += OnLightDismissOverlayTapped;
}

if (_gestureInterceptor != null)
{
UpdateGestureInterceptorSize();
UpdateGestureInterceptorLayout();
}

if (DrawerDepth != 0)
{
UpdateIsOpen(IsOpen, animate: false);
Expand All @@ -124,7 +134,7 @@ protected override void OnApplyTemplate()
void ResetPreviousTemplate()
{
_isReady = false;

_storyboard.Children.Clear();
_storyboard = new Storyboard();

Expand Down Expand Up @@ -162,6 +172,8 @@ private void OnOpenDirectionChanged(DependencyPropertyChangedEventArgs e)
StopRunningAnimation();
UpdateSwipeContentPresenterSize();
UpdateSwipeContentPresenterLayout();
UpdateGestureInterceptorSize();
UpdateGestureInterceptorLayout();
UpdateManipulationMode();
#if !STORYBOARD_RETARGET_ISSUE
UpdateTranslateAnimationTargetProperty();
Expand All @@ -172,6 +184,12 @@ private void OnOpenDirectionChanged(DependencyPropertyChangedEventArgs e)
UpdateIsOpen(IsOpen, animate: false);
}

private void OnEdgeSwipeDetectionLengthChanged(DependencyPropertyChangedEventArgs e)
{
UpdateGestureInterceptorSize();
UpdateGestureInterceptorLayout();
}

private void OnFitToDrawerContentChanged(DependencyPropertyChangedEventArgs e)
{
UpdateSwipeContentPresenterSize();
Expand All @@ -181,9 +199,14 @@ private void OnFitToDrawerContentChanged(DependencyPropertyChangedEventArgs e)
UpdateIsOpen(IsOpen, animate: false);
}

private void OnIsGestureEnabledChanged(DependencyPropertyChangedEventArgs e)
{
_gestureInterceptor.IsHitTestVisible = IsGestureEnabled && !IsOpen;
}

private void OnManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
if (e.OriginalSource != this) return;
if (!ShouldHandleManipulationFrom(e.OriginalSource)) return;
if (!IsGestureEnabled) return;

var position =
Expand Down Expand Up @@ -290,6 +313,10 @@ private void UpdateOpenness(double ratio)
_lightDismissOverlay.Opacity = 1 - ratio;
_lightDismissOverlay.IsHitTestVisible = ratio != 1;
}
if (_gestureInterceptor != null)
{
_gestureInterceptor.IsHitTestVisible = IsGestureEnabled && ratio == 1;
}
}

private void PlayAnimation(double fromRatio, bool willBeOpen)
Expand All @@ -313,6 +340,10 @@ private void PlayAnimation(double fromRatio, bool willBeOpen)
{
_lightDismissOverlay.IsHitTestVisible = willBeOpen;
}
if (_gestureInterceptor != null)
{
_gestureInterceptor.IsHitTestVisible = IsGestureEnabled && !willBeOpen;
}

_storyboard.Begin();
}
Expand Down Expand Up @@ -379,6 +410,35 @@ private void UpdateSwipeContentPresenterLayout()
}
}

private void UpdateGestureInterceptorLayout()
{
if (_gestureInterceptor == null) return;

switch (OpenDirection)
{
case DrawerOpenDirection.Left:
_gestureInterceptor.HorizontalAlignment = EdgeSwipeDetectionLength.HasValue ? HorizontalAlignment.Right : HorizontalAlignment.Stretch;
_gestureInterceptor.VerticalAlignment = VerticalAlignment.Stretch;
break;

case DrawerOpenDirection.Down:
_gestureInterceptor.HorizontalAlignment = HorizontalAlignment.Stretch;
_gestureInterceptor.VerticalAlignment = EdgeSwipeDetectionLength.HasValue ? VerticalAlignment.Top : VerticalAlignment.Stretch;
break;

case DrawerOpenDirection.Up:
_gestureInterceptor.HorizontalAlignment = HorizontalAlignment.Stretch;
_gestureInterceptor.VerticalAlignment = EdgeSwipeDetectionLength.HasValue ? VerticalAlignment.Bottom : VerticalAlignment.Stretch;
break;

case DrawerOpenDirection.Right:
default:
_gestureInterceptor.HorizontalAlignment = EdgeSwipeDetectionLength.HasValue ? HorizontalAlignment.Left : HorizontalAlignment.Stretch;
_gestureInterceptor.VerticalAlignment = VerticalAlignment.Stretch;
break;
}
}

private void UpdateSwipeContentPresenterSize()
{
if (_drawerContentControl == null) return;
Expand All @@ -395,6 +455,22 @@ private void UpdateSwipeContentPresenterSize()
}
}

private void UpdateGestureInterceptorSize()
{
if (_gestureInterceptor == null) return;

if (IsOpenDirectionHorizontal())
{
_gestureInterceptor.Height = double.NaN;
_gestureInterceptor.Width = EdgeSwipeDetectionLength ?? double.NaN;
}
else
{
_gestureInterceptor.Height = EdgeSwipeDetectionLength ?? double.NaN;
_gestureInterceptor.Width = double.NaN;
}
}

#if !STORYBOARD_RETARGET_ISSUE
private void UpdateTranslateAnimationTargetProperty()
{
Expand Down Expand Up @@ -447,6 +523,13 @@ private double TranslateOffset
}
}

private bool ShouldHandleManipulationFrom(object source)
{
return source == this
|| source == _gestureInterceptor
|| source == _lightDismissOverlay;
}

private bool IsInRangeForOpeningEdgeSwipe(Point p)
{
if (EdgeSwipeDetectionLength is double limit)
Expand All @@ -459,7 +542,7 @@ private bool IsInRangeForOpeningEdgeSwipe(Point p)

return distanceToEdge <= limit;
}
else // anywhere is fine if null
else // anywhere is fine if null
{
return true;
}
Expand Down
11 changes: 10 additions & 1 deletion src/Uno.Toolkit.UI/Controls/DrawerControl/DrawerControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
Background="{TemplateBinding LightDismissOverlayBackground}" />
<ContentControl x:Name="DrawerContentControl"
Content="{TemplateBinding DrawerContent}"
Background="{TemplateBinding DrawerBackground}">
Background="{TemplateBinding DrawerBackground}"
HorizontalContentAlignment="{TemplateBinding HorizontalAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalAlignment}">
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Border Background="{TemplateBinding Background}">
Expand All @@ -47,6 +49,13 @@
<TranslateTransform />
</ContentControl.RenderTransform>
</ContentControl>

<!-- workaround for edge swipe to work on top of other control (eg: SwipeControl) -->
<!-- see: https://github.com/unoplatform/nventive-private/issues/271 -->
<Border x:Name="GestureInterceptor"
Background="Transparent"
Visibility="{Binding IsGestureEnabled, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource TrueToVisible}}"
Margin="{TemplateBinding GestureInterceptorMargin}" />
</Grid>
</ControlTemplate>
</Setter.Value>
Expand Down

0 comments on commit b98ad87

Please sign in to comment.