有没有办法在Windows Phone 8.1 Runtime中平滑动画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);
}
}
}
我可以使用VerticalOffset
为DoubleAnimation
属性设置动画:
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中声明。 但是这个动画在我的设备上并不流畅(Lumia 930)。
答案 0 :(得分:15)
无论数据虚拟化是否开启,您都应该坚持使用ChangeView
来滚动动画。
如果没有看到ChangeView
不起作用的代码,就很难猜出实际发生了什么,但有几件事你可以试试。
第一种方法是在调用Task.Delay(1)
之前添加ChangeView
,只是为了给操作系统一些时间来完成其他并发UI任务。
await Task.Delay(1);
scrollViewer.ChangeView(null, scrollViewer.ScrollableHeight, null, false);
第二种方法有点复杂。我注意到的是,当ListView
中有许多复杂项目时,从第一项到最后一项(来自ChangeView
方法)的滚动动画根本不是很平滑。
这是因为ListView
首先需要实现/渲染许多项目,因为数据虚拟化然后进行动画滚动。效率不高的恕我直言。
我想出的是 - 首先,使用非动画ListView.ScrollIntoView
滚动到最后一项只是为了实现它。然后,调用ChangeView
将偏移量移动到ActualHeight * 2
ListView
的大小并禁用动画(您可以根据应用的滚动体验将其更改为您想要的任何大小) 。最后,再次调用ChangeView
以回滚到最后,这次是动画。这样做会提供更好的滚动体验,因为滚动距离只是ActualHeight
的{{1}}。
请记住,当您想要滚动到的项目已在UI上实现时,您不希望在上面执行任何操作。您只需计算此项与ListView
顶部之间的距离,然后调用ScrollViewer
滚动到该项目。
我已将此逻辑包含在此answer的 Update 2 部分中(由于这个问题,我意识到我的初始答案在启用虚拟化时不起作用:p)。让我知道你是怎么走的。
答案 1 :(得分:4)
我认为这个问题已在这里得到解答:
Animated (Smooth) scrolling on ScrollViewer
还有WinRT XAML Toolki,它提供了一种将ScrollViewer滚动到带动画的指定偏移量的方法&#34;:
答案 2 :(得分:0)
在新版Windows 10中不推荐使用ScrollToVerticalOffset(让ScrollViewOffSetMediator扩展控件不再工作),而新的ChangeView方法实际上并没有提供平滑或可控制的动画,因此需要一个新的解决方案。请在此处查看我的答案,无论应用程序的最终用户最初放置滚动条的位置如何,都可以顺利地动画并将ScrollViewer及其内容缩放到任何所需位置:
答案 3 :(得分:0)