ListView 上的水平滚动 [英] Horizontal scroll on ListView

查看:29
本文介绍了ListView 上的水平滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在页面上捕获 PointerMoved 事件以与水平菜单一起使用.所以用户可以向左/向右滑动,页面就会相应地动画.

I'm currently capturing the PointerMoved event on the page to use with a horizontal menu. So the user can swipe left/right and the page will animate accordingly.

这在用户触摸静态元素(TextBlock 等)时有效,但如果他们触摸 ListView,它会捕获触摸事件.

This works when the user touches a static element (TextBlock etc.) but if they touch a ListView it captures the touch events.

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

How can I implement the ListView so when the user scrolls vertically it works as normal, but when the user scrolls horizontally it passes the events to my code?

推荐答案

这是可能的,但你需要一个小技巧.作为参考,我放在这里 Rob Caplan 的文章.

It is possible, but you will need a small trick. As a refference I put here Rob Caplan's article.

让我们开始吧:

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

  1. First - where are your events? - answer is simple - while you have ScrollViewer enabled, all events are intercepted by it and handeled. You ListView will get only PointerEntered event and just after it PointerExited, all further proccesing is handeled by ScrollViewer. That is the problem. But as I've said there is a method to do what you want.

为此,假设您仅使用 VerticalScroll 定义了 ListView:

For this purpose lets assume that you have defined your ListView only with VerticalScroll:

<ListView Name="myList" ScrollViewer.HorizontalScrollMode="Disabled">

当然可以双向进行,但这是一个简单的例子.

Of course it is possible to do for both directions, but it's a simple example.

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

Now let's have a look at constructor of a Page:

PointerPoint firstPoint = null;
ScrollViewer listScrollviewer = null;

public MainPage()
{
  this.InitializeComponent();
  myList.ItemsSource = yourItemSource;
  myList.PointerEntered += myList_PointerEntered;
  myList.PointerMoved += myList_PointerMoved;
}

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

Nothing weird here - I just subscribe to events, and declare two variables firstPoint and listScrollviewer, which I'll need later.

我们还需要获取我们的 ListViewScrollViewer - 以下方法将完成这项工作:

We will need also to get our ScrollViewer of our ListView - the following method will do the job:

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;
}

  • 现在 - 要启用我们的事件,我们需要禁用 ScrollViewer:

    private ScrollViewer DisableScrolling(DependencyObject depObj)
    {
        ScrollViewer foundOne = GetScrollViewer(depObj);
        if (foundOne != null) foundOne.VerticalScrollMode = ScrollMode.Disabled;
        return foundOne;
    }
    

  • 我们将在触发 PointerEntered 事件时禁用 ScrollViewer.在这一步中,我们还将记住按下的 PointerPoint - 因为我们禁用了 Scrollviewer,所以我们必须手动滚动它 - 这就是我们需要的 PointerPoint for.

  • We will disable the ScrollViewer upon PointerEntered event which is fired. In this step we will also remember the pressed PointerPoint - as we have disable Scrollviewer, we will have to scroll it manually - that is what we need this PointerPoint for.

    private void myList_PointerEntered(object sender, PointerRoutedEventArgs e)
    {
        firstPoint = e.GetCurrentPoint(myList);
        if (listScrollviewer == null) listScrollviewer = DisableScrolling(myList);
    }
    

  • 最后是我们的 PointerMoved 事件,现在将被触发,因为我们禁用了 ScrollViewer - 移动 ScrollViewer + 其他你需要的代码放在那里:

  • Finally our PointerMoved event, which now wil be fired as we had disabled ScrollViewer - moving ScrollViewer + other code you need to put there:

    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
    }
    

  • <小时>

    几点说明:


    Few remarks:

    • 这个方法仍然需要很多调整,但希望能告诉你如何实现你的目标,
    • 您可能还需要将一些小的水平移动与垂直移动分开,
    • 如果你的 ListView 或其他控件有水平滚动,那么你也需要禁用和处理它,
    • 这个方法可能不会像原来的 ScrollViewer 那样流畅.
    • this method still needs much tuning, but hopefuly will show you how to achieve your goal,
    • you may need also to separate some small horizontal movements from vertical ones,
    • if your ListView or other Control has horizontal scroll, then you will also need to disable and handle it,
    • this method won't probably work so smooth like original ScrollViewer.

    我还在 OneDrive 中这里放了一个简单的工作示例.

    I've also put a simple working example here at OneDrive.

    这篇关于ListView 上的水平滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆