动画(顺利)的ScrollViewer编程 [英] Animate (smoothly) ScrollViewer programatically

查看:107
本文介绍了动画(顺利)的ScrollViewer编程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法顺利动画一个的ScrollViewer S垂直于Windows Phone的8.1运行时偏移?



我使用 ScrollViewer.ChangeView()法和垂直偏移如果我设置不显示动画无论变化尝试了 disableAnimation 参数设置为true或false



例如: myScrollViewer.ChangeView(NULL,myScrollViewer.VerticalOffset + p,空,假);
偏移没有动画更改



我使用的是垂直偏移调解员也尝试:

  ///<总结>转发偏移属性更改到一个的ScrollViewer 
///例如,使水平/ VerticalOffset动画
///中保。
///< /总结>
公共密封类ScrollViewerOffsetMediator:FrameworkElement的
{
///<总结>
///的ScrollViewer实例转发偏置上的变化。
///< /总结>
公众的ScrollViewer ScrollViewer中
{
{返回(的ScrollViewer)的GetValue(ScrollViewerProperty); }
集合{的SetValue(ScrollViewerProperty,值); }
}
公共静态只读的DependencyProperty ScrollViewerProperty =
DependencyProperty.Register(的ScrollViewer,
typeof运算(的ScrollViewer),
typeof运算(ScrollViewerOffsetMediator),
新PropertyMetadata(NULL,OnScrollViewerChanged));
私有静态无效OnScrollViewerChanged(DependencyObject的0,DependencyPropertyChangedEventArgs E)
{
VAR调解=(ScrollViewerOffsetMediator)O;
VAR的ScrollViewer =(的ScrollViewer)(e.NewValue);
如果(空=的ScrollViewer!)
{
scrollViewer.ScrollToVerticalOffset(mediator.VerticalOffset);
}
}

///<总结>
/// VerticalOffset财产转交的ScrollViewer。
///< /总结>
公共双VerticalOffset
{
{返回(双)的GetValue(VerticalOffsetProperty); }
集合{的SetValue(VerticalOffsetProperty,值); }
}
公共静态只读的DependencyProperty VerticalOffsetProperty =
DependencyProperty.Register(VerticalOffset,
typeof运算(双),
typeof运算(ScrollViewerOffsetMediator),
新PropertyMetadata(0.0,OnVerticalOffsetChanged));
公共静态无效OnVerticalOffsetChanged(DependencyObject的0,DependencyPropertyChangedEventArgs E)
{
VAR调解=(ScrollViewerOffsetMediator)O;
如果(空= mediator.ScrollViewer!)
{
mediator.ScrollViewer.ScrollToVerticalOffset((双)(e.NewValue));
}
}

///<总结>
///乘数ScrollableHeight财产转交的ScrollViewer。
///< /总结>
///<&言论GT;
/// 0.0的意思是滚动到顶部; 1.0意思是滚动到屏幕底部。
///< /言论>
公共双ScrollableHeightMultiplier
{
{返回(双)的GetValue(ScrollableHeightMultiplierProperty); }
集合{的SetValue(ScrollableHeightMultiplierProperty,值); }
}
公共静态只读的DependencyProperty ScrollableHeightMultiplierProperty =
DependencyProperty.Register(ScrollableHeightMultiplier,
typeof运算(双),
typeof运算(ScrollViewerOffsetMediator),
新PropertyMetadata(0.0,OnScrollableHeightMultiplierChanged));
公共静态无效OnScrollableHeightMultiplierChanged(DependencyObject的0,DependencyPropertyChangedEventArgs E)
{
VAR调解=(ScrollViewerOffsetMediator)O;
变种的ScrollViewer = mediator.ScrollViewer;
如果(空=的ScrollViewer!)
{
scrollViewer.ScrollToVerticalOffset((双)(e.NewValue)* scrollViewer.ScrollableHeight);
}
}
}

和我可以动画<

 <$:以 DoubleAnimation是 code> VerticalOffset 属性C $ C>故事板SB =新的故事板(); 
DoubleAnimation是DA =新DoubleAnimation是();
da.EnableDependentAnimation = TRUE;
da.From = Mediator.ScrollViewer.VerticalOffset;
da.To = da.From + P;
da.Duration =新的持续时间(TimeSpan.FromMilliseconds(300));
da.EasingFunction =新ExponentialEase(){EasingMode = EasingMode.EaseOut};
Storyboard.SetTarget(DA,中介);
Storyboard.SetTargetProperty(DA,(Mediator.VerticalOffset));
sb.Children.Add(DA);

sb.Begin();



调解员在XAML声明。
,而这部动画我的设备(的Lumia 930)上并不顺利。


解决方案

您应该坚持使用 ChangeView 对于无论数据虚拟化是否是进行滚动动画。



没有看到你的代码,其中 ChangeView 不工作,这是一个有点难以猜测到底发生了什么的但也有一对夫妇的事情,你可以试试。



第一种方法是添加一个 Task.Delay(1)之前调用 ChangeView ,只给操作系统一些时间才能完成关闭其他并发UI任务。

 等待Task.Delay(1); 
scrollViewer.ChangeView(NULL,scrollViewer.ScrollableHeight,空,假);



第二种方法是更复杂一点。我已经注意到的是,当你在的ListView许多复杂的项目,从第一个项目滚动动画到最后(从 ChangeView 法)不是很顺利的。



这是因为的ListView 首先需要实现/渲染一路上由于数据虚拟化,然后多个项目做动画滚动。 。不是很有效,恕我直言



我想出了是这样的 - 首先,使用非动画 ListView.ScrollIntoView 滚动到最后一个项目只是为了得到它实现。然后,调用 ChangeView 移动偏移到一个大小中的ActualHeight * 2 的ListView 动画禁用(你可以把它改成你要根据你的应用程序的滚动经验无论大小)。最后,再次调用 ChangeView 这个时候滚动回末,随着动画。这样做会给一个更好的滚动体验的原因滚动距离,只是在的ActualHeight 的ListView

请,当项目要滚动到已经实现了对用户界面,你不想做任何事情之上。你只是简单地计算这个项目,并在的ScrollViewer 和呼叫 ChangeView 的顶部之间的距离,滚动到它。



我已经包裹在上面这个回答的< STRONG>更新2 部分(感谢这个问题,我意识到,当虚拟化是在我最初的回答不工作:p)。让我知道你怎么走。


Is there a way to smoothly animate a ScrollViewers vertical offset in Windows Phone 8.1 Runtime?

I have tried using the ScrollViewer.ChangeView() method and the change of vertical offset is not animated no matter if I set the disableAnimation parameter to true or false.

For example: myScrollViewer.ChangeView(null, myScrollViewer.VerticalOffset + p, null, false); The offset is changed without animation.

I also tried using a vertical offset mediator:

/// <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);
        }
    }
}

and I can animate the VerticalOffset property with 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 is declared in XAML. But this animation is not smooth on my device (Lumia 930).

解决方案

You should stick with ChangeView for scrolling animations regardless of whether data virtualization is on or not.

Without seeing your code where the ChangeView doesn't work, it's a bit hard to guess what's really going on but there are a couple of things that you can try.

First approach is to add a Task.Delay(1) before calling ChangeView, just to give the OS some time to finish off other concurrent UI tasks.

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

The second approach is a bit more complex. What I've noticed is that, when you have many complex items in the ListView, the scrolling animation from the first item to the last (from the ChangeView method) isn't very smooth at all.

This is because the ListView first needs to realize/render many items along the way due to data virtualization and then does the animated scrolling. Not very efficient IMHO.

What I came up with is this - First, use a non-animated ListView.ScrollIntoView to scroll to the last item just to get it realized. Then, call ChangeView to move the offset up to a size of the ActualHeight * 2 of the ListView with animation disabled (you can change it to whatever size you want based on your app's scrolling experience). Finally, call ChangeView again to scroll back to the end, with animation this time. Doing this will give a much better scrolling experience 'cause the scrolling distance is just the ActualHeight of the ListView.

Keep in mind that when the item you want to scroll to is already realized on the UI, you don't want to do anything above. You simply just calculate the distance between this item and the top of the ScrollViewer and call ChangeView to scroll to it.

I already wrapped the logic above in this answer's Update 2 section (thanks to this question I realized my initial answer doesn't work when virtualization is on :p). Let me know how you go.

这篇关于动画(顺利)的ScrollViewer编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆