Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a swipe gesture to open SplitView Pane

Tags:

I am trying to add a swipe gesture to the SplitView control (aka "hamburger menu") of UWP, similar to the swipe left/right of a Pivot control. How can I set a gesture to change the Display mode of it?

In iOS 8 and later, I can use UISplitViewController and set presentsWithGesture property to do that but there is not a similar thing in WinRT.

Now after reading this blog: http://blogs.msdn.com/b/cdndevs/archive/2015/07/10/uwp-new-controls-part-2-splitview.aspx, I realized that there is the DisplayMode property in SplitView control and I should use VisualStateManager to change the state of it But how can I use vsm to pan the left Pane in and out? I am not aware that this is achievable with vsm.

Any help/hint would be greatly appreciated.

like image 956
iou90 Avatar asked Aug 20 '15 01:08

iou90


2 Answers

Interesting question! :)

I recently created a SwipeableSplitView which extends the SplitView control to enable a swipe from left edge gesture when the DisplayMode is set to Overlay (as I don't see the point to have it in other modes, but feel free to extend it whenever needed).

All I am doing is, inside the control's style, create another layer on top of the PaneRoot layer and handle all the gestures there.

<Grid x:Name="PaneRoot" ManipulationMode="TranslateX" Grid.ColumnSpan="2" HorizontalAlignment="Left" Background="{TemplateBinding PaneBackground}" Width="{Binding TemplateSettings.OpenPaneLength, RelativeSource={RelativeSource Mode=TemplatedParent}}">     <Grid.Clip>         <RectangleGeometry x:Name="PaneClipRectangle">             <RectangleGeometry.Transform>                 <CompositeTransform x:Name="PaneClipRectangleTransform" />             </RectangleGeometry.Transform>         </RectangleGeometry>     </Grid.Clip>     <Grid.RenderTransform>         <CompositeTransform x:Name="PaneTransform" TranslateX="{Binding RenderTransform.TranslateX, ElementName=PanArea}" />     </Grid.RenderTransform>     <Border Child="{TemplateBinding Pane}" />     <Rectangle x:Name="HCPaneBorder" Fill="{ThemeResource SystemControlForegroundTransparentBrush}" HorizontalAlignment="Right" Visibility="Collapsed" Width="1" x:DeferLoadStrategy="Lazy" /> </Grid>  <!--a new layer here to handle all the gestures --> <Grid x:Name="OverlayRoot" Grid.ColumnSpan="2">     <Grid.ColumnDefinitions>         <ColumnDefinition Width="{Binding TemplateSettings.OpenPaneGridLength, RelativeSource={RelativeSource Mode=TemplatedParent}}" />         <ColumnDefinition Width="Auto" />         <ColumnDefinition />     </Grid.ColumnDefinitions>     <!--the actual element for panning, manipulations happen here-->     <Rectangle x:Name="PanArea" Fill="Transparent" ManipulationMode="TranslateX" Width="{Binding PanAreaThreshold, RelativeSource={RelativeSource Mode=TemplatedParent}}" Grid.Column="1">         <Rectangle.RenderTransform>             <CompositeTransform TranslateX="{Binding PanAreaInitialTranslateX, RelativeSource={RelativeSource Mode=TemplatedParent}}" />         </Rectangle.RenderTransform>     </Rectangle>     <!--this is used to dismiss this swipeable pane-->     <Rectangle x:Name="DismissLayer" Fill="Transparent" Grid.Column="2" /> </Grid> 

While updating the TranslateX of the new layer's transform object, I am also updating the PaneRoot's to keep their position in sync.

void OnManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e) {     _panAreaTransform = PanArea.RenderTransform as CompositeTransform;     _paneRootTransform = PaneRoot.RenderTransform as CompositeTransform;      if (_panAreaTransform == null || _paneRootTransform == null)     {         throw new ArgumentException("Make sure you have copied the default style to Generic.xaml!!");     } }  void OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) {     var x = _panAreaTransform.TranslateX + e.Delta.Translation.X;      // keep the pan within the bountry     if (x < PanAreaInitialTranslateX || x > 0) return;      // while we are panning the PanArea on X axis, let's sync the PaneRoot's position X too     _paneRootTransform.TranslateX = _panAreaTransform.TranslateX = x; }  void OnManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) {     var x = e.Velocities.Linear.X;      // ignore a little bit velocity (+/-0.1)     if (x <= -0.1)     {         CloseSwipeablePane();     }     else if (x > -0.1 && x < 0.1)     {         if (Math.Abs(_panAreaTransform.TranslateX) > Math.Abs(PanAreaInitialTranslateX) / 2)         {             CloseSwipeablePane();         }         else         {             OpenSwipeablePane();         }     }     else     {         OpenSwipeablePane();     } } 

Keep in mind that because the IsPaneOpen property is not virtual, I have to create another one IsSwipeablePaneOpen to wrap the former around. So whenever you feel like using the IsPaneOpen property, use IsSwipeablePaneOpen instead.

This is how it works in a demo app I created in GitHub. You can find the full source code here.

enter image description here


Credits

  • The SplitView template was generated from Koen Zwikstra's awesome Visual Studio UWP templates.
  • Page animations and some other implementations were inspired by this post from Jerry Nixon.
like image 62
Justin XL Avatar answered Oct 20 '22 09:10

Justin XL


Well, vsm is used in making Responsive UI in that blog. To add a swipe gesture in SplitView, here's what I did:

  • Detect gesture on your root panel of SplitView's Content, and add some Manipulatioin involved event handler of it.
  • Handle SplitView's IsPaneOpen property in Manipulation event.
like image 37
JuniperPhoton Avatar answered Oct 20 '22 08:10

JuniperPhoton