Budowa aplikacji w technologii.net wykład 11 Animacje



Podobne dokumenty
Programowanie obiektowe i zdarzeniowe wykład 8 grafika i animacja

Jarosław Kuchta Podstawy Programowania Obiektowego. Podstawy grafiki obiektowej

Aby nadać jej pożądaną postać należy w pliku Window1.xaml stworzyć definicję swojego stylu modyfikując ręcznie postać zapisu XAML:

Spis treści. Część I Przygotowanie środowiska Część II Język C# Wstęp... 9

Laboratorium Programowanie urządzeń mobilnych

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Modele zawartości. WPF wykorzystuje 4 modele zawartości kontrolek: ContentControl pojedyncza zawartość

Programowanie obiektowe i zdarzeniowe wykład 1 Wprowadzenie do programowania zdarzeniowego

1. Wprowadzenie do WPF i XAML. Tworzenie interfejsu użytkownika.

XAML Extensible Application Markup Language

Ćwiczenie 14 Dmuchawce

Utworzenie aplikacji mobilnej Po uruchomieniu Visual Studio pokazuje się ekran powitalny. Po lewej stronie odnośniki do otworzenia lub stworzenia

Windows Presentation Foundation

Dynamiczne i wydajne tworzenie interfejsu. Piotr Michałkiewicz

Ćwiczenie 4 - Podstawy materiałów i tekstur. Renderowanie obrazu i animacji

Przykładowa dostępna aplikacja w Visual Studio - krok po kroku

Część XVII C++ Funkcje. Funkcja bezargumentowa Najprostszym przypadkiem funkcji jest jej wersja bezargumentowa. Spójrzmy na przykład.

Górnicki Mateusz 17681

Adobe InDesign lab.1 Jacek Wiślicki, Paweł Kośla. Spis treści: 1 Podstawy pracy z aplikacją Układ strony... 2.

Dodanie nowej formy do projektu polega na:

Ćwiczenie 5 Animacja tekstu

Arkadiusz Kalicki, Lech Mankiewicz Plugin Webcam dla SalsaJ Podręcznik użytkownika

Wizualne systemy programowania. Wykład 11 Grafika. dr Artur Bartoszewski -Wizualne systemy programowania, sem. III- WYKŁAD

GRAFIKA WEKTOROWA. WYKŁAD 1 Wprowadzenie do grafiki wektorowej. Jacek Wiślicki Katedra Informatyki Stosowanej

1 Zrozumieć Flasha... 1 Co można zrobić za pomocą Flasha?... 2 Tworzenie obrazków do strony 3 Animowanie witryny 4 Tworzenie filmów

1. Dockbar, CMS + wyszukiwarka aplikacji Dodawanie portletów Widok zawartości stron... 3

Grafika Komputerowa Materiały Laboratoryjne

6.4. Efekty specjalne

Sieciowe Technologie Mobilne. Laboratorium 2

Aleksandra Zając. Raport. Blender. Pokemon: Eevee

Programowanie telefonów z Windows Phone 7, cz. 5

Autodesk 3D Studio MAX Animacja komputerowa i praca kamery

Rozdział 3. Zapisywanie stanu aplikacji w ustawieniach lokalnych

MVVM i XAML w Visual Studio 2015 / Jacek Matulewski. Gliwice, cop Spis treści

Silverlight. Od podstaw

xmlns:prism= c. <ContentControl prism:regionmanager.regionname="mainregion" />

SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE

Animacja. Instrukcja wykonania animacji metodą klatek kluczowych. Autor: Bartosz Kowalczyk. Blender 2.61

Informatyka II. Laboratorium Aplikacja okienkowa

Opis Edytora postaci Logomocji

Podręczna pomoc Microsoft Power Point 2007

Ćwiczenie 1 Galeria zdjęć

Ćwiczenie 1 Automatyczna animacja ruchu

Ćwiczenie 6 Animacja trójwymiarowa

Ustawienia ogólne. Ustawienia okólne są dostępne w panelu głównym programu System Sensor, po kliknięciu ikony

1 TEMAT LEKCJI: 2 CELE LEKCJI: 3 METODY NAUCZANIA 4 ŚRODKI DYDAKTYCZNE. Scenariusz lekcji. Scenariusz lekcji. 2.1 Wiadomości: 2.

1. Umieść kursor w miejscu, w którym ma być wprowadzony ozdobny napis. 2. Na karcie Wstawianie w grupie Tekst kliknij przycisk WordArt.

Aplikacja kret dla App Inventor 2

Misja#3. Robimy film animowany.

Laboratorium programowania urządzeń mobilnych

etrader Pekao Podręcznik użytkownika Strumieniowanie Excel

using System;... using System.Threading;

Pracownia internetowa w każdej szkole (edycja Jesień 2007)

INTERAKTYWNA KOMUNIKACJA WIZUALNA. Flash - podstawy

- dodaj obiekt tekstowy: /** Maciej */ Stage { title : "First JavaFX App" scene: Scene { width: 300 height: 300 content: [ ] } }

Animacje z zastosowaniem suwaka i przycisku

Delphi podstawy programowania. Środowisko Delphi

Komputery I (2) Panel sterowania:

Język JAVA podstawy. wykład 2, część 2. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Systemy multimedialne 2015

Przetwarzanie grafiki rastrowej na wektorową

Przewodnik po soczewkach

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Multimedia i interfejsy. Ćwiczenie 5 HTML5

TabControl kontrolka odpowiedzialna za wyświetlenie zestawu zakładek. PageControl podobnie jak TabControl ale posiada wbudowane strony.

BAZY DANYCH Panel sterujący

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania

Badanie ruchu złożenia

Visual Studio instalacja

Compas 2026 Vision Instrukcja obsługi do wersji 1.07

Adobe Photoshop Dodatek do lab4 J.Wiślicki, A.Romanowski;

Ćw. I Projektowanie opakowań transportowych cz. 1 Ćwiczenia z Corel DRAW

WASM AppInventor Lab 3. Rysowanie i animacja po kanwie PODSTAWY PRACY Z KANWAMI

5.4. Efekty specjalne

MsAccess - ćwiczenie nr 3 (zao) Budowa formularzy

Projekt Hurtownia, realizacja rejestracji dostaw produktów

Słowa kluczowe Sterowanie klawiaturą, klawiatura, klawisze funkcyjne, przesuwanie obiektów ekranowych, wydawanie poleceń za pomocą klawiatury

PyX jest pakietem Pythona do grafiki wektorowej. Pozawala zatem tworzyd pliki EPS oraz PDF.

Instrukcja laboratoryjna cz.3

Dodawanie grafiki i obiektów

1. Wstęp Pierwsze uruchomienie Przygotowanie kompozycji Wybór kompozycji Edycja kompozycji...

Rysunek 1: Okno timeline wykorzystywane do tworzenia animacji.

Obsługa grafiki w Delphi, rysowanie na płótnie, obsługa myszki, zapisywanie obrazków do plików, bitmapy pozaekranowe.

I. Wstawianie rysunków

Tworzenie prezentacji w MS PowerPoint

Systemy wirtualnej rzeczywistości. Komponenty i serwisy

Wykład 4 Delegat (delegate), właściwości indeksowane, zdarzenie (event) Zofia Kruczkiewicz

Java: otwórz okienko. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Szybkie tworzenie grafiki w GcIde

Lokalizacja jest to położenie geograficzne zajmowane przez aparat. Miejsce, w którym zainstalowane jest to urządzenie.

Jak uzyskać efekt 3D na zdjęciach z wykorzystaniem programu InkScape

Laboratorium - Monitorowanie i zarządzanie zasobami systemu Windows 7

Projekt Hurtownia, realizacja rejestracji dostaw produktów

Prezentacje multimedialne w Powerpoint

CorelDRAW. 1. Rysunek rastrowy a wektorowy. 2. Opis okna programu

Dokument hipertekstowy

Ćwiczenie 23 Praca z plikiem.psd

Podstawy pozycjonowania CSS

Instrukcja postępowania użytkownika programów LiderSim i ProLider w związku z wprowadzeniem od r. nowych stawek VAT.

Transkrypt:

Budowa aplikacji w technologii.net wykład 11 Animacje 1/52 Wykonanie animacji w Windows Forms, MFS, Swingu, etc. opierało się na timerach i własnej funkcji rysującej: 1. Stworzenie timera, który co określoną liczbę milisekund odpala zdarzenie. 2. W reakcji na zdarzenie timera, należy dokonać wymaganych przez animację obliczeń, zmian parametrów, etc. (np. jeśli animujemy obracające się logo zwiększamy kąt obrotu o stały stopień). 3. Następnie unieważniamy zawartość okna. Zmusi to system do wywołania naszej procedury rysującej. 4. W tej procedurze rysujemy kolejną klatkę animacji.

2/52 Wiążą się z tym problemy: Procedura rysująca odpowiada za wyświetlanie pikseli, nie kontrolek zatem zawartość animacji musi być rysowana ręcznie (w WPF animacji podlegają dowolne własności elementów). Dodanie kolejnej animacji komplikuje kod (w WPF można składać bardziej złożone animacji z kilku prostszych). Stały framerate (ustawiony w timerze). Jego modyfikacja pociąga za sobą zmianę procedury obliczającej kolejną klatkę. Bardziej złożone sposoby animacji (np. przemieszczanie po ścieżce) wymagają bardziej złożonego kodu (w WPF animacje definiuje się w XAMLu). W WPF model jest prostszy, gdyż okna samo dba o aktualizację swej zawartości, gdy zmienią się własności elementów. Ponadto nie wymaga ręcznej zmiany własności w reakcji na zdarzenia timera. Zamiast tego animacje definiuje się w sposób deklaratywny. Animacja własności Animacja w WPF nie wymaga zajmowania się serią klatek. Zamiast tego określamy jaka własność elementu w jaki sposób ma się zmieniać w czasie. Ograniczenie: animacje dotyczą tylko dependency properties (a co za tym idzie, nie da się uzyskać w ten sposób efektów, których nie osiągniemy modyfikując własności, np. nie można animacją dodawać elementów do okna). Mogą one służyć uatrakcyjnieniu standardowej aplikacji, ale nie nadają się np. do gier.

3/52 Podstawy Każda animacja operuje na pojedynczej własności. Animowanie własności wymaga użycia klasy animacji właściwej dla typu tej własności. Klasy animacji: zmieniających pewną wartość na drodze liniowej interpolacji (z wartości From do wartości To lub zwiększając wartość aktualną o By): ByteAnimation ColorAnimation DecimalAnimation DoubleAnimation Int16Animation Int32Animation Int64Animation PointAnimation Point3DAnimation QuarternionAnimation RectAnimation Rotation3DAnimation SingleAnimation SizeAnimation ThicknessAnimation VectorAnimation Vector3DAnimation

zmieniających pewną wartość w określonych punktach czasu: BooleanAnimationUsingKeyFrames ByteAnimationUsingKeyFrames CharAnimationUsingKeyFrames ColorAnimationUsingKeyFrames DecimalAnimationUsingKeyFrames DoubleAnimationUsingKeyFrames Int16AnimationUsingKeyFrames Int32AnimationUsingKeyFrames Int64AnimationUsingKeyFrames MatrixAnimationUsingKeyFrames ObjectAnimationUsingKeyFrames PointAnimationUsingKeyFrames Point3DAnimationUsingKeyFrames QuarternionAnimationUsingKeyFrames RectAnimationUsingKeyFrames Rotation3DAnimationUsingKeyFrames SingleAnimationUsingKeyFrames SizeAnimationUsingKeyFrames StringAnimationUsingKeyFrames ThicknessAnimationUsingKeyFrames VectorAnimationUsingKeyFrames Vector3DAnimationUsingKeyFrames 4/52

5/52 animacje wykorzystujące ścieżkę (PathGeometry): DoubleAnimationUsingPath MatrixAnimationUsingPath PointAnimationUsingPath Możliwe jest też tworzenie własnych klas animacji. Nie ma klas do animowania własności typu wyliczeniowego (np. HorizontalAlignment). Zazwyczaj nie animuje się też typów referencyjnych (np. Brush zamiast tego używa się np. ColorAnimation, DoubleAnimation do animacji własności pędzla). Animacje w kodzie Wymaga stworzenia obiektu animacji, ustawienia własności i odpalenia jej przy pomocy metody BeginAnimation() (zadeklarowanej w interfejsie IAnimatable). <Grid> <Button Name="cmdPowiększ" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="3" Click="PowiększClick" >Powiększ</Button> </Grid>

private void PowiększClick(object sender, RoutedEventArgs e) { DoubleAnimation anim = new DoubleAnimation(); anim.from = cmdpowiększ.actualwidth; anim.to = this.width - 30; anim.duration = TimeSpan.FromSeconds(3); cmdpowiększ.beginanimation(button.widthproperty, anim); } 6/52

7/52 From początkowa wartość własności (gdybyśmy ustawili tu stałą wartość, wówczas własność zostałaby zresetowana do niej na początku animacji): anim.from = 160; Jeśli jej nie określimy, animacja zaczyna się od wartości aktualnej (ale musiała być ona wcześniej jawnie ustawiona: w kodzie, w XAMLu lub przez settera, ale nie przez kontener). private void Window_Loaded(object sender, RoutedEventArgs e) { cmdpowiększ.width = cmdpowiększ.actualwidth; } To wartość końcowa. Podobnie jak From, można ją opuścić. Oznaczać to będzie powrót do początkowej wartości (czyli aktualnej wartości, nie licząc animacji). DoubleAnimation anim = new DoubleAnimation(); anim.duration = TimeSpan.FromSeconds(3); cmdpowiększ.beginanimation(button.widthproperty, anim);

8/52 Aby to zadziałało, aktualna wartość szerokości już musiała zostać zmodyfikowana przez jakąś animację. Możemy to wykorzystać, aby stworzyć animację powrotu (wykorzystując zdarzenie Completed, oznaczające zakończenie animacji): private void PowiększClick(object sender, RoutedEventArgs e) { } DoubleAnimation anim = new DoubleAnimation(); anim.to = this.width - 30; anim.duration = TimeSpan.FromSeconds(3); anim.completed += anim_completed; cmdpowiększ.beginanimation(button.widthproperty, anim); void anim_completed(object sender, EventArgs e) { DoubleAnimation anim = new DoubleAnimation(); anim.duration = TimeSpan.FromSeconds(3); cmdpowiększ.beginanimation(button.widthproperty, anim); }

9/52 Inne rozwiązanie (automatyczny powrót do pierwotnej własności odwrócenie animacji): anim.autoreverse = true; Inne rozwiązanie (powrót do pierwotnej własności bez animacji): anim.fillbehavior = FillBehavior.Stop; Animacja po zakończeniu nadal istnieje i ma wpływ na aktualną wartość własności. Aby zlikwidować wpływ animacji, należy usunąć jej obiekt: cmdpowiększ.beginanimation(button.widthproperty, null); By można użyć, zamiast podawania To. Zmienia własność o podaną wartość. anim.by = 100; odpowiada to: anim.to = cmdpowiększ.width + 100;

10/52 Podobny efekt można osiągnąć ustawiając flagę IsAdditive: DoubleAnimation anim = new DoubleAnimation(); anim.from = 0; anim.to = 100; anim.duration = TimeSpan.FromSeconds(3); anim.isadditive = true; cmdpowiększ.beginanimation(button.widthproperty, anim); Duration określamy czas trwania a nie szybkość animacji zatem powiększanie przycisku zawsze będzie trwało 3 sekundy, niezależnie od rozmiaru okna. Uwaga: na własności nie można wykonywać kilku animacja na raz (odpalenie kolejnej, przerywa poprzednią). Może spowodować to wrażenie, że animacja zwolniła gdyż dla nowej animacji znów ustawiono czas trwania 3 sekundy. Można odpalić (niezależnie) animacje różnych własności elementu: cmdpowiększ.beginanimation(button.widthproperty,...); cmdpowiększ.beginanimation(button.heightproperty,...);

11/52 Inne własności animacji: BeginTime wymusza opóźnienie rozpoczęcia animacji (TimeSpan). SpeedRatio szybkość animacji, domyślnie 1. AccelerationRatio, DecelerationRatio do animacji nieliniowej, która przyśpiesza na początku, a zwalnia na końcu. Wartości od 0 do 1 określają jaką część czasu trwania ma zająć przyśpieszanie lub zwalnianie. DoubleAnimation anim = new DoubleAnimation(); anim.to = this.width - 30; anim.duration = TimeSpan.FromSeconds(5); anim.accelerationratio = 0.3; anim.decelerationratio = 0.3; cmdpowiększ.beginanimation(button.widthproperty, anim);

12/52 RepeatBehavior pozwala powtarzać animację określoną liczbę razy, przez określony czas lub bez końca (RepeatBehavior.Forever). lub: DoubleAnimation anim = new DoubleAnimation(); anim.to = this.width - 30; anim.duration = TimeSpan.FromSeconds(0.5); anim.autoreverse = true; anim.repeatbehavior = new RepeatBehavior(3); cmdpowiększ.beginanimation(button.widthproperty, anim); anim.repeatbehavior = new RepeatBehavior(TimeSpan.FromSeconds(2.5)); Można ustawić flagę IsCumulative, wówczas kolejne powtórzenie animacji rozpocznie się od ostatniego stanu poprzedniej (a nie stanu początkowego działa to jak domyślne ustawienie IsAdditive dla kolejnych powtórzeń).

13/52 Animacje w XAMLu Animacja w XAMLu definiowana jest w obiekcie storyboard. Reprezentuje on przebieg animacji, pozwala na grupowanie kilku animacji, kontrolowanie animacji. Ponadto pełni podobną rolę, co wywołanie metody BeginAnimation(). <Storyboard TargetName="cmdPowiększ" TargetProperty="Width"> <DoubleAnimation From="160" To="300" Duration="0:0:5" /> </Storyboard> Inny wariant (TargetName i TargetProperty to własności dołączone): <Storyboard> <DoubleAnimation Storyboard.TargetName="cmdPowiększ" Storyboard.TargetProperty="Width" From="160" To="300" Duration="0:0:5" /> </Storyboard>

Do uruchomienia animacji konieczny jest EventTrigger. Jego zadaniem jest odpalenie animacji. (EventTrigger nie musi znajdować sie w Stylu.) <Button Padding="3" HorizontalAlignment="Center" VerticalAlignment="Center" Width="160"> <Button.Triggers> <EventTrigger RoutedEvent="Button.Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation To="300" Duration="0:0:5" Storyboard.TargetProperty="Width" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Button.Triggers> Powiększ </Button> Nie musimy określać TargetName wówczas automatycznie użyty zostanie element, w którym zagnieżdżono storyboard. 14/52

15/52 W XAMLu nie ma obsługi wyrażeń, dlatego wartość docelowa została ustawiona na stałą. Wartość tę można odczytać z innej własności przy pomocy bindingu:... To="{Binding ElementName=window,Path=Width}"... Jeśli chcemy bardziej złożonych obliczeń, powinniśmy napisać własnego IValueConvertera lub stworzyć własność zależnościową do której będziemy mogli dowiązać i która zajmie się obliczeniami. Poza EventTriggerem możemy również używać PropertyTriggerów: <Style x:key="powiększalski"><style.triggers> <Trigger Property="Button.IsPressed" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <DoubleAnimation.../> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> </Trigger> </Style.Triggers></Style>

16/52... <Button... Style="{StaticResource powiększalski}"> Powiększ </Button> Trigger.EnterActions to akcje wykonywane, w chwili gdy własność przyjmuje wskazaną wartość. Trigger.ExitActions są wykonywane, gdy następuje utrata tej wartości (wracamy do false). Wszystkie animacje umieszczone w storyboard są automatycznie synchronizowane: <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Width" By="100" Duration="0:0:0.5" /> <DoubleAnimation Storyboard.TargetProperty="Height" By="50" Duration="0:0:0.5" /> </Storyboard> Możemy korzystać ze SpeedRatio, aby przyśpieszyć niektóre animacje, BeginTime, aby opóźnić rozpoczęcie innych, etc.

17/52 Przykład wykorzystanie do animacji przejścia (między dwoma obrazkami). Obrazki umieszczamy w Gridzie jeden na drugim: <Grid> <Image Source="Gra o tron.jpg" /> <Image Source="Zew Cthulhu.jpg" Name="second" /> </Grid> W momencie ładowania okienka uruchamiamy animację zmieniającą przeźroczystość górnego obrazka: <Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard Storyboard.TargetName="second"> <DoubleAnimation Duration="0:0:5" Storyboard.TargetProperty="Opacity" To="0" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Window.Triggers>

18/52

19/52 Ciekawszym rozwiązaniem jest wykorzystanie i animowanie maski przeźroczystości. <Image Source="Zew Cthulhu.jpg" Name="second"> <Image.OpacityMask> <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> <GradientStop Offset="0" Color="Transparent" x:name="transparentstop" /> <GradientStop Offset="0" Color="Black" x:name="visiblestop" /> </LinearGradientBrush> </Image.OpacityMask> </Image>... <Storyboard> <DoubleAnimation Storyboard.TargetName="visibleStop" Storyboard.TargetProperty="Offset" From="0" To="1.2" Duration="0:0:6" /> <DoubleAnimation Storyboard.TargetName="transparentStop" Storyboard.TargetProperty="Offset" BeginTime="0:0:1" From="0" To="1" Duration="0:0:5" /> </Storyboard>

20/52

21/52 WPF daje możliwość kontrolowania animacji przy pomocy następujących klas akcji: PauseStoryboard ResumeStoryboard StopStoryboard (zatrzymanie nie jest równoważne zakończeniu, bo nie zachowuje końcowej wartości własności, a wraca do początkowej) SeekStoryboard (skok do wskazanej pozycji) SetStoryboardSpeedRatio SkipStoryboardToFill (skok do końca) RemoveStoryboard (zatrzymuje i usuwa) Dodajmy przyciski do kontroli animacji: <DockPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" DockPanel.Dock="Bottom"> <Button Name="cmdStart" >Start</Button> <Button Name="cmdPause">Pause</Button> <Button Name="cmdResume">Resume</Button> <Button Name="cmdStop">Stop</Button> </StackPanel> <Grid Margin="3"> <Image.../> <Image.../> </Grid> </DockPanel>

22/52 Następnie event trigger do uruchomienia animacji: <Window.Triggers> <EventTrigger SourceName="cmdStart" RoutedEvent="Button.Click"> <BeginStoryboard Name="fadeStoryboardBegin"> <Storyboard>... </Storyboard> </BeginStoryboard> </EventTrigger>... </Window.Triggers>

23/52 W podobny sposób event triggery do pozostałych akcji (podajemy tylko jakiego BeginStoryboard mają dotyczyć). Uwaga: jest to nazwa BeginStoryboard a nie Storyboard. <Window.Triggers>... <EventTrigger SourceName="cmdPause" RoutedEvent="Button.Click"> <PauseStoryboard BeginStoryboardName="fadeStoryboardBegin"/> </EventTrigger> <EventTrigger SourceName="cmdResume" RoutedEvent="Button.Click"> <ResumeStoryboard BeginStoryboardName="fadeStoryboardBegin"/> </EventTrigger> <EventTrigger SourceName="cmdStop" RoutedEvent="Button.Click"> <StopStoryboard BeginStoryboardName="fadeStoryboardBegin"/> </EventTrigger> </Window.Triggers>

(Możemy to też kontrolować zwyczajnie wywołując metody Stop(), Pause(), Resume(), etc. z obiektu Storyboard. Ale użycie powyższych akcji pozwala nam łatwo uruchamiać i zatrzymywać animację w triggerach, np. po najechaniu myszą na element.) 24/52

25/52 Przebieg animacji możemy monitorować przy użyciu poniższych zdarzeń: Completed animacja została zakończona CurrentGlobalSpeedInvalidated zmianie uległa szybkość animacji (oznacza to również pauzę, wznowienie, zmianę pozycji) CurrentStateInvalidated uruchomienie lub zakończenie CurrentTimeInvalidated tyknięcie zegara animacji (również uruchomienie lub zakończenie) RemoveRequested usuwanie animacji Może wykorzystać CurrentTimeInvalidated, by dodać wskaźnik zaawansowania animacji. <DockPanel>... <ProgressBar Name="progres" DockPanel.Dock="Bottom" Height="10" Minimum="0" Maximum="1" />... </DockPanel>

26/52 Dodajemy obsługę zdarzenia: <Window.Triggers> <EventTrigger...> <BeginStoryboard...> <Storyboard CurrentTimeInvalidated= "Storyboard_CurrentTimeInvalidated">... </Storyboard> </BeginStoryboard> </Window.Triggers> Nadawcą zdarzenia jest Clock, z którego możemy odczytać postęp animacji: private void Storyboard_CurrentTimeInvalidated(object sender, EventArgs e) { Clock clock = (Clock)sender; if(clock.currentprogress!= null) progres.value = (double)clock.currentprogress; }

27/52

28/52 Domyślnie animacje działają w 60 klatkach na sekundę. Jeśli animacja jest zbyt wymagająca (intensywnie wykorzystuje przeźroczystość, materiał wideo, duże bitmapy) możemy chcieć ją zmniejszyć, by poprawić wydajność: <Storyboard Timeline.DesiredFrameRate="30">... </Storyboard>

29/52 Posługiwanie się animacjami Co animować? Jeśli chcemy, by elementy pojawiały się i znikały: Opacity. Jeśli chcemy przemieszczać elementy: Canvas.Left, Canvas.Top (jeśli kontenerem jest Canvas), ewentualnie Margin lub/i Padding (przy pomocy ThicknessAnimation), ewentualnie MinWidth i MinHeight kolumny lub wiersza w Gridzie. RenderTransform aby przemieszczać (TranslateTransform), obracać (RotateTransform), skalować (ScaleTransform) elementy. Działają szybciej niż animacja własności określających rozmiar czy pozycję. ColorAnimation aby modyfikować własności pędzla.

30/52 Animacja transformacji Każdy element ma dwa rodzaje transformacji: RenderTransform (stosowana przed wyświetleniem obiektu) i LayoutTransform (stosowana przed ułożeniem elementów przez kontener). (Animacja nie może stworzyć transformacji, a jedynie animować własności istniejącej.) Przykład: obracający się przycisk. <Button RenderTransformOrigin="0.5,0.5"> <Button.RenderTransform> <RotateTransform/> </Button.RenderTransform> OK </Button>

31/52 EventTrigger do uruchomienia animacji: <EventTrigger RoutedEvent="Button.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty= "RenderTransform.Angle" To="360" Duration= "0:0:1" RepeatBehavior="Forever"/> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger>

32/52 I do zakończenia (powrotu do stanu początkowego): <EventTrigger RoutedEvent="Button.MouseLeave"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty= "RenderTransform.Angle" Duration="0:0:0.2"/> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger>

33/52 Parametry przycisku możemy ustawić w stylu: <Style TargetType="Button"> <Setter Property="Margin" Value="3" /> <Setter Property="Padding" Value="20,3"/> <Setter Property="HorizontalAlignment" Value="Center"/> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/> <Setter Property="RenderTransform"> <Setter.Value> <RotateTransform></RotateTransform> </Setter.Value> </Setter> <Style.Triggers> <EventTrigger... <EventTrigger... </Style.Triggers> </Style>

34/52 Teraz każdy z przycisków będzie używał tej animacji: <StackPanel> <Button>jeden</Button> <Button>dwa</Button> <Button>trzy</Button> <Button>cztery</Button> <Button>pięć</Button> </StackPanel>

Jeśli wymienimy RenderTransform na LayoutTransform: 35/52

36/52 Aby animować bardziej złożone rodzaje transformacji najlepiej umieścić je w TransformGroup: <Border.RenderTransform> <TransformGroup> <ScaleTransform></ScaleTransform> <RotateTransform></RotateTransform> </TransformGroup> </Border.RenderTransform> Następnie: <DoubleAnimation Storyboard.TargetProperty= "RenderTransform.Children[0].ScaleX".../> <DoubleAnimation Storyboard.TargetProperty= "RenderTransform.Children[0].ScaleY".../> <DoubleAnimation Storyboard.TargetProperty= "RenderTransform.Children[1].Angle".../>

37/52 Zamiast animowania transformacji elementu, można rozważyć animację prostokąta wypełnionego VisualBrushem: <Rectangle Name="rectangle"> <Rectangle.Fill> <VisualBrush Visual="{Binding ElementName=element}"/> </Rectangle.Fill> <Rectangle.RenderTransform>... </Rectangle.RenderTransform> </Rectangle>

38/52 Animowanie pędzli Kolor pędzla animujemy przy pomocy klasy ColorAnimation. Wymaga stworzenia pędzla: <Ellipse Stretch="Uniform" Margin="3" Name="elipsa"> <Ellipse.Fill> <RadialGradientBrush> <GradientStop Color="Yellow" Offset="0"/> <GradientStop Color="LawnGreen" Offset="1"/> </RadialGradientBrush> </Ellipse.Fill> </Ellipse>

39/52 Teraz możemy ustawić jego właściwości: <BeginStoryboard> <Storyboard> <ColorAnimation Storyboard.TargetName="elipsa" To="DeepSkyBlue" Storyboard.TargetProperty= "Fill.GradientStops[1].Color" Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever"/> </Storyboard> </BeginStoryboard>

40/52 PointAnimation pozwala przemieszczać punkt (działa to jak DoubleAnimation składowej X i Y). Dzięki temu możemy np. modyfikować kształt figury zbudowanej z punktów. W poniższym przykładzie animujemy centralny punkt gradientu radialnego. <PointAnimation Storyboard.TargetName="elipsa" Storyboard.TargetProperty="Fill.GradientOrigin" From="0.7,0.3" To="0.3,0.7" Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever" />

41/52 Animacja z wykorzystaniem klatek kluczowych Pozwala zdefiniować większą liczbę etapów animacji. Każda klatka ma określoną wartość docelową oraz czas. Można w ten sposób definiować bardziej złożony przebieg animacji (zmian wartości). Przykład: <Grid> <Ellipse Width="20" Height="20" Stroke="Black" Fill="Yellow" Name="elipsa" /> </Grid>

42/52 Animacja rozmiaru: <Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName= "elipsa" Storyboard.TargetProperty="Width" RepeatBehavior="Forever"> <LinearDoubleKeyFrame Value="20" KeyTime="0:0:0"/> <LinearDoubleKeyFrame Value="200" KeyTime="0:0:1"/> <LinearDoubleKeyFrame Value="200" KeyTime="0:0:2"/> <LinearDoubleKeyFrame Value="20" KeyTime="0:0:3"/> <LinearDoubleKeyFrame Value="20" KeyTime="0:0:4"/> </DoubleAnimationUsingKeyFrames>...

43/52... <DoubleAnimationUsingKeyFrames Storyboard.TargetName= "elipsa" Storyboard.TargetProperty="Height" RepeatBehavior="Forever"> <LinearDoubleKeyFrame Value="20" KeyTime="0:0:0"/> <LinearDoubleKeyFrame Value="20" KeyTime="0:0:1"/> <LinearDoubleKeyFrame Value="200" KeyTime="0:0:2"/> <LinearDoubleKeyFrame Value="200" KeyTime="0:0:3"/> <LinearDoubleKeyFrame Value="20" KeyTime="0:0:4"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Window.Triggers> Klatki określają węzły animacji punkty, do jakich ma się udać animacja, wartości jakie mamy przyjąć. Dzielą one animację na wykonywane po kolei segmenty.

44/52 Poza interpolacją liniową między klatkami kluczowymi, możemy wybrać wartości dyskretne (nie dokonuje interpolacji wartość jest przyjmowana w określonej chwili czasu): <ColorAnimationUsingKeyFrames Storyboard.TargetName="elipsa" Storyboard.TargetProperty="Fill.Color" RepeatBehavior="Forever"> <DiscreteColorKeyFrame Value="Yellow" KeyTime="0:0:0"/> <DiscreteColorKeyFrame Value="Red" KeyTime="0:0:0.3"/> <DiscreteColorKeyFrame Value="Green" KeyTime="0:0:0.6"/> <DiscreteColorKeyFrame Value="Blue" KeyTime="0:0:0.9"/> <DiscreteColorKeyFrame Value="Yellow" KeyTime="0:0:1.2"/> </ColorAnimationUsingKeyFrames> Wartość KeyTime (koniec segmentu animacji) może być również określana procentowo. Możemy używać różnych interpolacji w obrębie jednej animacji.

45/52 Dostępny jest jeszcze jeden rodzaj klatek kluczowych: oparte na krzywej Beziera. Używają interpolacji do zmiany wartości, ale zgodnie z krzywą Beziera. Dwa punkty krzywej są stałe (0,0 i 1,1), pozostałe dwa definiowane są przy pomocy KeySpline. <Canvas> <Ellipse Canvas.Top="20"... Name="elipsa1"/> <Ellipse Canvas.Top="60"... Name="elipsa2"/> </Canvas>

<Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName= "elipsa1" Storyboard.TargetProperty="(Canvas.Left)" RepeatBehavior="Forever"> <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/> <LinearDoubleKeyFrame Value="300" KeyTime="0:0:4"/> <LinearDoubleKeyFrame Value="0" KeyTime="0:0:8"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName= "elipsa2" Storyboard.TargetProperty="(Canvas.Left)" RepeatBehavior="Forever"> <SplineDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <SplineDoubleKeyFrame Value="300" KeyTime="0:0:4" KeySpline="0.5,0 0.5,1"/> <SplineDoubleKeyFrame Value="0" KeyTime="0:0:8" KeySpline="0.2,0.5 0.5,0.2"/> </DoubleAnimationUsingKeyFrames> </Storyboard> 46/52

47/52 Animation easing Efekt nieliniowy na początku lub końcu zmiany wartości. Pozwala na bardziej naturalne animacje. Własność może np. łagodniej zbliżać się do wartości docelowej lub oscylować przez jakiś czas wokół niej. <Storyboard...> <DoubleAnimation Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width" To="400" Duration="0:0:1.5"> <DoubleAnimation.EasingFunction> <ElasticEase EasingMode="EaseOut" Oscillations="10"/> </DoubleAnimation.EasingFunction> </DoubleAnimation> </Storyboard> EasingMode (EaseOut, EaseIn, EaseInOut) określa, czy efekt ma być stosowany na początku czy końcu animacji.

48/52 Dostępne funkcje: BackEase pozwala na przestrzelenie się (własność początkowo osiąga wartość przekraczającą docelową), by potem powoli dorównać ElasticEase efekt sprężystości (przestrzelenie i słabnąca oscylacja) BounceEase podobnie jak wyżej, ale bez przestrzelenia CircleEase, CubicEase, QuadraticEase, QuarticEase, QuinticEase, SineEase, PowerEase, ExponentialEase steruje początkowym przyśpieszeniem i końcowym zwolnieniem przy użyciu różnych funkcji Możemy to też stosować do klatek kluczowych wymaga odpowiedniego typu klatki: <PointAnimationUsingKeyFrames... > <LinearPointKeyFrame.../> <EasingPointKeyFrame...> <EasingPointKeyFrame.EasingFunction> <CircleEase></CircleEase> </EasingPointKeyFrame.EasingFunction> </EasingPointKeyFrame> <LinearPointKeyFrame.../> <LinearPointKeyFrame.../> </PointAnimationUsingKeyFrames>

Animacje oparte na ścieżkach Używają geometrii, by określić ustawianą przez animację wartość. Przeważnie stosowane do określania położenia (ale mogą działać dla dowolnych własności jej wartość odczytywana jest ze zdefiniowanej ścieżki). Zaczynamy od zdefiniowania geometrii: <Window.Resources> <PathGeometry x:key="gwiazda" Figures="M 95,20 L 160,150 L 20,70 L 180,60 L 50,160 Z"/>... </Window.Resources> Następnie możemy jej użyć do animacji położenie elipsy: <Storyboard> <DoubleAnimationUsingPath Storyboard.TargetName="elipsa3" Storyboard.TargetProperty="(Canvas.Left)" PathGeometry="{StaticResource gwiazda}" Duration="0:0:5" RepeatBehavior="Forever" Source="X" /> <DoubleAnimationUsingPath Storyboard.TargetName="elipsa3" Storyboard.TargetProperty="(Canvas.Top)" PathGeometry="{StaticResource gwiazda}" Duration="0:0:5" RepeatBehavior="Forever" Source="Y"/> </Storyboard> 49/52

50/52 Efekty WPF dysponuje zestawem efektów wizualnych, które możemy nadać dowolnemu elementowi. Są dwie grupy efektów: BitmapEffects (mniej wydajne) oraz Effects. Przykład: <Label...> <Label.BitmapEffect> <OuterGlowBitmapEffect GlowColor="Yellow" GlowSize="20" Opacity="0.5"/> </Label.BitmapEffect> Hello world! </Label> <Button...> <Button.Effect> <BlurEffect Radius="5"/> </Button.Effect> OK </Button>

51/52 BitmapEffects: BlurBitmapEffect rozmycie (własności Radius, KernelType) BevelBitmapEffect efekt wypukłej krawędzi (własności BevelWidth, EdgeProfile, LightAngle, Relief, Smoothness) EmbossBitmapEffect efekt wyżłobienia (własności LightAngle, Relief) OuterGlowBitmapEffect efekt halo (GlowColor, GlowSize, Noise, Opacity) DropShadowBitmapEffect efekt cienia (Color, Direction, Noise, Opacity, ShadowDepth, Softness) BitmapEffectGroup pozwala łączyć kilka efektów Effects: BlurEffect rozmycie (własności Radius, KernelType, RenderingBias) DropShadowEffect efekt cienia (własności BlurRadius, Color, Direction, Opacity, ShadowDepth, RenderingBias) ShaderEffect pozwala zastosować efekt pixel shadera (należy wskazać gotowy, skompilowany plik) Oczywiście efekty (ich własności) też możemy animować.

52/52 Frame-Based Animation WPF pozwala również tworzyć własną, dowolną animację przez ręczne generowanie zawartości kolejnych ramek. Należy obsłużyć statyczne zdarzenie CompositionTarget.Rendering. Będzie ono podnoszone cyklicznie (aby pobrać zawartość ramki do wyrenderowania). CompositionTarget.Rendering += RenderFrame; Naszym zadaniem jest dostarczenie zawartości: poprzez manipulację elementami okna, dodawanie nowych, etc. private void RenderFrame(object sender, EventArgs e) {... Ellipse ellipse = new Ellipse(); ellipse.width =...; ellipse.height =...; ellipse.fill =...; canvas.children.add(ellipse);... }