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.
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.
Credits
Well, vsm is used in making Responsive UI in that blog. To add a swipe gesture in SplitView, here's what I did:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With