gpt4 book ai didi

c# - 以编程方式(平滑地)动画化 ScrollViewer

转载 作者:IT王子 更新时间:2023-10-29 04:02:47 25 4
gpt4 key购买 nike

有没有办法在 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);
}
}
}

我可以使用 DoubleAnimationVerticalOffset 属性设置动画:

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)上并不流畅。

最佳答案

无论是否启用数据虚拟化,您都应该坚持使用 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

请记住,当您要滚动到的项目已在 UI 上实现时,您不想在上面执行任何操作。您只需计算此项与 ScrollViewer 顶部之间的距离,然后调用 ChangeView 滚动到它。

我已经在这个 answer 中包含了上面的逻辑的 Update 2 部分(由于这个问题,我意识到当虚拟化开启时我的初始答案不起作用 :p)。让我知道你过得怎么样。

关于c# - 以编程方式(平滑地)动画化 ScrollViewer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26198000/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com