如何通过横向拖动(滑动手势)在 views/screens 之间导航?
How can I navigate between views/screens by dragging sideways (swipe gesture)?
所以我希望用户通过横向拖动来更改显示的 window。他的光标在屏幕上的确切位置应该无关紧要(所以只有拖动操作才是重要的)我画了一点我的想法。我希望用户看到第二个屏幕出现在光标之后,甚至在他将光标向右移动时缩回(基本上跟随他的光标)。这个动作应该是双向的:从 main window 到 2nd window 和从 2nd window 回到 main window
你会如何处理这个问题?
编辑:
图片1;用户将光标放在点 A 上并单击。按住鼠标单击的同时,他将其拖过绿色箭头。
图片2;此图表示“幻灯片”仍在进行时的中间状态(您可以看到“统计”屏幕仍未完全接管初始屏幕)
图3;代表最终状态;在用户到达(假想的)绿色箭头的末尾之后。统计信息屏幕现已完全显示,用户可以阅读其中的信息。
应该允许与现在发生的情况相反(从左向右拖动以返回初始屏幕)
您需要对您的内容应用翻译转换。
以下示例显示如何拖动内容(或内容的图像)。为简单起见,该示例仅显示如何从右向左滑动。它也没有显示如何实现历史记录以返回导航。您需要一个 Queue
来存储下一页,并需要一个 Stack
来存储上一页(基于滑动方向)。
虽然下面的例子做到了,但我不建议直接使用控件来处理页面及其导航。而是创建页面数据模型并使用每个页面模型的 DataTemplate
呈现控件。
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public object CurrentPage
{
get => (object)GetValue(CurrentPageProperty);
set => SetValue(CurrentPageProperty, value);
}
public static readonly DependencyProperty CurrentPageProperty = DependencyProperty.Register(
"CurrentPage",
typeof(object),
typeof(MainWindow),
new PropertyMetadata(default));
private StackPanel DraggableContent { get; }
// Accept swipe after 25% swipe delta
// based on the max possible swipe width (a displayed page).
// Note that the 'PageHost' will host two pages (their image)
// during the swipe action.
private double SwipeAcceptDragThreshold
=> this.PageHost.ActualWidth / 2 * 0.25;
private bool IsSwiping { get; set; }
private double HorizontalDragStart { get; set; }
private UserControl PreviousPage { get; set; }
private UserControl NextPage { get; set; }
/* Page controls */
private UserControl GreenPage { get; }
private UserControl OrangePage { get; }
private UserControl BluePage { get; }
public MainWindow()
{
InitializeComponent();
this.GreenPage = new PageControl() { Background = Brushes.Green };
this.OrangePage = new PageControl() { Background = Brushes.Orange };
this.BluePage = new GreenPage() { Background = Brushes.Blue };
this.CurrentPage = this.GreenPage;
this.NextPage = this.OrangePage;
this.DraggableContent = new StackPanel() { Orientation = Orientation.Horizontal };
}
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonDown(e);
this.HorizontalDragStart = e.GetPosition(this).X;
}
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnPreviewMouseMove(e);
if (e.LeftButton == MouseButtonState.Released)
{
return;
}
double dragDelta = e.GetPosition(this).X - this.HorizontalDragStart;
if (!this.IsSwiping)
{
bool isSwipeRightToLeft = dragDelta < HorizontalDragStart;
UserControl swipeInPage = null;
UserControl swipeOutPage = null;
if (isSwipeRightToLeft)
{
if (this.NextPage == null)
{
return;
}
swipeInPage = this.NextPage;
swipeOutPage = this.CurrentPage as UserControl;
this.PreviousPage = this.CurrentPage as UserControl;
}
this.IsSwiping = true;
/* Create an image of the content that will be dragged, using VisualBrush */
swipeInPage.Height = this.PageHost.ActualHeight;
swipeInPage.Width = this.PageHost.ActualWidth;
swipeOutPage.Height = this.PageHost.ActualHeight;
swipeOutPage.Width = this.PageHost.ActualWidth;
this.CurrentPage = null;
// Prepare the snapshot
this.DraggableContent.Children.Add(swipeOutPage);
this.DraggableContent.Children.Add(swipeInPage);
// To improve performance, the user will only drag a snapshot
// of the pages. The snapshot is painted on an empty Grid
// using a VisualBrush.
this.CurrentPage = new Grid()
{
Background = new VisualBrush(DraggableContent),
Width = this.PageHost.ActualWidth * 2 // Host two pages
};
}
this.TranslateTransform.X = dragDelta;
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (this.IsSwiping)
{
this.IsSwiping = false;
double dragDelta = Math.Abs(e.GetPosition(this).X - this.HorizontalDragStart);
bool isDragAccepted = dragDelta > this.SwipeAcceptDragThreshold;
// Disconnect page controls from the visual tree
this.DraggableContent.Children.Clear();
this.CurrentPage = isDragAccepted
? NextPage
: this.PreviousPage;
this.TranslateTransform.X = 0;
// TODO::Generate and set next page or null if last page reached
this.NextPage = this.BluePage;
}
}
}
MainWindow.xaml
<Window>
<!-- Allow content to exceed the Window -->
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden">
<ContentPresenter x:Name="PageHost"
Content="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=CurrentPage}">
<ContentPresenter.RenderTransform>
<TranslateTransform x:Name="TranslateTransform" />
</ContentPresenter.RenderTransform>
</ContentPresenter>
</ScrollViewer>
</Window>
PageControl.xaml
<UserControl>
<Grid Background="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Background}" />
</UserControl>
所以我希望用户通过横向拖动来更改显示的 window。他的光标在屏幕上的确切位置应该无关紧要(所以只有拖动操作才是重要的)我画了一点我的想法。我希望用户看到第二个屏幕出现在光标之后,甚至在他将光标向右移动时缩回(基本上跟随他的光标)。这个动作应该是双向的:从 main window 到 2nd window 和从 2nd window 回到 main window 你会如何处理这个问题?
编辑: 图片1;用户将光标放在点 A 上并单击。按住鼠标单击的同时,他将其拖过绿色箭头。
图片2;此图表示“幻灯片”仍在进行时的中间状态(您可以看到“统计”屏幕仍未完全接管初始屏幕)
图3;代表最终状态;在用户到达(假想的)绿色箭头的末尾之后。统计信息屏幕现已完全显示,用户可以阅读其中的信息。
应该允许与现在发生的情况相反(从左向右拖动以返回初始屏幕)
您需要对您的内容应用翻译转换。
以下示例显示如何拖动内容(或内容的图像)。为简单起见,该示例仅显示如何从右向左滑动。它也没有显示如何实现历史记录以返回导航。您需要一个 Queue
来存储下一页,并需要一个 Stack
来存储上一页(基于滑动方向)。
虽然下面的例子做到了,但我不建议直接使用控件来处理页面及其导航。而是创建页面数据模型并使用每个页面模型的 DataTemplate
呈现控件。
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public object CurrentPage
{
get => (object)GetValue(CurrentPageProperty);
set => SetValue(CurrentPageProperty, value);
}
public static readonly DependencyProperty CurrentPageProperty = DependencyProperty.Register(
"CurrentPage",
typeof(object),
typeof(MainWindow),
new PropertyMetadata(default));
private StackPanel DraggableContent { get; }
// Accept swipe after 25% swipe delta
// based on the max possible swipe width (a displayed page).
// Note that the 'PageHost' will host two pages (their image)
// during the swipe action.
private double SwipeAcceptDragThreshold
=> this.PageHost.ActualWidth / 2 * 0.25;
private bool IsSwiping { get; set; }
private double HorizontalDragStart { get; set; }
private UserControl PreviousPage { get; set; }
private UserControl NextPage { get; set; }
/* Page controls */
private UserControl GreenPage { get; }
private UserControl OrangePage { get; }
private UserControl BluePage { get; }
public MainWindow()
{
InitializeComponent();
this.GreenPage = new PageControl() { Background = Brushes.Green };
this.OrangePage = new PageControl() { Background = Brushes.Orange };
this.BluePage = new GreenPage() { Background = Brushes.Blue };
this.CurrentPage = this.GreenPage;
this.NextPage = this.OrangePage;
this.DraggableContent = new StackPanel() { Orientation = Orientation.Horizontal };
}
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonDown(e);
this.HorizontalDragStart = e.GetPosition(this).X;
}
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnPreviewMouseMove(e);
if (e.LeftButton == MouseButtonState.Released)
{
return;
}
double dragDelta = e.GetPosition(this).X - this.HorizontalDragStart;
if (!this.IsSwiping)
{
bool isSwipeRightToLeft = dragDelta < HorizontalDragStart;
UserControl swipeInPage = null;
UserControl swipeOutPage = null;
if (isSwipeRightToLeft)
{
if (this.NextPage == null)
{
return;
}
swipeInPage = this.NextPage;
swipeOutPage = this.CurrentPage as UserControl;
this.PreviousPage = this.CurrentPage as UserControl;
}
this.IsSwiping = true;
/* Create an image of the content that will be dragged, using VisualBrush */
swipeInPage.Height = this.PageHost.ActualHeight;
swipeInPage.Width = this.PageHost.ActualWidth;
swipeOutPage.Height = this.PageHost.ActualHeight;
swipeOutPage.Width = this.PageHost.ActualWidth;
this.CurrentPage = null;
// Prepare the snapshot
this.DraggableContent.Children.Add(swipeOutPage);
this.DraggableContent.Children.Add(swipeInPage);
// To improve performance, the user will only drag a snapshot
// of the pages. The snapshot is painted on an empty Grid
// using a VisualBrush.
this.CurrentPage = new Grid()
{
Background = new VisualBrush(DraggableContent),
Width = this.PageHost.ActualWidth * 2 // Host two pages
};
}
this.TranslateTransform.X = dragDelta;
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (this.IsSwiping)
{
this.IsSwiping = false;
double dragDelta = Math.Abs(e.GetPosition(this).X - this.HorizontalDragStart);
bool isDragAccepted = dragDelta > this.SwipeAcceptDragThreshold;
// Disconnect page controls from the visual tree
this.DraggableContent.Children.Clear();
this.CurrentPage = isDragAccepted
? NextPage
: this.PreviousPage;
this.TranslateTransform.X = 0;
// TODO::Generate and set next page or null if last page reached
this.NextPage = this.BluePage;
}
}
}
MainWindow.xaml
<Window>
<!-- Allow content to exceed the Window -->
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden">
<ContentPresenter x:Name="PageHost"
Content="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=CurrentPage}">
<ContentPresenter.RenderTransform>
<TranslateTransform x:Name="TranslateTransform" />
</ContentPresenter.RenderTransform>
</ContentPresenter>
</ScrollViewer>
</Window>
PageControl.xaml
<UserControl>
<Grid Background="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Background}" />
</UserControl>