【问题标题】:ListView with Groove like quick return header带有 Groove 的 ListView,例如快速返回标头
【发布时间】:2016-12-23 10:40:37
【问题描述】:

向下滚动时,Groove 将标题向上移动到可视区域之外,就像常规 ListView 标题一样。向上滚动时,它会立即将标题向下移动到可视区域,而不管当前的垂直滚动偏移量如何。标题似乎是 ListView 内容的一部分,因为滚动条包含标题。

这如何在 Windows 10 UWP 应用中实现?

【问题讨论】:

    标签: win-universal-app uwp uwp-xaml


    【解决方案1】:

    您可以利用ListView's 内部ScrollViewer's ViewChanged 事件来做到这一点。

    首先你要获得内部ScrollViewer。这是最简单的版本,但您可能希望使用众多 VisualTreeHelper 扩展之一来更安全、更轻松地完成它:

    private void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        var border = VisualTreeHelper.GetChild(MyListView, 0);
        var scrollviewer = VisualTreeHelper.GetChild(border, 0) as ScrollViewer;
    
        scrollviewer.ViewChanged += Scrollviewer_ViewChanged;
    }
    

    在 EventHandler 中,您可以根据滚动方向更改标题的可见性。

    private void Scrollviewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
    {
        var sv = sender as ScrollViewer;
    
        if (sv.VerticalOffset > _lastVerticalOffset)
        {
            MyHeader.Visibility = Visibility.Collapsed;
        }
        else
        {
            MyHeader.Visibility = Visibility.Visible;
        }
    }
    

    这是基本思想。您可能不想添加一些流畅的动画,而只是更改可见性。

    【讨论】:

      【解决方案2】:

      环顾四周并进行实验后,我现在可以回答我自己的问题了。

      可以使用基于composition animation 的表达式来调整与滚动相关的标题的Y 偏移量。这个想法是基于这个answer。我在GitHub 上准备了一个完整的工作示例。

      动画是在ListView的SizeChanged事件中准备好的:

      ScrollViewer scrollViewer = null;
      private double previousVerticalScrollOffset = 0.0;
      private CompositionPropertySet scrollProperties;
      private CompositionPropertySet animationProperties;
      
      SizeChanged += (sender, args) =>
      {
          if (scrollProperties == null)
              scrollProperties = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer);
      
          var compositor = scrollProperties.Compositor;
      
          if (animationProperties == null)
          {
              animationProperties = compositor.CreatePropertySet();
              animationProperties.InsertScalar("OffsetY", 0.0f);
          }
      
          var expressionAnimation = compositor.CreateExpressionAnimation("animationProperties.OffsetY - ScrollingProperties.Translation.Y");
      
          expressionAnimation.SetReferenceParameter("ScrollingProperties", scrollProperties);
          expressionAnimation.SetReferenceParameter("animationProperties", animationProperties);
      
          var headerVisual = ElementCompositionPreview.GetElementVisual((UIElement)Header);
          headerVisual.StartAnimation("Offset.Y", expressionAnimation);
      };
      

      animationProperties 中的 OffsetY 变量将驱动 header 的 OffsetY 属性的动画。 OffsetY 变量在 ScrollViewer 的 ViewChanged 事件中更新:

      scrollViewer.ViewChanged += (sender, args) =>
      {
          float oldOffsetY = 0.0f;
          animationProperties.TryGetScalar("OffsetY", out oldOffsetY);
      
          var delta = scrollViewer.VerticalOffset - previousVerticalScrollOffset;
          previousVerticalScrollOffset = scrollViewer.VerticalOffset;
      
          var newOffsetY = oldOffsetY - (float)delta;
      
          // Keep values within negativ header size and 0
          FrameworkElement header = (FrameworkElement)Header;
          newOffsetY = Math.Max((float)-header.ActualHeight, newOffsetY);
          newOffsetY = Math.Min(0, newOffsetY);
      
          if (oldOffsetY != newOffsetY)
              animationProperties.InsertScalar("OffsetY", newOffsetY);
      };
      

      虽然这确实可以正确设置动画,但标题并未堆叠在 ListView 项的顶部。因此,最后的难题是减少 ListView 的 ItemsPanelTemplate 的 ZIndex:

      <ListView.ItemsPanel>
          <ItemsPanelTemplate>
              <ItemsStackPanel Canvas.ZIndex="-1" />
          </ItemsPanelTemplate>
      </ListView.ItemsPanel>
      

      结果如下:

      【讨论】:

      • 这可行,但动画远不如 Groove Music 中的流畅。与 Groove 相比,它与滚动的紧密同步程度存在非常明显的差异。
      猜你喜欢
      • 2020-01-16
      • 2017-09-13
      • 2023-03-23
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-03
      相关资源
      最近更新 更多