Dela via


Nyckelbildsanimeringar och animeringar med interpoleringsfunktioner

Linjära nyckelramsanimeringar, nyckelramsanimeringar med ett KeySpline-värde eller lättande funktioner är tre olika tekniker för ungefär samma scenario: att skapa en storyboardad animering som är lite mer komplex och som använder ett icke-linjärt animeringsbeteende från ett starttillstånd till ett sluttillstånd.

Förutsättningar

Kontrollera att du har läst avsnittet Storyboarded-animeringar . Det här avsnittet bygger på de animeringsbegrepp som förklaras i Storyboarded-animeringar och kommer inte att gå igenom dem igen. Till exempel beskriver Storyboarded-animeringar hur du riktar in dig på animeringar, storyboards som resurser, egenskapsvärden för tidslinjen , till exempel Varaktighet, FillBehavior och så vidare.

Animera med hjälp av nyckelramsanimeringar

Animeringar med nyckelramar tillåter mer än ett målvärde som nås vid en punkt längs tidslinjen för animering. Med andra ord kan varje nyckelram ange ett annat mellanliggande värde, och den sista nyckelramen som nås är det slutliga animeringsvärdet. Genom att ange flera värden för att animera kan du göra mer komplexa animeringar. Animeringar med nyckelramar möjliggör också olika interpoleringslogik, som var och en implementeras som en annan Nyckelbildrute-underklass per animeringstyp. Mer specifikt har varje animeringstyp för nyckelramar en diskret, linjär, spline - och lättnadsvariant för sin KeyFrame-klass för att ange sina nyckelramar. Om du till exempel vill ange en animering som riktar sig mot en Double och använder nyckelramar kan du deklarera nyckelramar med DiscreteDoubleKeyFrame, LinearDoubleKeyFrame, SplineDoubleKeyFrame och EasingDoubleKeyFrame. Du kan använda alla dessa typer i en enda KeyFrames-samling för att ändra interpolationen varje gång en ny nyckelram nås.

För interpoleringsbeteende styr varje nyckelram interpolationen tills KeyTime har nåtts. Dess värde nås vid den tidpunkten också. Om det finns fler nyckelramar utöver blir värdet startvärdet för nästa nyckelram i en sekvens.

Om det inte finns någon nyckelram med KeyTime på "0:0:0" i början av animeringen är startvärdet det icke-animerade värdet för egenskapen. Det här liknar hur en Från/Till-Genom-animering/ fungerar om det saknas Från.

Varaktigheten för en nyckelramsanimering är implicit varaktigheten lika med det högsta KeyTime-värdet som angetts i någon av dess nyckelramar. Du kan ange en explicit varaktighet om du vill, men var försiktig så att den inte är kortare än en KeyTime i dina egna nyckelramar eller så klipper du av en del av animeringen.

Förutom Varaktighet kan du ange alla tidslinjebaserade egenskaper för en nyckelramanimation, precis som du kan med en Från/Till/By-animering, eftersom nyckelramanimationsklasserna också härleds från Tidslinje. Dessa är:

  • AutoReverse: När den sista nyckelbilden har nåtts upprepas bildrutorna i omvänd ordning från slutet. Detta fördubblar animeringens synliga varaktighet.
  • BeginTime: fördröjer starten av animeringen. Tidslinjen för KeyTime-värdena i ramarna börjar inte räknas förrän BeginTime har nåtts, så det finns ingen risk för att skära av bildrutor
  • FillBehavior: styr vad som händer när den sista nyckelramen nås. FillBehavior har ingen effekt på mellanliggande nyckelramar.
  • RepeatBehavior:
    • Om värdet är För evigt upprepas nyckelramarna och tidslinjen oändligt.
    • Om det är inställt på ett iterationsantal upprepas tidslinjen så många gånger.
    • Om den är inställd på Varaktighet upprepas tidslinjen tills den tiden har nåtts. Detta kan trunkera animeringen en bit genom nyckelramsekvensen, om det inte är en heltalsfaktor för tidslinjens implicita varaktighet.
  • SpeedRatio (används inte ofta)

Linjära nyckelramar

Linjära nyckelramar resulterar i en enkel linjär interpolering av värdet tills ramens KeyTime har nåtts. Det här interpoleringsbeteendet är mest likt de enklare animeringarna "från till med" som beskrivs i avsnittet Storyboarded-animeringar.

Så här använder du en nyckelramsanimering för att skala återgivningshöjden för en rektangel med hjälp av linjära nyckelramar. Det här exemplet kör en animering där rektangelns höjd ökar något och linjärt under de första 4 sekunderna och sedan skalas snabbt under den sista sekunden tills rektangeln är dubbelt så hög som starthöjden.

<StackPanel>
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimationUsingKeyFrames
              Storyboard.TargetName="myRectangle"
              Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <LinearDoubleKeyFrame Value="1" KeyTime="0:0:0"/>
                <LinearDoubleKeyFrame Value="1.2" KeyTime="0:0:4"/>
                <LinearDoubleKeyFrame Value="2" KeyTime="0:0:5"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </StackPanel.Resources>
</StackPanel>

Diskreta nyckelramar

Diskreta nyckelramar använder ingen interpolering alls. När en KeyTime nås tillämpas det nya värdet helt enkelt. Beroende på vilken UI-egenskap som animeras skapar detta ofta en animering som verkar "hoppa". Var säker på att detta är det estetiska beteende som du verkligen vill ha. Du kan minimera de uppenbara hoppen genom att öka antalet nyckelramar som du deklarerar, men om en smidig animering är ditt mål kan det vara bättre att använda linjära eller spline-nyckelramar i stället.

Anmärkning

Diskreta nyckelramar är det enda sättet att animera ett värde som inte är av typen Double, Point och Color med en DiscreteObjectKeyFrame. Vi går igenom detta mer detaljerat senare i det här avsnittet.

Spline-nyckelramar

En spline-nyckelram skapar en variabelövergång mellan värden enligt värdet för egenskapen KeySpline . Den här egenskapen anger den första och andra kontrollpunkterna i en Bezier-kurva, som beskriver animeringens acceleration. I grund och botten definierar en KeySpline en funktion över tid-relation där funktionstidsdiagrammet är formen på den Bezier-kurvan. Du anger vanligtvis ett KeySpline-värde i en XAML-kort attributsträng som har fyra dubbla värden avgränsade med blanksteg eller kommatecken. Dessa värden är "X,Y"-par för två kontrollpunkter i Bezier-kurvan. "X" är tid och "Y" är funktionsmodifieraren till värdet. Varje värde ska alltid vara mellan 0 och 1 inklusive. Utan ändring av kontrollpunkt till en KeySpline är den raka linjen från 0,0 till 1,1 representationen av en funktion över tid för en linjär interpolation. Dina kontrollpunkter ändrar formen på kurvan och därmed funktionens beteende över tid för spline-animeringen. Det är förmodligen bäst att se detta visuellt som ett diagram.

I nästa exempel visas tre olika nyckelramar som tillämpas på en animering, där den sista är en nyckelsplineanimering för ett Double-värde (SplineDoubleKeyFrame). Observera strängen "0.6,0.0 0.9,0.00" som används för KeySpline. Detta skapar en kurva där animeringen verkar köras långsamt först men sedan snabbt når värdet precis innan KeyTime nås.

<Storyboard x:Name="myStoryboard">
    <!-- Animate the TranslateTransform's X property
        from 0 to 350, then 50,
        then 200 over 10 seconds. -->
    <DoubleAnimationUsingKeyFrames
        Storyboard.TargetName="MyAnimatedTranslateTransform"
        Storyboard.TargetProperty="X"
        Duration="0:0:10" EnableDependentAnimation="True">

        <!-- Using a LinearDoubleKeyFrame, the rectangle moves 
            steadily from its starting position to 500 over 
            the first 3 seconds.  -->
        <LinearDoubleKeyFrame Value="500" KeyTime="0:0:3"/>

        <!-- Using a DiscreteDoubleKeyFrame, the rectangle suddenly 
            appears at 400 after the fourth second of the animation. -->
        <DiscreteDoubleKeyFrame Value="400" KeyTime="0:0:4"/>

        <!-- Using a SplineDoubleKeyFrame, the rectangle moves 
            back to its starting point. The
            animation starts out slowly at first and then speeds up. 
            This KeyFrame ends after the 6th second. -->
        <SplineDoubleKeyFrame KeySpline="0.6,0.0 0.9,0.00" Value="0" KeyTime="0:0:6"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Underlätta nyckelramar

En lättande nyckelram är en nyckelram där interpolation tillämpas och funktionen över tiden för interpoleringen styrs av flera fördefinierade matematiska formler. Du kan faktiskt uppnå i stort sett samma resultat med en spline-nyckelram som du kan med vissa utjämningsfunktioner, men det finns också vissa utjämningsfunktioner, till exempel BackEase, som du inte kan återskapa med en spline.

Om du vill använda en lättande funktion på en lättande nyckelram anger du egenskapen EasingFunction som ett egenskapselement i XAML för nyckelramen. För värdet anger du ett objektelement för någon av de lättande funktionstyperna.

Det här exemplet tillämpar en CubicEase och sedan en BounceEase som efterföljande nyckelramar på en DoubleAnimation för att skapa en studsande effekt.

<Storyboard x:Name="myStoryboard">
    <DoubleAnimationUsingKeyFrames Duration="0:0:10"
        Storyboard.TargetProperty="Height"
        Storyboard.TargetName="myEllipse">

        <!-- This keyframe animates the ellipse up to the crest 
            where it slows down and stops. -->
        <EasingDoubleKeyFrame Value="-300" KeyTime="00:00:02">
            <EasingDoubleKeyFrame.EasingFunction>
                <CubicEase/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>

        <!-- This keyframe animates the ellipse back down and makes
            it bounce. -->
        <EasingDoubleKeyFrame Value="0" KeyTime="00:00:06">
            <EasingDoubleKeyFrame.EasingFunction>
                <BounceEase Bounces="5"/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Det här är bara ett exempel på en lättnadsfunktion. Vi går igenom mer i nästa avsnitt.

Funktioner för att underlätta

Med hjälp av hjälpfunktioner kan du använda anpassade matematiska formler för dina animeringar. Matematiska operationer är ofta användbara för att skapa animeringar som simulerar verklig fysik i ett 2D-koordinatsystem. Du kanske till exempel vill att ett objekt ska studsa realistiskt eller bete sig som om det vore på en fjäder. Du kan använda nyckelramar eller till och med från/till-animeringar/ för att uppskatta dessa effekter, men det skulle krävas en betydande mängd arbete och animeringen skulle vara mindre exakt än att använda en matematisk formel.

Lättningsfunktioner kan tillämpas på animeringar på tre sätt:

Här är en lista över lättnadsfunktionerna:

  • BackEase: Drar tillbaka animeringens rörelse något innan den börjar animera i den angivna sökvägen.
  • BounceEase: Skapar en studsande effekt.
  • CircleEase: Skapar en animering som accelererar eller saktar in med hjälp av en cirkulär funktion.
  • CubicEase: Skapar en animering som accelererar eller saktar in med formeln f(t) = t3.
  • ElasticEase: Skapar en animering som liknar en fjäder som oscillerar fram och tillbaka tills den kommer till vila.
  • ExponentialEase: Skapar en animering som accelererar eller saktar in med hjälp av en exponentiell formel.
  • PowerEase: Skapar en animering som accelererar eller saktar in med formeln f(t) = tp där p är lika med power-egenskapen .
  • QuadraticEase: Skapar en animering som accelererar eller saktar ned med formeln f(t) = t2.
  • QuarticEase: Skapar en animering som accelererar eller saktar in med formeln f(t) = t4.
  • QuinticEase: Skapa en animering som accelererar eller saktar in med formeln f(t) = t5.
  • SineEase: Skapar en animering som accelererar eller saktar in med hjälp av en sinusformel.

Vissa av lättnadsfunktionerna har sina egna egenskaper. BounceEase har till exempel två egenskaper Bounces och Bounciness som ändrar funktionen över tid för just BounceEase. Andra lättningsfunktioner, till exempel CubicEase , har inte andra egenskaper än egenskapen EasingMode som alla lättande funktioner delar och alltid ger samma funktionsöver tidsbeteende.

Vissa av dessa lättnadsfunktioner har lite överlappning, beroende på hur du ställer in egenskaper för de lättnadsfunktioner som har egenskaper. Till exempel är QuadraticEase exakt samma som en PowerEase med Power lika med 2. Och CircleEase är i princip ett standardvärde ExponentialEase.

BackEase-funktionen är unik eftersom den kan ändra värdet utanför det normala intervallet som anges av Från/Till eller värden för nyckelrutor. Den startar animeringen genom att ändra värdet i motsatt riktning som förväntat från ett normalt från/till-beteende , går tillbaka till från- eller startvärdet igen och kör sedan animeringen som vanligt.

I ett tidigare exempel visade vi hur du deklarerar en lättnadsfunktion för en nyckelramsanimering. I nästa exempel tillämpas en övergångsfunktion på en Från/Till/Med-animering.

<StackPanel x:Name="LayoutRoot" Background="White">
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimation From="30" To="200" Duration="00:00:3" 
                Storyboard.TargetName="myRectangle" 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <DoubleAnimation.EasingFunction>
                    <BounceEase Bounces="2" EasingMode="EaseOut" 
                                Bounciness="2"/>
                </DoubleAnimation.EasingFunction>
            </DoubleAnimation>
        </Storyboard>
    </StackPanel.Resources>
    <Rectangle x:Name="myRectangle" Fill="Blue" Width="200" Height="30"/>
</StackPanel>

När en lättningsfunktion tillämpas på en från/till-animering/ ändras funktionens egenskaper över tid för hur värdet interpoleras mellan värdena Från och Till under animeringens varaktighet. Utan en lättande funktion skulle det vara en linjär interpolation.

Diskreta objektvärdesanimeringar

En typ av animering förtjänar särskilt omnämnande eftersom det är det enda sättet du kan använda ett animerat värde på egenskaper som inte är av typen Double, Point eller Color. Det här är nyckelramsanimeringen ObjectAnimationUsingKeyFrames. Att animera med objektvärden skiljer sig eftersom det inte finns någon möjlighet att interpolera värdena mellan ramarna. När ramens KeyTime nås anges det animerade värdet omedelbart till det värde som anges i nyckelramens Värde. Eftersom det inte finns någon interpolering finns det bara en nyckelram som du använder i nyckelramsamlingen ObjectAnimationUsingKeyFrames : DiscreteObjectKeyFrame.

Värdet för en DiscreteObjectKeyFrame anges ofta med egenskapselementsyntax, eftersom det objektvärde som du försöker ange ofta inte är uttrycksbart som en sträng för att fylla värde i attributsyntaxen. Du kan fortfarande använda attributsyntax om du använder en referens, till exempel StaticResource.

En plats där du ser en ObjectAnimationUsingKeyFrames som används i standardmallarna är när en mallegenskap refererar till en penselresurs . Dessa resurser är SolidColorBrush-objekt , inte bara ett färgvärde , och de använder resurser som definieras som systemteman (ThemeDictionaries). De kan tilldelas direkt ett Brush-typvärde som TextBlock.Foreground och behöver inte använda indirekt målinriktning. Men eftersom en SolidColorBrush inte är Double, Point eller Color måste du använda en ObjectAnimationUsingKeyFrames för att använda resursen.

<Style x:Key="TextButtonStyle" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid Background="Transparent">
                    <TextBlock x:Name="Text"
                        Text="{TemplateBinding Content}"/>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPointerOverForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPressedForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
...
                       </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Du kan också använda ObjectAnimationUsingKeyFrames för att animera egenskaper som använder ett uppräkningsvärde. Här är ett annat exempel från ett namngivet format som kommer från Standardmallarna för Windows Runtime. Observera hur den anger egenskapen Synlighet som tar en uppräkningskonstant för synlighet . I det här fallet kan du ange värdet med hjälp av attributsyntax. Du behöver bara det okvalificerade konstantnamnet från en uppräkning för att ange en egenskap med ett uppräkningsvärde, till exempel "Komprimerad".

<Style x:Key="BackButtonStyle" TargetType="Button">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <Grid x:Name="RootGrid">
            <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal"/>
...           <VisualState x:Name="Disabled">
                <Storyboard>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame Value="Collapsed" KeyTime="0"/>
                  </ObjectAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
...
          </VisualStateManager.VisualStateGroups>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Du kan använda mer än en DiscreteObjectKeyFrame för en ObjectAnimationUsingKeyFrames-ramuppsättning . Detta kan vara ett intressant sätt att skapa en "bildspel"-animering genom att animera värdet för Image.Source, som ett exempelscenario där flera objektvärden kan vara användbara.