添加滑动手势以打开 SplitView 窗格
Adding a swipe gesture to open SplitView Pane
我正在尝试向 UWP 的 SplitView 控件(又名 "hamburger menu")添加滑动手势,类似于 Pivot 控件的滑动 left/right。如何设置一个手势来改变它的显示模式?
在 iOS 8 及更高版本中,我可以使用 UISplitViewController 并设置 presentsWithGesture 属性 来做到这一点,但在 WinRT 中没有类似的东西。
现在读了这个博客:http://blogs.msdn.com/b/cdndevs/archive/2015/07/10/uwp-new-controls-part-2-splitview.aspx,我意识到SplitView控件中有DisplayMode 属性,我应该使用VisualStateManager来改变它的状态但是我如何使用vsm来平移左窗格进出?我不知道这可以通过 vsm 实现。
任何 help/hint 将不胜感激。
好吧,vsm 用于在该博客中制作 Responsive UI。要在 SplitView 中添加滑动手势,我是这样做的:
- 在 SplitView 的内容的根面板上检测手势,并添加一些 Manipulatioin 涉及的事件处理程序。
- 在 Manipulation 事件中处理 SplitView 的 IsPaneOpen 属性。
有趣的问题! :)
我最近创建了一个 SwipeableSplitView
,它扩展了 SplitView
控件以在设置 DisplayMode
时启用 从左边缘滑动 手势到 Overlay
(因为我看不出在其他模式下使用它有什么意义,但可以在需要时随意扩展它)。
我所做的就是,在控件的样式内,在 PaneRoot
层之上创建另一个层并处理那里的所有手势。
<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>
在更新新层变换对象的 TranslateX
的同时,我也在更新 PaneRoot
以保持它们的位置同步。
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();
}
}
请记住,因为 IsPaneOpen
属性 不是虚拟的,所以我必须创建另一个 IsSwipeablePaneOpen
来包裹前者。因此,每当您想使用 IsPaneOpen
属性 时,请改用 IsSwipeablePaneOpen
。
这就是我在 GitHub 中创建的演示应用程序的工作原理。您可以找到完整的源代码 here.
学分
- SplitView 模板由 Koen Zwikstra 的精彩 Visual Studio UWP templates.
生成
- 页面动画和其他一些实现的灵感来自 this post
来自杰瑞·尼克松。
我正在尝试向 UWP 的 SplitView 控件(又名 "hamburger menu")添加滑动手势,类似于 Pivot 控件的滑动 left/right。如何设置一个手势来改变它的显示模式?
在 iOS 8 及更高版本中,我可以使用 UISplitViewController 并设置 presentsWithGesture 属性 来做到这一点,但在 WinRT 中没有类似的东西。
现在读了这个博客:http://blogs.msdn.com/b/cdndevs/archive/2015/07/10/uwp-new-controls-part-2-splitview.aspx,我意识到SplitView控件中有DisplayMode 属性,我应该使用VisualStateManager来改变它的状态但是我如何使用vsm来平移左窗格进出?我不知道这可以通过 vsm 实现。
任何 help/hint 将不胜感激。
好吧,vsm 用于在该博客中制作 Responsive UI。要在 SplitView 中添加滑动手势,我是这样做的:
- 在 SplitView 的内容的根面板上检测手势,并添加一些 Manipulatioin 涉及的事件处理程序。
- 在 Manipulation 事件中处理 SplitView 的 IsPaneOpen 属性。
有趣的问题! :)
我最近创建了一个 SwipeableSplitView
,它扩展了 SplitView
控件以在设置 DisplayMode
时启用 从左边缘滑动 手势到 Overlay
(因为我看不出在其他模式下使用它有什么意义,但可以在需要时随意扩展它)。
我所做的就是,在控件的样式内,在 PaneRoot
层之上创建另一个层并处理那里的所有手势。
<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>
在更新新层变换对象的 TranslateX
的同时,我也在更新 PaneRoot
以保持它们的位置同步。
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();
}
}
请记住,因为 IsPaneOpen
属性 不是虚拟的,所以我必须创建另一个 IsSwipeablePaneOpen
来包裹前者。因此,每当您想使用 IsPaneOpen
属性 时,请改用 IsSwipeablePaneOpen
。
这就是我在 GitHub 中创建的演示应用程序的工作原理。您可以找到完整的源代码 here.
学分
- SplitView 模板由 Koen Zwikstra 的精彩 Visual Studio UWP templates. 生成
- 页面动画和其他一些实现的灵感来自 this post 来自杰瑞·尼克松。