Horizontal scroll on ListView

后端 未结 1 1412
一整个雨季
一整个雨季 2020-12-06 03:35

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 accordingl

相关标签:
1条回答
  • 2020-12-06 04:31

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

    Let's start:

    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.

    2. 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.

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

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

    4. 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;
      }
      
    5. Now - to enable our events we will need to disable the ScrollViewer:

      private ScrollViewer DisableScrolling(DependencyObject depObj)
      {
          ScrollViewer foundOne = GetScrollViewer(depObj);
          if (foundOne != null) foundOne.VerticalScrollMode = ScrollMode.Disabled;
          return foundOne;
      }
      
    6. 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);
      }
      
    7. 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:

    • 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.

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

    0 讨论(0)
提交回复
热议问题