Анимировать (плавно) ScrollViewer программно

есть ли способ плавно анимировать ScrollViewers вертикальное смещение в среде выполнения Windows Phone 8.1?

Я пробовал использовать 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();

посредник объявлен в XAML. Но эта анимация не гладкая на моем устройстве (Lumia 930).

4 ответов


вы должны придерживаться ChangeView для прокрутки анимации независимо от того, виртуализации данных или нет.

не видя ваш код, где ChangeView не работает, это немного трудно догадаться, что на самом деле происходит, но есть несколько вещей, которые вы можете попробовать.

первый подход-добавить Task.Delay(1) перед вызовом ChangeView, просто чтобы дать ОС некоторое время, чтобы закончить другие параллельные задачи пользовательского интерфейса.

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

второй подход немного сложнее. Я заметил, что когда у вас много сложных элементов ListView прокрутка анимации от первого элемента до последнего (с ChangeView метод) не очень гладко вообще.

это так ListView сначала необходимо реализовать / визуализировать много элементов на этом пути из-за виртуализации данных, а затем делает анимированную прокрутку. Не очень эффективный ИМХО.

то, что я придумал, это-во-первых, используйте не анимированный ListView.ScrollIntoView в прокрутите до последнего пункта, чтобы он был реализован. Тогда звоните ChangeView чтобы переместить смещение до размера ActualHeight * 2 на ListView с анимацией отключена (вы можете изменить его на любой размер, который вы хотите на основе опыта прокрутки вашего приложения). Наконец, звоните ChangeView снова прокрутите назад до конца, на этот раз с анимацией. Это даст гораздо лучший опыт прокрутки, потому что расстояние прокрутки-это просто ActualHeight на ListView.

имейте в виду, что когда элемент, который вы хотите прокрутить, уже реализован в пользовательском интерфейсе, вы не хотите ничего делать выше. Вы просто просто вычислить расстояние между этим элементом и верхней части ScrollViewer, а вызов ChangeView выделите его.

я уже обернул логику выше в этом ответ ' s обновление 2 раздел (благодаря этому вопросу я понял, что мой первоначальный ответ не работает, когда виртуализация включена: p). Дай мне знать, как пойдешь.


Я думаю, что на этот вопрос уже ответили здесь:

анимированная (плавная) прокрутка на ScrollViewer

существует также WinRT XAML Toolki, который предоставляет "способ прокрутки ScrollViewer до указанного смещения с анимацией":

http://winrtxamltoolkit.codeplex.com/


с ScrollToVerticalOffset устарел / устарел в новых сборках Windows 10 (оставляя scrollviewoffsetmediator extension control больше не работает), и новый метод ChangeView фактически не обеспечивает плавную или управляемую анимацию, новое решение необходимо. Пожалуйста, посмотрите мой ответ здесь, который позволяет ровно анимировать и масштабировать ScrollViewer и его содержимое в любую нужную позицию, независимо от того, где конечный пользователь приложения имеет полосы прокрутки первоначально позиционируется:

как прокрутить до элемента в UWP


Я считаю в этой статье это то, что вы ищете, и кажется, что метод, который он использовал, работает на вас.

Быстрый Способ:

  1. добавить параметр зависимости смещения вручную в scrollviewer.

  2. дублировать scrollviewer

  3. используйте аниматор.