2014-10-04 7 views
36

Gibt es eine Möglichkeit, eine ScrollViewer s vertikale Verschiebung in Windows Phone 8.1 Runtime reibungslos zu animieren?Animieren (reibungslos) ScrollViewer programmgesteuert

Ich habe versucht, mit der ScrollViewer.ChangeView() Methode und die Änderung der vertikalen Offset ist nicht animiert, egal, ob ich den disableAnimation Parameter auf wahr oder falsch gesetzt.

Zum Beispiel: myScrollViewer.ChangeView(null, myScrollViewer.VerticalOffset + p, null, false); Der Offset wird ohne Animation geändert.

Ich versuchte auch, einen vertikalen Versatz Vermittler mit:

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

und ich kann mit DoubleAnimation die VerticalOffset Eigenschaft animieren:

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 erklärt in XAML. Aber diese Animation ist nicht glatt auf meinem Gerät (Lumia 930).

+4

Eines könnte man try ist ['WinRTXamlToolkit's' ScrollToVerticalOffsetWithAnimation' Erweiterung] (http://winrtxamltoolkit.codeplex.com/SourceControl/latest#WinRTXamlToolkit/WinRTXamlToolkit.Shared/Controls/Extensions/ScrollViewerExtensions.cs). Sie können es manuell implementieren oder die Bibliothek über Nuget hinzufügen. –

+2

Ich glaube nicht, es gibt einen Weg, um es komplett reibungslos zu machen. Diese Art von Animation ist wahrscheinlich nicht hardwarebeschleunigt. –

+0

Nein ... http://sviluppomobile.blogspot.fi/2013/04/smooth-scrolling-content-on-windows.html? –

Antwort

14

Sie sollten mit ChangeView für Scroll-Animationen bleiben, unabhängig davon, ob die Datenvirtualisierung aktiviert ist oder nicht.

Ohne Ihren Code zu sehen, wo die ChangeView nicht funktioniert, ist es ein bisschen schwer zu erraten, was wirklich los ist, aber es gibt ein paar Dinge, die Sie ausprobieren können.

Der erste Ansatz besteht darin, einen Task.Delay(1) vor dem Aufruf ChangeView hinzuzufügen, nur um dem Betriebssystem einige Zeit zu geben, andere gleichzeitige UI-Aufgaben zu beenden.

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

Der zweite Ansatz ist ein bisschen komplexer. Was ich bemerkt habe ist, dass, wenn Sie viele komplexe Elemente in der ListView haben, die Scroll-Animation vom ersten Element bis zum letzten (von der ChangeView-Methode) überhaupt nicht sehr glatt ist.

Dies liegt daran, die ListView ersten Bedürfnisse zu realisieren/viele Gegenstände auf dem Weg durch Daten Virtualisierung machen und dann tut das animierte Scrollen. Nicht sehr effizient IMHO.

Was ich herausgefunden habe, ist dies - Verwenden Sie zuerst eine nicht animierte ListView.ScrollIntoView, um zum letzten Element zu blättern, nur um es zu realisieren. Dann rufen ChangeView den Offset bis zu einer Größe des ActualHeight * 2 der ListView mit Animation zu bewegen deaktiviert (Sie können es ändern, was Größe wollen Sie basierend auf Ihrer App-Scrolling Erfahrung). Schließlich rufen ChangeView wieder zurück bis zum Ende zu scrollen, diesmal mit Animation. Dadurch wird eine viel bessere Scrollen Erfahrung Ursache des Scroll-Abstandes gibt, ist nur die ActualHeight der ListView.

Beachten Sie, dass, wenn das Element, das Sie bewegen möchten, bereits auf der Benutzeroberfläche realisiert ist, können Sie nichts über tun wollen.Sie berechnen einfach den Abstand zwischen diesem Objekt und dem oberen Rand der ScrollViewer und rufen ChangeView auf, um zu diesem Objekt zu blättern.

Ich wickelte bereits die Logik oben in dieser answer ‚s Update 2 Abschnitt (dank dieser Frage, die ich meine erste Antwort funktioniert nicht realisiert, wenn die Virtualisierung auf ist: p). Lass mich wissen, wie du gehst.

+2

Der erste Ansatz machte die 'ChangeView' glatt, wegen der' Task.Delay'. Ich hatte keine Ahnung, dass das so viel helfen würde. Vielen Dank. –

4

denke ich, dass diese Frage bereits hier beantwortet wurde:

Animated (Smooth) scrolling on ScrollViewer

Es gibt auch den WinRT XAML Toolki, die „eine Möglichkeit, eine Scroll mit vorgeschriebenem Offset mit Animation blättern“ bietet:

+3

Wenn Sie die Quelle von [ScrollViewerExtensions.cs] (http://winrtxamltoolkit.codeplex.com/SourceControl/latest#WinRTXamlToolkit/WinRTXamlToolkit.Shared/Controls/Extensions/ScrollViewerExtensions.cs) betrachten, ist die Methode, die die Animation erstellt mit dem Namen 'ScrollToVerticalOffsetWithAnimation', und Sie können die Zeile' da.EnableDependentAnimation = true' sehen, was bedeutet, dass die Animation nicht auf dem Kompositions-Thread ausgeführt wird, was bedeutet, dass sie möglicherweise nicht glatt läuft, und das ist die Hauptfrage, wie den Scrollviewer mit ** unabhängigen Animationen zu animieren ** –

+0

Keiner von denen ist relevant für WinRT/Windows10 –

0

Mit ScrollToVerticalOffset in neueren Builds von Windows 10 veraltet/veraltet (das ScrollViewOffSetMediator-Erweiterungssteuerelement funktioniert nicht mehr) und die neue ChangeView-Methode, die keine glatte oder steuerbare Animation bietet, ist eine neue Lösung erforderlich. Bitte beachten Sie meine Antwort hier, die man glatt belebter ermöglicht und zoomen Sie die Scroll und sein Inhalt in jede gewünschte Position, unabhängig davon, wo die Endbenutzers Anwendung die Bildlaufleisten hat zunächst positioniert:

How to scroll to element in UWP