在ListView上水平滚动

本文关键字:滚动 水平 ListView | 更新日期: 2023-09-27 18:03:19

我目前正在捕获页面上的PointerMoved事件,以便与水平菜单一起使用。因此,用户可以向左/向右滑动,页面将相应地动画。

当用户触摸一个静态元素(TextBlock等),但如果他们触摸一个ListView,它会捕获触摸事件。

我如何实现ListView所以当用户垂直滚动它正常工作,但当用户水平滚动它传递事件给我的代码?

在ListView上水平滚动

这是可能的,但是您需要一个小技巧。作为参考,我把罗伯·卡普兰的文章放在这里。

让我们开始:

  1. 首先-你的事件在哪里?-答案很简单-当您启用ScrollViewer时,所有事件都被它截获并处理。您的ListView将只得到PointerEntered事件,在PointerExited之后,所有进一步的处理都由ScrollViewer处理。这就是问题所在。但正如我所说,有一个方法可以做你想做的。

  2. 为了这个目的,让我们假设您只使用VerticalScroll:

    定义了ListView
    <ListView Name="myList" ScrollViewer.HorizontalScrollMode="Disabled">
    

    当然两个方向都可以做到,但这只是一个简单的例子。

  3. 现在让我们来看看Page的构造函数:

    PointerPoint firstPoint = null;
    ScrollViewer listScrollviewer = null;
    public MainPage()
    {
      this.InitializeComponent();
      myList.ItemsSource = yourItemSource;
      myList.PointerEntered += myList_PointerEntered;
      myList.PointerMoved += myList_PointerMoved;
    }
    

    这里没有什么奇怪的-我只是订阅事件,并声明两个变量firstPointlistScrollviewer,我稍后会用到。

  4. 我们还需要从ListView中获取ScrollViewer -下面的方法将完成这项工作:

    public static ScrollViewer GetScrollViewer(DependencyObject depObj)
    {
        if (depObj is ScrollViewer) return depObj as ScrollViewer;
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            var child = VisualTreeHelper.GetChild(depObj, i);
            var result = GetScrollViewer(child);
            if (result != null) return result;
        }
        return null;
    }
    
  5. 现在-启用我们的事件,我们需要禁用ScrollViewer:

    private ScrollViewer DisableScrolling(DependencyObject depObj)
    {
        ScrollViewer foundOne = GetScrollViewer(depObj);
        if (foundOne != null) foundOne.VerticalScrollMode = ScrollMode.Disabled;
        return foundOne;
    }
    
  6. 我们将在PointerEntered事件被触发时禁用ScrollViewer。在这一步中,我们还将记住按下的PointerPoint -因为我们已经禁用了Scrollviewer,我们将不得不手动滚动它-这就是我们需要这个PointerPoint的原因。

    private void myList_PointerEntered(object sender, PointerRoutedEventArgs e)
    {
        firstPoint = e.GetCurrentPoint(myList);
        if (listScrollviewer == null) listScrollviewer = DisableScrolling(myList);
    }
    
  7. 最后我们的PointerMoved事件,现在将被触发,因为我们已经禁用了ScrollViewer -移动ScrollViewer +其他代码,你需要放在那里:

    private void myList_PointerMoved(object sender, PointerRoutedEventArgs e)
    {
        if (listScrollviewer != null)
        {
            PointerPoint secondPoint = e.GetCurrentPoint(myList);
            double verticalDifference = secondPoint.Position.Y - firstPoint.Position.Y;
            listScrollviewer.ChangeView(null, listScrollviewer.VerticalOffset - verticalDifference, null);
        }
        // some other code you need
    }
    

几个备注:

  • 这个方法仍然需要大量的调整,但希望能告诉你如何实现你的目标,
  • 你可能还需要将一些小的水平移动与垂直移动分开,
  • 如果你的ListView或其他控件有水平滚动,那么你也需要禁用和处理它,
  • 这个方法可能不会像原来的ScrollViewer那样流畅。

我还在OneDrive上放了一个简单的工作示例