Animar (sin problemas) ScrollViewer mediante programación


¿Hay alguna forma de animar sin problemas un desplazamiento vertical de ScrollViewer en el tiempo de ejecución de Windows Phone 8.1?

He intentado usar el método ScrollViewer.ChangeView() y el cambio de desplazamiento vertical no es animado sin importar si establezco el parámetro disableAnimation en verdadero o falso.

Por ejemplo: myScrollViewer.ChangeView(null, myScrollViewer.VerticalOffset + p, null, false); El desplazamiento se cambia sin animación.

También intenté usar un mediador de desplazamiento vertical:

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

Y puedo animar la propiedad VerticalOffset con 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();

El mediador se declara en XAML. Pero esta animación no es suave en mi dispositivo (Lumia 930).

Author: Cœur, 2014-10-05

4 answers

Debe seguir con ChangeView para las animaciones de desplazamiento, independientemente de si la virtualización de datos está activada o no.

Sin ver tu código donde el ChangeView no funciona, es un poco difícil adivinar lo que realmente está pasando, pero hay un par de cosas que puedes probar.

El primer enfoque es agregar un Task.Delay(1) antes de llamar a ChangeView, solo para darle al sistema operativo algo de tiempo para terminar otras tareas concurrentes de la interfaz de usuario.

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

El segundo enfoque es un poco más complejo. Lo que tengo se nota que, cuando tiene muchos elementos complejos en el ListView, la animación de desplazamiento desde el primer elemento hasta el último (desde el método ChangeView) no es muy suave en absoluto.

Esto se debe a que el ListView primero necesita realizar/renderizar muchos elementos a lo largo del camino debido a la virtualización de datos y luego hace el desplazamiento animado. No muy eficiente en mi humilde opinión.

Lo que se me ocurrió es esto: Primero, use un ListView.ScrollIntoView no animado para desplazarse hasta el último elemento solo para realizarlo. Entonces, llame ChangeView para mover el desplazamiento hasta un tamaño de ActualHeight * 2 de ListView con la animación desactivada (puede cambiarlo al tamaño que desee según la experiencia de desplazamiento de su aplicación). Finalmente, llame a ChangeView de nuevo para desplazarse hasta el final, con animación esta vez. Hacer esto dará una experiencia de desplazamiento mucho mejor porque la distancia de desplazamiento es solo el ActualHeight de la ListView.

Tenga en cuenta que cuando el elemento al que desea desplazarse ya está realizado en la interfaz de usuario, no desea hacer nada arriba. Simplemente calcule la distancia entre este elemento y la parte superior del ScrollViewer y llame a ChangeView para desplazarse hasta él.

Ya envolví la lógica anterior en esta respuesta's Actualización 2 sección (gracias a esta pregunta me di cuenta de que mi respuesta inicial no funciona cuando la virtualización está en :p). Hazme saber cómo te va.

 15
Author: Justin XL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:47

Creo que esa pregunta ya ha sido respondida aquí:

Desplazamiento animado (suave) en ScrollViewer

También existe WinRT XAML Toolki, que proporciona"una forma de desplazar un ScrollViewer al desplazamiento especificado con animación":

Http://winrtxamltoolkit.codeplex.com /

 4
Author: SalientGreen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:25:51

Con ScrollToVerticalOffset obsoleto/obsoleto en nuevas versiones de Windows 10 (dejando el control de extensión ScrollViewOffSetMediator ya no funcionando), y el nuevo método ChangeView no proporciona animación suave o controlable, se necesita una nueva solución. Por favor, vea mi respuesta aquí que le permite a uno sin problemas animar y acercar el ScrollViewer y su contenido a cualquier posición deseada, independientemente de dónde el usuario final de la aplicación tenga las barras de desplazamiento inicialmente posición:

Cómo desplazarse a un elemento en UWP

 0
Author: zax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-01 14:30:22

Creo que este artículo es lo que estás buscando y parece que el método que usó está funcionando para ti.

Camino rápido:

  1. Agregue manualmente el parámetro de dependencia de desplazamiento a scrollviewer.

  2. Duplica tu scrollviewer

  3. Usa un animador.

 0
Author: user10141586,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-10 01:28:47