Animer (en douceur) ScrollViewer programmatically

y a-t-il un moyen d'animer en douceur un décalage vertical de ScrollViewer dans Windows Phone 8.1 Runtime?

j'ai essayé d'utiliser la méthode ScrollViewer.ChangeView() et le changement de décalage vertical n'est pas animé peu importe si je mets le paramètre disableAnimation à vrai ou faux.

par exemple: myScrollViewer.ChangeView(null, myScrollViewer.VerticalOffset + p, null, false); L'offset est modifié sans animation.

j'ai aussi essayé d'utiliser un médiateur de décalage 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);
        }
    }
}

et je peux animer la propriété VerticalOffset avec 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();

médiateur est déclaré dans XAML. Mais cette animation n'est pas fluide sur mon appareil (Lumia 930).

36
demandé sur Cœur 2014-10-05 03:03:35

4 réponses

vous devez vous en tenir à ChangeView pour faire défiler les animations, que la virtualisation des données soit activée ou non.

sans voir votre code où le ChangeView ne fonctionne pas, il est un peu difficile de deviner ce qui se passe vraiment, mais il ya un certain nombre de choses que vous pouvez essayer.

la première approche consiste à ajouter un Task.Delay(1) avant d'appeler ChangeView , juste pour donner au système D'exploitation un peu de temps pour terminer d'autres tâches D'interface utilisateur simultanées.

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

la seconde approche est un peu plus complexe. Ce que j'ai remarqué, c'est que , lorsque vous avez beaucoup d'éléments complexes dans le ListView , l'animation défilante du premier élément au dernier (de la méthode ChangeView ) n'est pas très lisse du tout.

c'est parce que le ListView a d'abord besoin de réaliser/rendre de nombreux éléments en cours de route en raison de la virtualisation des données et fait ensuite le défilement animé. Pas très efficace IMHO.

ce que j'ai trouvé est ceci - D'abord, utilisez un ListView.ScrollIntoView non animé pour faire défiler jusqu'au dernier article juste pour le réaliser. Ensuite, appelez ChangeView pour déplacer l'offset jusqu'à une taille du ActualHeight * 2 du ListView avec l'animation désactivée (vous pouvez le changer à n'importe quelle taille que vous voulez basé sur l'expérience de défilement de votre application). Enfin, appelez ChangeView de nouveau pour revenir à la fin, avec animation cette fois. Faire ceci donnera un bien meilleur défilement l'expérience parce que la distance de défilement est juste le ActualHeight du ListView .

gardez à l'esprit que lorsque l'article que vous voulez faire défiler est déjà réalisé sur L'UI, vous ne voulez pas faire quoi que ce soit ci-dessus. Vous n'avez qu'à calculer la distance entre cet article et le haut du ScrollViewer et appeler ChangeView pour y faire défiler.

j'ai déjà enveloppé la logique ci-dessus dans ce réponse 's Mettre à jour la section 2 (grâce à cette question, j'ai réalisé que ma réponse initiale ne fonctionne pas lorsque la virtualisation est activée :p). Permettez-moi de savoir comment vous allez.

15
répondu Justin XL 2017-05-23 12:17:47

je pense que cette question a déjà été répondu ici:

animation (lisse) défilant sur ScrollViewer

il y a aussi le WinRT XAML Toolki, qui fournit "un moyen de faire défiler un ScrollViewer à l'offset spécifié avec l'animation":

http://winrtxamltoolkit.codeplex.com /

4
répondu SalientGreen 2017-05-23 12:25:51

avec ScrollToVerticalOffset obsolète / obsolète dans les nouvelles constructions de Windows 10 (laissant le contrôle D'extension ScrollViewOffSetMediator ne fonctionne plus), et la nouvelle méthode ChangeView ne fournissant pas réellement l'animation lisse ou contrôlable, une nouvelle solution est nécessaire. S'il vous plaît voir ma réponse ici qui permet de en douceur animer et zoomer le ScrollViewer et son contenu à n'importe quelle position désirée, indépendamment de l'endroit où l'utilisateur final de l'application a le scrollbars initialement positionné:

Comment faites défiler jusqu'à l'élément en UWP

0
répondu zax 2017-08-01 14:30:22

je crois cet article est ce que vous cherchez et il semble que la méthode qu'il a utilisée est de travailler pour vous.

Rapide": 151960920"

  1. ajouter manuellement le paramètre de dépendance d'offset à scrollviewer .

  2. dupliquez votre scrollviewer

  3. utilisez un animateur.

0
répondu user10141586 2018-08-10 01:28:47