Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erläuterung von Animationsbeispielen mit Shape

Detaillierte Erläuterung von Animationsbeispielen mit Shape

零下一度
零下一度Original
2017-06-23 15:05:471629Durchsuche

Im vorherigen Artikel ging es fast ausschließlich um die Anwendung von DoubleAnimation, und in diesem Artikel geht es um PointAnimation.

1. Verwenden Sie PointAnimation

Die Verwendung von PointAnimation kann Shape verformen, aber tatsächlich sehe ich nicht viele Leute, die es auf diese Weise verwenden. Schließlich ist dies bei den meisten von WPF erstellten Programmen nicht erforderlich so schick.

1.1 Verwenden von PointAnimation auf Wenn Sie es sich nicht merken können, verlassen Sie sich am besten auf die Blend-Generierung.

1.2 Verwendung von PointAnimation im Code
<Storyboard x:Name="Storyboard2"            RepeatBehavior="Forever"            AutoReverse="True"            Duration="0:0:4"><PointAnimation Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.StartPoint)"                    Storyboard.TargetName="Path2"                    To="0,0"                    EnableDependentAnimation="True" /><PointAnimation Storyboard.TargetProperty="(Path.Data).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(LineSegment.Point)"                    Storyboard.TargetName="Path2"                    To="100,0"                    EnableDependentAnimation="True" /><ColorAnimation To="#FF85C82E"                    Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"                    Storyboard.TargetName="Path2" /></Storyboard>…<Path Margin="0,20,0,0"      x:Name="Path2"      Fill="GreenYellow"><Path.Data><PathGeometry><PathFigure StartPoint="50,0"><LineSegment Point="50,0" /><LineSegment Point="0,100" /><LineSegment Point="0,100" /><LineSegment Point="100,100" /><LineSegment Point="100,100" /></PathFigure></PathGeometry></Path.Data></Path>
Wenn viele Punkte vorhanden sind, z. B. Diagramme, wird PointAnimation normalerweise im C#-Code verwendet:

Detaillierte Erläuterung von Animationsbeispielen mit Shape

Da Sie direkt

können, kann die Eigenschaftspfad-Syntax sehr einfach sein.
_storyboard = new Storyboard();
Random random = new Random();for (int i = 0; i < _pathFigure.Segments.Count; i++)
{var animation = new PointAnimation { Duration = TimeSpan.FromSeconds(3) };
    Storyboard.SetTarget(animation, _pathFigure.Segments[i]);
    Storyboard.SetTargetProperty(animation, "(LineSegment.Point)");
    animation.EnableDependentAnimation = true;
    animation.EasingFunction = new QuarticEase { EasingMode = EasingMode.EaseOut };
    animation.To = new Point((_pathFigure.Segments[i] as LineSegment).Point.X, (i % 2 == 0 ? 1 : -1) * i * 1.2 + 60);
    _storyboard.Children.Add(animation);
}
_storyboard.Begin();
2. PointAnimation erweitern

Die Animationen in den beiden oben genannten Beispielen sind relativ einfach. Wenn sie komplizierter sind, muss XAML- oder C#-Code sehr kompliziert geschrieben werden. Ich habe auf diese Webseite verwiesen und wollte eine ähnliche Animation erstellen, stellte jedoch fest, dass ich viel XAML schreiben musste, also habe ich es aufgegeben, PointAnimation für die Implementierung zu verwenden. Die Kernanimation dieser Seite ist dieser HTML-Code: Detaillierte Erläuterung von Animationsbeispielen mit Shape

SetTarget

Sie benötigen nur eine Reihe von Punkten, um die Animation aller Punkte zu steuern, was in der Tat viel effizienter ist als PointAnimation. In WPF können Sie eine PointCollectionAnimation durch Erben der Timeline implementieren. Weitere Informationen finden Sie in diesem Projekt. Obwohl die Timeline-Klasse von UWP nicht geschlossen ist, weiß ich leider nicht, wie ich eine benutzerdefinierte Animation erben und ableiten kann.

Zu diesem Zeitpunkt müssen Sie Ihre Denkweise ein wenig ändern. DoubleAnimation kann wie folgt verstanden werden: Storyboard übergibt TimeSpan an DoubleAnimation, und DoubleAnimation verwendet diesen TimeSpan (manchmal muss er mit EasingFunction kombiniert werden), um den aktuellen Wert des Zielattributs zu berechnen, und übergibt ihn schließlich an das Zielattribut, wie in der Abbildung gezeigt Folgende Abbildung:

<polygon fill="#FFD41D" points="97.3,0 127.4,60.9 194.6,70.7 145.9,118.1 157.4,185.1 97.3,153.5 37.2,185.1 48.6,118.1 0,70.7     67.2,60.9">  
      <animate id="animation-to-check" begin="indefinite" fill="freeze" attributeName="points" dur="500ms" to="110,58.2 147.3,0 192.1,29 141.7,105.1 118.7,139.8 88.8,185.1 46.1,156.5 0,125 23.5,86.6     71.1,116.7"/>
      <animate id="animation-to-star" begin="indefinite" fill="freeze" attributeName="points" dur="500ms" to="97.3,0 127.4,60.9 194.6,70.7 145.9,118.1 157.4,185.1 97.3,153.5 37.2,185.1 48.6,118.1 0,70.7     67.2,60.9"/>  </polygon>
In diesem Fall können Sie auch dieses berechnete Double erhalten und dann den Ziel-PointCollection-Wert über den Konverter berechnen:

Angenommen, Sie sagen diesem Konverter: Wenn der eingehende Double-Wert (mit dem Namen Progress) 0 ist, ist PointCollection {0,0 1,1...}, wenn Progress 100 ist, ist PointCollection {1,1 2,2 ...}, wenn Progress einen dieser Werte erreicht. Die Zeitberechnungsmethode lautet: Detaillierte Erläuterung von Animationsbeispielen mit Shape

Damit ist der Konvertierungsprozess von TimeSpan in PointCollection abgeschlossen. Dann gibt es noch die in XAML definierte Verwendungsweise. Bezug nehmend auf die obige PointCollectionAnimation: Obwohl es einen zusätzlichen Konverter gibt, sollte das XAML prägnant genug sein: Detaillierte Erläuterung von Animationsbeispielen mit Shape

Am Ende habe ich mich dafür entschieden, diesen Konverter
private PointCollection GetCurrentPoints(PointCollection fromPoints, PointCollection toPoints, double percentage)
{var result = new PointCollection();for (var i = 0;
        i < Math.Min(fromPoints.Count, toPoints.Count);
        i++)
    {
        var x = (1 - percentage / 100d) * fromPoints[i].X + percentage / 100d * toPoints[i].X;
        var y = (1 - percentage / 100d) * fromPoints[i].Y + percentage / 100d * toPoints[i].Y;

        result.Add(new Point(x, y));
    }return result;
}
zu nennen. Es ist ersichtlich, dass Polygon Points an ProgressToPointCollectionBridge bindet und DoubleAnimation ProgressToPointCollectionBridge.Progress ändert, wodurch Points geändert wird. Die Einfachheit von XAML ist durchaus zufriedenstellend. Wenn Sie mehrere Punkte bedienen müssen, bietet es große Vorteile gegenüber PointAnimation.

Die laufenden Ergebnisse lauten wie folgt:

<local:ProgressToPointCollectionBridge x:Name="ProgressToPointCollectionBridge"><PointCollection>97.3,0 127.4,60.9 194.6,70.7 145.9,118.1 157.4,185.1 97.3,153.5 37.2,185.1 48.6,118.1 0,70.7 67.2,60.9</PointCollection><PointCollection>110,58.2 147.3,0 192.1,29 141.7,105.1 118.7,139.8 88.8,185.1 46.1,156.5 0,125 23.5,86.6 71.1,116.7</PointCollection></local:ProgressToPointCollectionBridge><Storyboard x:Name="Storyboard1"            FillBehavior="HoldEnd"><DoubleAnimation Duration="0:0:2"                        To="100"                        FillBehavior="HoldEnd"                        Storyboard.TargetProperty="(local:ProgressToPointCollectionBridge.Progress)"                        Storyboard.TargetName="ProgressToPointCollectionBridge"                        EnableDependentAnimation="True"/></Storyboard>…<Polygon x:Name="polygon"            Points="{Binding Source={StaticResource ProgressToPointCollectionBridge},Path=Points}"            Stroke="DarkOliveGreen"            StrokeThickness="2"            Height="250"            Width="250"            Stretch="Fill" />

Vollständiges XAML: ProgressToPointCollectionBridge

ProgressToPointCollectionBridge:Detaillierte Erläuterung von Animationsbeispielen mit Shape

3. Fazit
<UserControl.Resources><local:ProgressToPointCollectionBridge x:Name="ProgressToPointCollectionBridge"><PointCollection>97.3,0 127.4,60.9 194.6,70.7 145.9,118.1 157.4,185.1 97.3,153.5 37.2,185.1 48.6,118.1 0,70.7 67.2,60.9</PointCollection><PointCollection>110,58.2 147.3,0 192.1,29 141.7,105.1 118.7,139.8 88.8,185.1 46.1,156.5 0,125 23.5,86.6 71.1,116.7</PointCollection></local:ProgressToPointCollectionBridge><Storyboard x:Name="Storyboard1"                FillBehavior="HoldEnd"><DoubleAnimation Duration="0:0:2"                            To="100"                            FillBehavior="HoldEnd"                            Storyboard.TargetProperty="(local:ProgressToPointCollectionBridge.Progress)"                            Storyboard.TargetName="ProgressToPointCollectionBridge"                            EnableDependentAnimation="True"><DoubleAnimation.EasingFunction><ElasticEase EasingMode="EaseInOut" /></DoubleAnimation.EasingFunction></DoubleAnimation><ColorAnimation Duration="0:0:2"                        To="#FF48F412"                        Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"                        Storyboard.TargetName="polygon"                        d:IsOptimized="True"><ColorAnimation.EasingFunction><ElasticEase EasingMode="EaseInOut" /></ColorAnimation.EasingFunction></ColorAnimation></Storyboard></UserControl.Resources><Grid x:Name="LayoutRoot"        Background="White"><Polygon x:Name="polygon"                Points="{Binding Source={StaticResource ProgressToPointCollectionBridge},Path=Points}"                Stroke="DarkOliveGreen"                StrokeThickness="2"                Height="250"                Width="250"                Stretch="Fill"                Fill="#FFEBF412" /></Grid>
Wenn DoubleAnimation „die Double-Eigenschaft des Ziels animiert“, dann kann man sagen, dass PointAnimation „den Punkt des Ziels animiert“. .X und Point. Y zwei Double-Eigenschaften werden gleichzeitig animiert“, ColorAnimation ist „die vier Int-Eigenschaften Color.A, R, G, B des Ziels werden gleichzeitig animiert“. So verstanden sind PointAnimation und ColorAnimation lediglich Erweiterungen von DoubleAnimation. Darüber hinaus sollte DoubleAnimation in der Lage sein, die Animation aller Arten von Attributen zu erweitern. Ich weiß jedoch nicht, wie man Animationen in UWP anpasst, und kann sie nur durch die Kompromissmethode in diesem Artikel erweitern. Obwohl XAML komplizierter geschrieben werden muss, hat es auch seine Vorteile:

[ContentProperty(Name = nameof(Children))]public class ProgressToPointCollectionBridge : DependencyObject
{public ProgressToPointCollectionBridge()
    {
        Children = new ObservableCollection<PointCollection>();
    }/// <summary>///     获取或设置Points的值/// </summary>public PointCollection Points
    {get { return (PointCollection) GetValue(PointsProperty); }set { SetValue(PointsProperty, value); }
    }/// <summary>///     获取或设置Progress的值/// </summary>public double Progress
    {get { return (double) GetValue(ProgressProperty); }set { SetValue(ProgressProperty, value); }
    }/// <summary>///     获取或设置Children的值/// </summary>public Collection<PointCollection> Children
    {get { return (Collection<PointCollection>) GetValue(ChildrenProperty); }set { SetValue(ChildrenProperty, value); }
    }protected virtual void OnProgressChanged(double oldValue, double newValue)
    {UpdatePoints();
    }protected virtual void OnChildrenChanged(Collection<PointCollection> oldValue, Collection<PointCollection> newValue)
    {var oldCollection = oldValue as INotifyCollectionChanged;if (oldCollection != null)
            oldCollection.CollectionChanged -= OnChildrenCollectionChanged;var newCollection = newValue as INotifyCollectionChanged;if (newCollection != null)
            newCollection.CollectionChanged += OnChildrenCollectionChanged;UpdatePoints();
    }private void OnChildrenCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {UpdatePoints();
    }private void UpdatePoints()
    {if (Children == null || Children.Any() == false)
        {
            Points = null;
        }else if (Children.Count == 1)
        {var fromPoints = new PointCollection();for (var i = 0; i < Children[0].Count; i++)
                fromPoints.Add(new Point(0, 0));var toPoints = Children[0];
            Points = GetCurrentPoints(fromPoints, toPoints, Progress);
        }else{var rangePerSection = 100d / (Children.Count - 1);var fromIndex = Math.Min(Children.Count - 2, Convert.ToInt32(Math.Floor(Progress / rangePerSection)));
            fromIndex = Math.Max(fromIndex, 0);var toIndex = fromIndex + 1;
            PointCollection fromPoints;if (fromIndex == toIndex)
            {
                fromPoints = new PointCollection();for (var i = 0; i < Children[0].Count; i++)
                    fromPoints.Add(new Point(0, 0));
            }else{
                fromPoints = Children.ElementAt(fromIndex);
            }var toPoints = Children.ElementAt(toIndex);
            var percentage = (Progress / rangePerSection - fromIndex) * 100;

            Points = GetCurrentPoints(fromPoints, toPoints, percentage);
        }
    }private PointCollection GetCurrentPoints(PointCollection fromPoints, PointCollection toPoints, double percentage)
    {var result = new PointCollection();for (var i = 0;
            i < Math.Min(fromPoints.Count, toPoints.Count);
            i++)
        {
            var x = (1 - percentage / 100d) * fromPoints[i].X + percentage / 100d * toPoints[i].X;
            var y = (1 - percentage / 100d) * fromPoints[i].Y + percentage / 100d * toPoints[i].Y;

            result.Add(new Point(x, y));
        }return result;
    }#region DependencyProperties#endregion}
Sie müssen nicht zu viel über Animationsklassen wissen, sondern nur Grundkenntnisse wie Abhängigkeiten Eigenschaften und Bindung.

ändert sich aufgrund von Änderungen in der Animations-API nicht und ist mit WPF, Silverlight und UWP kompatibel (wahrscheinlich habe ich diese Codes nicht wirklich auf WPF getestet).

  • Der Code ist einfach genug, sodass die Schritte zur Berechnung von TimeSpan und EasingFunction entfallen. Mit geringfügigen Änderungen kann es auch in ein generisches

    umgewandelt werden, um andere Datentypen als PointCollection zu unterstützen.
  • Basierend auf dem vorherigen Artikel bin ich immer der Meinung, dass alle Funktionen, die nicht von UWP bereitgestellt werden, in Zukunft durch alternative Methoden implementiert werden können. Bindung und DependencyProperty sind wirklich die besten für UWP-Entwickler .
  • 4. Referenz

    AnimationBridge 808ed36a4929ba137db2b9ee76c79186Wie SVG Shape Morphing funktioniert

    Gadal MetaSyllabus

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung von Animationsbeispielen mit Shape. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn