2014-10-04 77 views
36

有没有办法在Windows Phone 8.1 Runtime中平滑地动画ScrollViewer的垂直偏移量?通过编程动画(平滑)ScrollViewer

我曾尝试使用ScrollViewer.ChangeView()方法,并且无论将disableAnimation参数设置为true还是false,垂直偏移的更改都不会生成动画。

例如:myScrollViewer.ChangeView(null, myScrollViewer.VerticalOffset + p, null, false); 偏移量在没有动画的情况下更改。

我还用垂直方向的偏移调解的尝试:

/// <summary> 
/// Mediator that forwards Offset property changes on to a ScrollViewer 
/// instance to enable the animation of Horizontal/VerticalOffset. 
/// </summary> 
public sealed class ScrollViewerOffsetMediator : FrameworkElement 
{ 
    /// <summary> 
    /// ScrollViewer instance to forward Offset changes on to. 
    /// </summary> 
    public ScrollViewer ScrollViewer 
    { 
     get { return (ScrollViewer)GetValue(ScrollViewerProperty); } 
     set { SetValue(ScrollViewerProperty, value); } 
    } 
    public static readonly DependencyProperty ScrollViewerProperty = 
      DependencyProperty.Register("ScrollViewer", 
      typeof(ScrollViewer), 
      typeof(ScrollViewerOffsetMediator), 
      new PropertyMetadata(null, OnScrollViewerChanged)); 
    private static void OnScrollViewerChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
    { 
     var mediator = (ScrollViewerOffsetMediator)o; 
     var scrollViewer = (ScrollViewer)(e.NewValue); 
     if (null != scrollViewer) 
     { 
      scrollViewer.ScrollToVerticalOffset(mediator.VerticalOffset); 
     } 
    } 

    /// <summary> 
    /// VerticalOffset property to forward to the ScrollViewer. 
    /// </summary> 
    public double VerticalOffset 
    { 
     get { return (double)GetValue(VerticalOffsetProperty); } 
     set { SetValue(VerticalOffsetProperty, value); } 
    } 
    public static readonly DependencyProperty VerticalOffsetProperty = 
      DependencyProperty.Register("VerticalOffset", 
      typeof(double), 
      typeof(ScrollViewerOffsetMediator), 
      new PropertyMetadata(0.0, OnVerticalOffsetChanged)); 
    public static void OnVerticalOffsetChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
    { 
     var mediator = (ScrollViewerOffsetMediator)o; 
     if (null != mediator.ScrollViewer) 
     { 
      mediator.ScrollViewer.ScrollToVerticalOffset((double)(e.NewValue)); 
     } 
    } 

    /// <summary> 
    /// Multiplier for ScrollableHeight property to forward to the ScrollViewer. 
    /// </summary> 
    /// <remarks> 
    /// 0.0 means "scrolled to top"; 1.0 means "scrolled to bottom". 
    /// </remarks> 
    public double ScrollableHeightMultiplier 
    { 
     get { return (double)GetValue(ScrollableHeightMultiplierProperty); } 
     set { SetValue(ScrollableHeightMultiplierProperty, value); } 
    } 
    public static readonly DependencyProperty ScrollableHeightMultiplierProperty = 
      DependencyProperty.Register("ScrollableHeightMultiplier", 
      typeof(double), 
      typeof(ScrollViewerOffsetMediator), 
      new PropertyMetadata(0.0, OnScrollableHeightMultiplierChanged)); 
    public static void OnScrollableHeightMultiplierChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
    { 
     var mediator = (ScrollViewerOffsetMediator)o; 
     var scrollViewer = mediator.ScrollViewer; 
     if (null != scrollViewer) 
     { 
      scrollViewer.ScrollToVerticalOffset((double)(e.NewValue) * scrollViewer.ScrollableHeight); 
     } 
    } 
} 

,我可以用DoubleAnimation动画VerticalOffset属性:

Storyboard sb = new Storyboard(); 
DoubleAnimation da = new DoubleAnimation(); 
da.EnableDependentAnimation = true; 
da.From = Mediator.ScrollViewer.VerticalOffset; 
da.To = da.From + p; 
da.Duration = new Duration(TimeSpan.FromMilliseconds(300)); 
da.EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseOut }; 
Storyboard.SetTarget(da, Mediator); 
Storyboard.SetTargetProperty(da, "(Mediator.VerticalOffset)"); 
sb.Children.Add(da); 

sb.Begin(); 

介体是XAML声明。 但是这个动画在我的设备上并不流畅(Lumia 930)。

+4

有一件事你可以尝试是['WinRTXamlToolkit'' ScrollToVerticalOffsetWithAnimation'扩展](http://winrtxamltoolkit.codeplex.com/SourceControl/latest#WinRTXamlToolkit/WinRTXamlToolkit.Shared/Controls/Extensions/ScrollViewerExtensions.cs)。您可以手动实施它或通过Nuget添加库。 – 2014-10-10 01:27:24

+2

我不认为,有一种方法可以使它完全平滑。这种动画可能不是硬件加速的。 – 2015-05-22 12:27:30

+0

否... http://sviluppomobile.blogspot.fi/2013/04/smooth-scrolling-content-on-windows.html? – 2015-08-11 17:49:05

回答

14

无论数据虚拟化是否开启,您都应该坚持使用ChangeView来滚动动画。

没有看到您的代码,其中ChangeView不起作用,这有点难以猜测到底发生了什么,但有几件事情可以尝试。

第一种方法是在调用ChangeView之前添加一个Task.Delay(1),以使操作系统有一段时间完成其他并发UI任务。

await Task.Delay(1); 
scrollViewer.ChangeView(null, scrollViewer.ScrollableHeight, null, false); 

第二种方法有点复杂。我注意到的是,当ListView中有许多复杂项目时,从第一项到最后一项(从ChangeView方法)的滚动动画根本不是很流畅。

这是因为ListView首先需要通过数据虚拟化实现/呈现许多项目,然后执行动画滚动。恕我直言,效率不高。

我想出了这个 - 首先,使用非动画ListView.ScrollIntoView滚动到最后一项,以实现它。然后,拨打ChangeView将偏移量上移至ListViewActualHeight * 2的大小,并禁用动画(您可以根据应用程序的滚动体验将其更改为任意大小)。最后,再次拨打ChangeView以回滚到最后,这次是动画。这样做会带来更好的滚动体验,因为滚动距离只是ListViewActualHeight

请记住,当您想要滚动到的项目已经在用户界面上实现时,您不想执行任何操作。您只需计算此物品与ScrollViewer顶部之间的距离,并拨打ChangeView即可滚动到该物品。

我已经包裹在这answer更新2部分(感谢这个问题,我意识到,当虚拟化是在我最初的回答不工作:P)以上的逻辑。让我知道你怎么去。

+2

由于Task.Delay的原因,第一种方法使'ChangeView'变得平滑。我不知道这会有多大帮助。非常感谢你。 – 2015-10-02 19:14:27

4

我认为这个问题已经在这里找到答案:

Animated (Smooth) scrolling on ScrollViewer

也有WinRT的XAML Toolki,它提供了“一种方式来滚动的ScrollViewer与动画中的指定偏移”:

http://winrtxamltoolkit.codeplex.com/

+3

当您查看[ScrollViewerExtensions.cs](http://winrtxamltoolkit.codeplex.com/SourceControl/latest#WinRTXamlToolkit/WinRTXamlToolkit.Shared/Controls/Extensions/ScrollViewerExtensions.cs)的源代码时,创建动画的方法是名称为'ScrollToVerticalOffsetWithAnimation',你可以看到'da.EnableDependentAnimation = true'这行意味着动画不在组合线上运行,这意味着它可能不能流畅运行,这是主要问题,如何使用**独立动画制作scrollviewer的动画** – 2015-09-29 07:16:34

+0

这两者都不与WinRT/Windows10相关 – 2016-03-01 21:23:24

0

ScrollToVerticalOffset在较新版本的Windows 10中不再使用/废弃(使ScrollViewOffSetMediator扩展控件不再可用)以及新的ChangeView方法实际上不能提供流畅或可控的动画,因此需要新的解决方案。请在这里看到我的答案,让一个顺利动画和缩放ScrollViewer中,其内容以任何需要的位置,无论在应用程序的最终用户最初定位的滚动条:

How to scroll to element in UWP