以编程方式animation(平滑)ScrollViewer
有没有办法在Windows Phone 8.1 Runtime中平滑地设置ScrollViewer
的垂直偏移?
我已经尝试使用ScrollViewer.ChangeView()
方法,无论是否将disableAnimation
参数设置为true或false,垂直偏移的更改都不会生成animation。
例如: myScrollViewer.ChangeView(null, myScrollViewer.VerticalOffset + p, null, false);
偏移量被改变而没有animation。
我也尝试使用垂直偏移调解器:
/// <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
animationVerticalOffset
属性:
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();
Mediator在XAML中声明。 但是这个animation在我的设备上并不stream畅(Lumia 930)。
无论数据虚拟化是否ChangeView
,您都应该使用ChangeView
来滚动animation。
没有看到你的代码ChangeView
不工作的地方,要猜测到底是怎么回事有些困难,但是有几件事情你可以尝试。
第一种方法是在调用ChangeView
之前添加一个Task.Delay(1)
,只是为了给操作系统一些时间来完成其他并发的UI任务。
await Task.Delay(1); scrollViewer.ChangeView(null, scrollViewer.ScrollableHeight, null, false);
第二种方法有点复杂。 我注意到,当ListView
有许多复杂的项目时,从第一个项目到最后一个(从ChangeView
方法)的滚动animation根本不是很stream畅。
这是因为ListView
首先需要通过数据虚拟化来实现/呈现许多项目,然后执行animation滚动。 恕我直言,不是很有效率。
我想到了这一点 – 首先,使用非animationListView.ScrollIntoView
滚动到最后一个项目才能实现它。 然后,调用ChangeView
将偏移量上移到ListView
的ActualHeight * 2
的大小,禁用animation(根据应用程序的滚动体验,可以将其更改为任何大小)。 最后,再次调用ChangeView
以回滚到最后,这次是animation。 这样做会带来更好的滚动体验,因为滚动距离只是ListView
的ActualHeight
。
请记住,当您要滚动的项目已经在用户界面上实现,你不想做任何事情。 您只需计算此项目与ScrollViewer
顶部之间的距离,然后调用ChangeView
滚动到该项目。
我已经把上面的逻辑包含在这个答案的更新2部分中(感谢这个问题,我意识到当虚拟化开启时我的初始答案不起作用:p)。 让我知道你怎么去。
我想这个问题已经在这里回答了:
在ScrollViewer上进行animation(平滑)滚动
还有WinRT XAML Toolki,它提供了“通过animation滚动ScrollViewer到指定偏移量的方法”:
ScrollToVerticalOffset在较新版本的Windows 10(不再使用ScrollViewOffSetMediator扩展控件)中不推荐使用/废弃,而新的ChangeView方法实际上不能提供stream畅的或可控制的animation,因此需要新的解决scheme。 请在这里看到我的答案,它允许一个顺利地animation和缩放ScrollViewer及其内容到任何所需的位置,无论应用程序的最终用户有最初定位的滚动条的位置:
如何滚动到UWP中的元素