Animasi bingkai kunci dan animasi fungsi permudah

Animasi bingkai kunci linier, animasi bingkai kunci dengan nilai KeySpline , atau fungsi kemudahan adalah tiga teknik berbeda untuk skenario yang kira-kira sama: membuat animasi papan cerita yang sedikit lebih kompleks, dan yang menggunakan perilaku animasi nonlinear dari status awal ke status akhir.

Prasyarat

Pastikan Anda telah membaca topik animasi Storyboarded . Topik ini dibangun berdasarkan konsep animasi yang dijelaskan dalam animasi Storyboarded dan tidak akan membahasnya lagi. Misalnya, animasi Storyboarded menjelaskan cara menargetkan animasi, papan cerita sebagai sumber daya, nilai properti Garis Waktu seperti Durasi, FillBehavior, dan sebagainya.

Menganimasikan menggunakan animasi bingkai kunci

Animasi bingkai kunci mengizinkan lebih dari satu nilai target yang tercapai pada titik di sepanjang garis waktu animasi. Dengan kata lain, setiap bingkai kunci dapat menentukan nilai perantara yang berbeda, dan bingkai kunci terakhir yang dicapai adalah nilai animasi akhir. Dengan menentukan beberapa nilai untuk dianimasikan, Anda dapat membuat animasi yang lebih kompleks. Animasi bingkai kunci juga memungkinkan logika interpolasi yang berbeda, yang masing-masing diimplementasikan sebagai subkelas KeyFrame yang berbeda per jenis animasi. Secara khusus, setiap jenis animasi key-frame memiliki variasi Discrete, Linear, Spline , dan Easing dari kelas KeyFrame-nya untuk menentukan bingkai kuncinya. Misalnya, untuk menentukan animasi yang menargetkan Double dan menggunakan bingkai kunci, Anda dapat mendeklarasikan bingkai kunci dengan DiscreteDoubleKeyFrame, LinearDoubleKeyFrame, SplineDoubleKeyFrame, dan EasingDoubleKeyFrame. Anda dapat menggunakan salah satu dan semua jenis ini dalam satu koleksi KeyFrames , untuk mengubah interpolasi setiap kali bingkai kunci baru tercapai.

Untuk perilaku interpolasi, setiap bingkai kunci mengontrol interpolasi hingga waktu KeyTime tercapai. Nilainya juga tercapai pada saat itu. Jika ada lebih banyak bingkai kunci di luar, nilainya kemudian menjadi nilai awal untuk bingkai kunci berikutnya secara berurutan.

Pada awal animasi, jika tidak ada bingkai kunci dengan KeyTime "0:0:0" yang ada, nilai awal adalah apa pun nilai non-animasi properti. Ini mirip dengan bagaimana animasi From/To/By bertindak jika tidak ada From.

Durasi animasi bingkai kunci secara implisit durasinya sama dengan nilai KeyTime tertinggi yang diatur dalam salah satu bingkai kuncinya. Anda dapat mengatur Durasi eksplisit jika mau, tetapi berhati-hatilah tidak lebih pendek dari KeyTime di bingkai kunci Anda sendiri atau Anda akan memotong sebagian animasi.

Selain Durasi, Anda dapat mengatur semua properti berbasis Garis Waktu pada animasi bingkai kunci, seperti yang Anda bisa dengan animasi Dari/Ke/Menurut , karena kelas animasi bingkai kunci juga berasal dari Garis Waktu. Ini adalah:

  • AutoReverse: setelah bingkai kunci terakhir tercapai, bingkai diulang dalam urutan terbalik dari akhir. Ini menggandakan durasi animasi yang jelas.
  • BeginTime: menunda awal animasi. Garis waktu untuk nilai KeyTime dalam bingkai tidak mulai dihitung hingga BeginTime tercapai, sehingga tidak ada risiko memotong bingkai
  • FillBehavior: mengontrol apa yang terjadi ketika bingkai kunci terakhir tercapai. FillBehavior tidak berpengaruh pada bingkai kunci perantara apa pun.
  • RepeatBehavior:
    • Jika diatur ke Selamanya, maka bingkai kunci dan garis waktunya berulang tanpa batas.
    • Jika diatur ke jumlah perulangan, garis waktu akan berulang berkali-kali.
    • Jika diatur ke Durasi, garis waktu akan berulang hingga waktu tersebut tercapai. Ini mungkin memotong bagian animasi melalui urutan bingkai kunci, jika itu bukan faktor bilangan bulat dari durasi implisit garis waktu.
  • SpeedRatio (tidak umum digunakan)

Bingkai kunci linier

Bingkai kunci linier menghasilkan interpolasi linier sederhana dari nilai hingga KeyTime bingkai tercapai. Perilaku interpolasi ini paling mirip dengan animasi From/To/By yang lebih sederhana yang dijelaskan dalam topik animasi Storyboarded .

Berikut cara menggunakan animasi bingkai kunci untuk menskalakan tinggi render persegi panjang, menggunakan bingkai kunci linier. Contoh ini menjalankan animasi di mana tinggi persegi panjang sedikit meningkat dan linier selama 4 detik pertama, lalu menskalakan dengan cepat untuk detik terakhir sampai persegi panjang menggandakan tinggi awal.

<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>

Bingkai kunci diskrit

Bingkai kunci diskrit tidak menggunakan interpolasi sama sekali. Ketika KeyTime tercapai, Nilai baru hanya diterapkan. Bergantung pada properti UI mana yang sedang dianimasikan, ini sering menghasilkan animasi yang tampaknya "melompat". Pastikan bahwa ini adalah perilaku estetika yang benar-benar Anda inginkan. Anda dapat meminimalkan lompatan yang jelas dengan meningkatkan jumlah bingkai kunci yang Anda nyatakan, tetapi jika animasi yang halus adalah tujuan Anda, Anda mungkin lebih baik menggunakan bingkai kunci linier atau spline sebagai gantinya.

Catatan

Bingkai kunci diskrit adalah satu-satunya cara untuk menganimasikan nilai yang bukan tipe Double, Point, dan Color, dengan DiscreteObjectKeyFrame. Kita akan membahas ini secara lebih rinci nanti dalam topik ini.

Bingkai kunci spline

Bingkai kunci spline membuat transisi variabel antar nilai sesuai dengan nilai properti KeySpline . Properti ini menentukan titik kontrol pertama dan kedua dari kurva Bezier, yang menjelaskan akselerasi animasi. Pada dasarnya, KeySpline mendefinisikan hubungan function-over-time di mana grafik function-time adalah bentuk kurva Bezier tersebut. Anda biasanya menentukan nilai KeySpline dalam string atribut singkat XAML yang memiliki empat nilai Ganda yang dipisahkan oleh spasi atau koma. Nilai-nilai ini adalah pasangan "X,Y" untuk dua titik kontrol kurva Bezier. "X" adalah waktu dan "Y" adalah pengubah fungsi ke nilai. Setiap nilai harus selalu antara 0 dan 1 inklusif. Tanpa modifikasi titik kontrol ke KeySpline, garis lurus dari 0,0 hingga 1,1 adalah representasi fungsi dari waktu ke waktu untuk interpolasi linier. Titik kontrol Anda mengubah bentuk kurva tersebut dan dengan demikian perilaku fungsi dari waktu ke waktu untuk animasi spline. Mungkin yang terbaik adalah melihat ini secara visual sebagai grafik. Anda dapat menjalankan sampel visualizer spline kunci Silverlight di browser untuk melihat bagaimana titik kontrol memodifikasi kurva dan cara animasi sampel berjalan saat menggunakannya sebagai nilai KeySpline .

Contoh berikutnya menunjukkan tiga bingkai kunci berbeda yang diterapkan ke animasi, dengan yang terakhir menjadi animasi spline kunci untuk nilai Ganda (SplineDoubleKeyFrame). Perhatikan string "0.6,0.0 0.9,0.00" yang diterapkan untuk KeySpline. Ini menghasilkan kurva di mana animasi tampaknya berjalan lambat pada awalnya tetapi kemudian dengan cepat mencapai nilai tepat sebelum KeyTime tercapai.

<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>

Meringankan bingkai kunci

Bingkai kunci pelengkap adalah bingkai kunci tempat interpolasi diterapkan, dan fungsi dari waktu ke waktu interpolasi dikendalikan oleh beberapa rumus matematika yang telah ditentukan sebelumnya. Anda benar-benar dapat menghasilkan banyak hasil yang sama dengan bingkai kunci spline seperti yang Anda bisa dengan beberapa jenis fungsi pelingkatan, tetapi ada juga beberapa fungsi pelengkap, seperti BackEase, yang tidak dapat Anda reproduksi dengan spline.

Untuk menerapkan fungsi pelingan ke bingkai kunci pelingan, Anda mengatur properti EasingFunction sebagai elemen properti di XAML untuk bingkai kunci tersebut. Untuk nilai , tentukan elemen objek untuk salah satu jenis fungsi yang meringankan.

Contoh ini menerapkan CubicEase dan kemudian BounceEase sebagai bingkai kunci berturut-turut ke DoubleAnimation untuk membuat efek memantul.

<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>

Ini hanyalah satu contoh fungsi yang meringankan. Kita akan membahas lebih lanjut di bagian berikutnya.

Fungsi penguraian

Fungsi penguraian memungkinkan Anda menerapkan rumus matematika kustom ke animasi Anda. Operasi matematika sering berguna untuk menghasilkan animasi yang mensimulasikan fisika dunia nyata dalam sistem koordinat 2-D. Misalnya, Anda mungkin ingin objek memantul secara realistis atau berperilaku seolah-olah berada di musim semi. Anda dapat menggunakan bingkai kunci atau bahkan dari/ke/oleh animasi untuk perkiraan efek ini tetapi akan mengambil sejumlah besar pekerjaan dan animasi akan kurang akurat daripada menggunakan rumus matematika.

Fungsi kemudahan dapat diterapkan ke animasi dengan tiga cara:

Berikut adalah daftar fungsi penguraian:

  • BackEase: Mencabut gerakan animasi sedikit sebelum mulai menganimasikan di jalur yang ditunjukkan.
  • BounceEase: Membuat efek memantul.
  • CircleEase: Membuat animasi yang mempercepat atau mempercepat menggunakan fungsi melingkar.
  • CubicEase: Membuat animasi yang mempercepat atau mendeselerasi menggunakan rumus f(t) = t3.
  • ElasticEase: Membuat animasi yang menyerupan pegas berosilasi bolak-balik hingga berhenti.
  • ExponentialEase: Membuat animasi yang mempercepat atau mendeselerasi menggunakan rumus eksponensial.
  • PowerEase: Membuat animasi yang mempercepat atau mempercepat menggunakan rumus f(t) = tp di mana p sama dengan properti Daya .
  • QuadraticEase: Membuat animasi yang mempercepat atau mempercepat menggunakan rumus f(t) = t2.
  • QuarticEase: Membuat animasi yang mempercepat atau mendeselerasi menggunakan rumus f(t) = t4.
  • QuinticEase: Buat animasi yang mempercepat atau mempercepat menggunakan rumus f(t) = t5.
  • SineEase: Membuat animasi yang mempercepat atau mempercepat menggunakan rumus sinus.

Beberapa fungsi kemudahan memiliki sifatnya sendiri. Misalnya, BounceEase memiliki dua properti Bounces dan Bounciness yang memodifikasi perilaku fungsi dari waktu ke waktu dari BounceEase tertentu. Fungsi pelinggihan lainnya seperti CubicEase tidak memiliki properti selain properti EasingMode yang dibagikan semua fungsi pelukaan, dan selalu menghasilkan perilaku fungsi dari waktu ke waktu yang sama.

Beberapa fungsi permudah ini memiliki sedikit tumpang tindih, tergantung pada cara Anda mengatur properti pada fungsi permudah yang memiliki properti. Misalnya, QuadraticEase persis sama dengan PowerEase dengan Power sama dengan 2. Dan CircleEase pada dasarnya adalah Nilai default ExponentialEase.

Fungsi pelingan BackEase unik karena dapat mengubah nilai di luar rentang normal seperti yang diatur oleh Dari/Ke atau nilai bingkai kunci. Ini memulai animasi dengan mengubah nilai ke arah yang berlawanan seperti yang diharapkan dari perilaku Dari/Ke normal, kembali ke nilai Dari atau awal lagi, lalu menjalankan animasi seperti biasa.

Dalam contoh sebelumnya, kami menunjukkan cara mendeklarasikan fungsi pengurangan untuk animasi key-frame. Sampel berikutnya menerapkan fungsi permudah ke animasi Dari/Ke/Menurut .

<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>

Saat fungsi pelingan diterapkan ke animasi Dari/Ke/Menurut , fungsi akan berubah karakteristik fungsi dari waktu ke waktu tentang bagaimana nilai menginterpolasi antara nilai Dari dan Ke selama Durasi animasi. Tanpa fungsi penguraian, itu akan menjadi interpolasi linier.

Animasi nilai objek diskrit

Satu jenis animasi layak disebutkan secara khusus karena ini adalah satu-satunya cara Anda dapat menerapkan nilai animasi ke properti yang bukan tipe Double, Point, atau Color. Ini adalah animasi key-frame ObjectAnimationUsingKeyFrames. Menganimasikan menggunakan nilai Objek berbeda karena tidak ada kemungkinan untuk menginterpolasi nilai di antara bingkai. Ketika KeyTime bingkai tercapai, nilai animasi segera diatur ke nilai yang ditentukan dalam Nilai bingkai kunci. Karena tidak ada interpolasi, hanya ada satu bingkai kunci yang Anda gunakan dalam koleksi bingkai kunci ObjectAnimationUsingKeyFrames : DiscreteObjectKeyFrame.

NilaiDiscreteObjectKeyFrame sering diatur menggunakan sintaks elemen properti, karena nilai objek yang Anda coba atur sering tidak dapat diekspresikan sebagai string untuk mengisi Nilai dalam sintaks atribut. Anda masih dapat menggunakan sintaks atribut jika Anda menggunakan referensi seperti StaticResource.

Satu tempat Anda akan melihat ObjectAnimationUsingKeyFrames yang digunakan dalam templat default adalah saat properti templat mereferensikan sumber daya Brush . Sumber daya ini adalah objek SolidColorBrush , bukan hanya nilai Warna , dan mereka menggunakan sumber daya yang didefinisikan sebagai tema sistem (ThemeDictionaries). Mereka dapat ditetapkan langsung ke nilai jenis Brush seperti TextBlock.Foreground dan tidak perlu menggunakan penargetan tidak langsung. Tetapi karena SolidColorBrush bukan Double, Point, atau Color, Anda harus menggunakan ObjectAnimationUsingKeyFrames untuk menggunakan sumber daya.

<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>

Anda juga dapat menggunakan ObjectAnimationUsingKeyFrames untuk menganimasikan properti yang menggunakan nilai enumerasi. Berikut adalah contoh lain dari gaya bernama yang berasal dari templat default Windows Runtime. Perhatikan cara mengatur properti Visibilitas yang mengambil konstanta enumerasi Visibilitas . Dalam hal ini Anda dapat mengatur nilai menggunakan sintaks atribut. Anda hanya memerlukan nama konstanta yang tidak memenuhi syarat dari enumerasi untuk mengatur properti dengan nilai enumerasi, misalnya "Diciutkan".

<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>

Anda dapat menggunakan lebih dari satu DiscreteObjectKeyFrame untuk set bingkai ObjectAnimationUsingKeyFrames . Ini mungkin cara yang menarik untuk membuat animasi "peragaan slide" dengan meniru nilai Image.Source, sebagai contoh skenario di mana beberapa nilai objek mungkin berguna.