c# windows-runtime winrt-xaml windows-phone-8.1

c# - Animar(sin problemas) ScrollViewer mediante programación



windows-runtime winrt-xaml (3)

¿Hay alguna manera de animar sin problemas el desplazamiento vertical de un ScrollViewer en Windows Phone 8.1 Runtime?

He intentado utilizar el método ScrollViewer.ChangeView() y el cambio de desplazamiento vertical no está animado, independientemente de si configuro 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();

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



Debe seguir con ChangeView para desplazar animaciones independientemente de si la virtualización de datos está ChangeView o no.

Sin ver el código donde 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 finalizar otras tareas de IU simultáneas.

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

El segundo enfoque es un poco más complejo. Lo que noté es que, cuando tiene muchos elementos complejos en ListView , la animación de desplazamiento del primer elemento al último (del método ChangeView ) no es muy ChangeView .

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

Lo que se me ocurrió es esto: primero, use un ListView.ScrollIntoView no animado para desplazarse al último elemento solo para que se realice. Luego, llame a ChangeView para mover el desplazamiento hasta un tamaño del ActualHeight * 2 del ListView con la animación desactivada (puede cambiarlo al tamaño que desee en función de la experiencia de desplazamiento de su aplicación). Finalmente, vuelva a llamar a ChangeView para volver al final, con animación esta vez. Hacer esto proporcionará una experiencia de desplazamiento mucho mejor porque la distancia de desplazamiento es solo la ActualHeight del ListView .

Tenga en cuenta que cuando el elemento al que desea desplazarse ya se haya realizado en la interfaz de usuario, no desea hacer nada más arriba. Simplemente calcula la distancia entre este elemento y la parte superior del ScrollViewer y llama a ChangeView para desplazarte a él.

Ya completé la lógica de arriba en la sección Actualización 2 de esta respuesta (gracias a esta pregunta me di cuenta de que mi respuesta inicial no funciona cuando la virtualización está activada: p). Déjame saber cómo vas.


Con ScrollToVerticalOffset en desuso / obsoleto en compilaciones más recientes de Windows 10 (dejando que el control de extensión ScrollViewOffSetMediator ya no funcione), y el nuevo método ChangeView que no proporciona una animación fluida o controlable, se necesita una nueva solución. Por favor, consulte mi respuesta aquí, que le permite a uno animar y hacer zoom suavemente el ScrollViewer y sus contenidos a cualquier posición deseada, independientemente de dónde el usuario final de la aplicación tenga las barras de desplazamiento inicialmente posicionadas:

Cómo desplazarse a un elemento en UWP