添加滑动手势以打开SplitView面板

23

我试图向UWP的SplitView控件(也称为“汉堡菜单”)添加一个滑动手势,类似于Pivot控件的左右滑动。如何设置手势来更改其显示模式?

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来控制左侧面板的进出呢? 我不知道这是否可行。

任何帮助/提示都将不胜感激。

2个回答

40

有趣的问题! :)

我最近创建了一个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上创建的演示应用程序的工作方式。 您可以在此处找到完整的源代码。

enter image description here


制作者信息


5
我最近更新了GitHub存储库,并添加了另一个很酷的功能——“IsPanSelectorEnabled”属性,可以让您通过在面板底部区域上下滑动来选择菜单项。我相信这将有助于使用大屏手机的用户,因为他们不再需要伸手到顶部区域!演示视频链接:https://www.youtube.com/watch?v=K47MHJFe4dQ - Justin XL
1
@JerryNixon-MSFT 我猜这取决于情况。在使用Pivot或启用水平滑动的页面(例如,左右滑动以删除/完成项目)时,可能不是一个好主意使用它。但我认为开发人员至少应该有选择适合他们应用程序的选项。 :) - Justin XL
1
@JustinXL 在我看来,整个滑动打开的功能应该按照Android上的方式实现 - 如果滑动事件来自屏幕外部,或者从最左边的几个像素列开始(我认为在Android上,在高清屏幕上是12或24像素),将其视为抽屉/窗格的手势处理,否则将其视为通用页面手势处理。这样可以避免与可滑动选项卡混淆。 - fonix232
1
@fonix232 这就是为什么在源代码中有一个名为PanAreaThreshold的dp。你可以将其更改为12或24px,例如。 - Justin XL
1
@Jerry:没错,当然。话说,作为以前在iOS上经常使用此手势的人,我也希望这个手势可以在所有应用程序中实现。(顺便说一下,在相关的问题上,令人难以置信的是,VS甚至没有提供内置的汉堡控件来配合SplitView,你不得不在Template10中自己编写——难怪即使在内置应用程序中,汉堡控件UX也如此糟糕不一致!) - BoltClock
显示剩余7条评论

1

好的,vsm在该博客中用于制作响应式用户界面。要在SplitView中添加滑动手势,请按照以下步骤操作:

  • 在SplitView的内容的根面板上检测手势,并添加一些涉及操纵事件处理程序。
  • 在操纵事件中处理SplitView的IsPaneOpen属性。

1
这是我几个月前制作的演示,用于展示这一特性。这是一个Windows Phone 8.1项目,当然我没有使用SplitView来实现该特性。相反,演示包含了一个Pivot控件和我自己制作的汉堡菜单。 - JuniperPhoton
嘿,Jerry!@JerryNixon-MSFT 你应该看看我的回答。 :) - Justin XL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接