Omówienie animacji właściwości

Wypróbuj sposób tworzenia wiadomości
Jetpack Compose to zalecany zestaw narzędzi UI na Androida. Dowiedz się, jak korzystać z animacji w Compose

System animacji właściwości to solidna struktura, która umożliwia pozwala animować niemal wszystko. Możesz zdefiniować animację, aby z czasem zmienić dowolną właściwość obiektu, niezależnie od tego, czy wyświetla się na ekranie, czy nie. Animacja właściwości zmienia (pola w obiekcie) w określonym czasie. Aby coś animować, musisz określić parametr właściwość obiektu, którą chcesz animować, taką jak pozycja obiektu na ekranie, czas trwania obiektu dla których ma być animowany i jakie wartości mają być animowane.

System animacji właściwości pozwala określić następujące cechy obiektu animacja:

  • Czas trwania: możesz podać czas trwania animacji. Domyślna długość to 300 ms.
  • Interpolacja czasu: możesz określić sposób obliczania wartości właściwości jako obecnego czasu trwania animacji.
  • Liczba powtórzeń i zachowanie: możesz określić, czy animacja ma być powtarzana, gdy dochodzi do końca czasu trwania animacji i ile razy ma zostać powtórzona. Możesz też określ, czy animacja ma być odtwarzana wstecz. ustawianie odwrotnego odtwarzania, animacja w przód i w tył, aż zostanie osiągnięta odpowiednia liczba powtórzeń.
  • Zestawy animacji: można grupować animacje w logiczne zbiory, które są odtwarzane razem lub sekwencyjnie lub po określonych opóźnieniach.
  • Opóźnienie odświeżania klatki: możesz określić, jak często mają być odświeżane klatki animacji. domyślnie jest ustawione odświeżanie co 10 ms, ale aplikacja może odświeżać klatki z szybkością ostatecznie zależy od tego, jak duży jest ruch w systemie i jak szybko może on obsługiwać minutnik.

Pełny przykład animacji właściwości znajdziesz w sekcji Klasa ChangeColor w elemencie Customprzejść znajdziesz na GitHubie.

Jak działa animacja właściwości

Najpierw spójrzmy na prosty przykład, jak działa animacja. Rysunek 1 przedstawia hipotetyczny obiekt animowany za pomocą właściwości x, która reprezentuje w poziomie na ekranie. Czas trwania animacji jest ustawiony na 40 ms oraz odległość ma 40 pikseli. Co 10 ms (czyli domyślna częstotliwość odświeżania klatek) obiekt przesuwa się w poziomie o 10 pikseli. Po 40 ms animacja zatrzymuje się, a obiekt kończy się na pozycja w poziomie 40. To jest przykład animacji z interpolacją liniową, co oznacza porusza się ze stałą prędkością.

Rysunek 1. Przykład animacji liniowej

Możesz też określić animacje z interpolacją nieliniową. Rysunek 2 przedstawia hipotetyczny obiekt, który przyspiesza na początku animacji i zwalnia na na koniec animacji. Obiekt nadal przesuwa się o 40 pikseli w czasie 40 ms, ale nie liniowo. W na początku animacja przyspiesza do połowy, a potem zwalnia do końca animacji. Jak widać na rys. 2, przebyta odległość na początku i na końcu animacji jest mniejszy niż w środku.

Rysunek 2. Przykład animacji nieliniowej

Przyjrzyjmy się bliżej kluczowym komponentom systemu animacji właściwości oblicza animacje takie jak te pokazane powyżej. Rysunek 3 przedstawia główne klasy współdziałają ze sobą.

Rysunek 3. Sposób obliczania animacji

Obiekt ValueAnimator śledzi czas animacji, takich jak czas trwania animacji i bieżącą wartość właściwości, ani tworzyć animacji.

Pole ValueAnimator zawiera znacznik TimeInterpolator, który definiuje interpolację animacji, i zasadę TypeEvaluator, która określa sposób obliczania wartości dla właściwości animowanego. Na przykład na rys. 2 wartością TimeInterpolator będzie AccelerateDecelerateInterpolator, a TypeEvaluator to IntEvaluator.

Aby rozpocząć animację, utwórz ValueAnimator i dodaj do niego atrybut wartość początkową i końcową właściwości, którą chcesz animować, oraz czas trwania parametru animację. Gdy wywołujesz start(), animację Podczas całej animacji ValueAnimator oblicza ułamek, który upłynął od 0 do 1, w zależności od czasu trwania animacji i czasu, jaki upłynął. ułamek czasu trwania przedstawia procent czasu ukończenia animacji, 0 oznacza 0% a 1 oznacza 100%. Na przykład na ilustracji 1 ułamek czasu, który upłynął w czasie t = 10 ms, wyniesie 0,25. ponieważ łączny czas trwania to t = 40 ms.

Gdy funkcja ValueAnimator zakończy obliczanie ułamka, funkcja wywołuje aktualnie ustawioną funkcję TimeInterpolator, aby obliczyć ułamek interpolowany. Interpolowany ułamek mapuje upływ czasu na nowy biorąc pod uwagę ustawioną interpolację czasową. Na przykład na rys. 2 ponieważ animacja powoli przyspiesza, interpolowany ułamek, około 0,15, jest mniejszy niż upływ czasu, 0,25, przy t = 10 ms. Na rys. 1 interpolowany ułamek jest zawsze taki sam jak upływ czasu.

Podczas obliczania interpolowanego ułamka funkcja ValueAnimator wywołuje odpowiednią TypeEvaluator, aby obliczyć wartość argumentu animowaną właściwość, na podstawie interpolowanego ułamka, wartości początkowej wartość końcową animacji. Na przykład na rys .2 interpolowany ułamek wynosił 0,15 w t = 10 ms, więc jego wartość w tym momencie wynosi 0,15 × (40 – 0), czyli 6.

Czym animacja właściwości różni się od animacji widoku

System animacji widoku umożliwia animowanie tylko elementu View więc jeśli chcesz animować obiekty inne niż View, musisz zaimplementować za pomocą własnego kodu. System animacji widoku jest również ograniczony, ponieważ ujawnia kilka aspektów obiektu View animacji, takich jak skalowanie możesz zmienić widok, ale nie zmienić koloru tła.

Inną wadą systemu animacji widoku jest to, że zmienia się on tylko wtedy, gdy tag Narysowano widok, a nie sam widok. Jeśli na przykład animujesz przycisk do poruszania się na ekranie, przycisk będzie prawidłowo rysowany, ale miejsce, w którym można kliknąć przycisk nie zmienia się, więc trzeba wprowadzić własną logikę, aby to umożliwić.

W systemie animacji właściwości te ograniczenia są całkowicie usuwane, dowolną właściwość dowolnego obiektu (obiekty View i inne niż widoki), a sam obiekt zostaje rzeczywiście zmodyfikowany. System animacji właściwości jest też bardziej solidny pod względem animacji. Na przypisujesz animatorów do właściwości, które mają być animowane, takich jak kolor, położenie lub rozmiar i mogą definiować takie aspekty animacji, jak interpolacja synchronizacji wielu animatorów.

Jednak konfiguracja systemu animacji widoku jest krótsza i wymaga mniej kodu do napisania. Jeśli animacja widoku spełnia wszystkie wymagania, albo jeśli istniejący kod został już działa zgodnie z oczekiwaniami, nie ma potrzeby używania systemu animacji właściwości. Może też użycie obu systemów animacji w różnych sytuacjach ma sens w różnych sytuacjach.

Omówienie interfejsu API

Większość interfejsów API systemu animacji właściwości znajdziesz w języku: android.animation. Ponieważ system animacji widoku już definiuje wiele interpolatorów w argumencie android.view.animation, możesz użyć z interpolatorami w systemie animacji właściwości. W tabelach poniżej opisujemy główne komponentów systemu animacji właściwości.

Klasa Animator zapewnia podstawową strukturę tworzenia ani animacji. Zwykle nie używasz tej klasy bezpośrednio, ponieważ zapewnia ona tylko minimalną tę funkcję należy rozszerzyć, aby w pełni obsługiwać animowanie wartości. Poniżej podklasy rozszerzają Animator:

Tabela 1. Animatorzy

Kategoria Opis
ValueAnimator Główny mechanizm czasowy animacji właściwości, który również oblicza wartości dla właściwości, która ma być animowana. Ma wszystkie główne funkcje służące do obliczania animacji i zawierają szczegółowe informacje o czasie każdej animacji, a także informacje o tym, czy powtórzenia animacji, detektory odbierające zdarzenia aktualizacji oraz możliwość ustawiania typów do oceny. Animowanie właściwości składa się z dwóch elementów: obliczanie wartości animacji i ustawianie ich dla obiektu i właściwości, które są animowane. ValueAnimator nie wykonuje drugiego fragmentu, więc posłuchaj dla aktualizacji wartości obliczonych przez ValueAnimator i i modyfikować obiekty, które mają być animowane za pomocą własnej logiki. Zapoznaj się z sekcją na temat Więcej informacji znajdziesz w artykule Animating with ValueAnimator.
ObjectAnimator Podklasa klasy ValueAnimator, która umożliwia ustawienie wartości docelowej obiektu i obiektu do animacji. Ta klasa odpowiednio aktualizuje właściwość, gdy: oblicza nową wartość animacji. Czego chcesz użyć ObjectAnimator przeważnie, bo znacznie ułatwia to animowanie wartości na obiektach docelowych. Pamiętaj jednak: czasami lepiej jest używać usługi ValueAnimator bezpośrednio, ponieważ usługa ObjectAnimator ma jeszcze kilka ograniczeń, takich jak metody akcesora, które będą obecne w obiekcie docelowym.
AnimatorSet Zapewnia mechanizm grupowania animacji, tak aby były uruchamiane relacji między sobą. Możesz ustawić odtwarzanie animacji po kolei, po kolei lub później. określonego opóźnienia. Więcej informacji znajdziesz w sekcji Choreografia wielu osób za pomocą zestawów animacji.

Weryfikatorzy informują system animacji właściwości, jak obliczyć wartości danej usłudze. Zbierają dane o czasie dostarczone przez Animator klasy, wartość początkową i końcową animacji oraz obliczają animowane wartości właściwości na podstawie tych danych. System animacji właściwości udostępnia te weryfikatory:

Tabela 2. Weryfikatorzy

Klasa/interfejs Opis
IntEvaluator Domyślny tester do obliczania wartości właściwości int.
FloatEvaluator Domyślny tester do obliczania wartości właściwości float.
ArgbEvaluator Domyślny weryfikator do obliczania wartości reprezentowanych właściwości koloru pod postacią wartości szesnastkowych.
TypeEvaluator Interfejs, który pozwala utworzyć własnego testera. Jeśli animujesz element właściwością obiektu, która nie jest wartością int, float ani kolorem, musisz zaimplementować interfejs TypeEvaluator, aby określić, do obliczenia animowanych wartości właściwości obiektu. Możesz też określić niestandardową wartość TypeEvaluator dla atrybutów int, float i koloru. , jeśli chcesz przetwarzać te typy w inny sposób niż domyślne. Więcej informacji znajdziesz w sekcji Korzystanie z narzędzia TypeEvaluator na temat tego, jak napisać weryfikatora.

Interpolator czasowy określa sposób obliczania konkretnych wartości w animacji jako wartości funkcji czasu. Możesz na przykład określić, że animacje mają następować liniowo w całym czyli animację przesuwa się równomiernie przez cały czas. Można też ją określić, aby użyć czasu nieliniowego, np. przyspieszania na początku i zwalniania na początku na koniec animacji. Tabela 3 opisuje interpolatory zawarte w funkcji android.view.animation. Jeśli żaden z podanych interpolatorów nie pasuje zaimplementuj interfejs TimeInterpolator i utwórz własny. Więcej informacji o tworzeniu niestandardowych wartości znajdziesz w artykule Używanie interpolatorów. i interpolatorze.

Tabela 3. Interpolatory

Klasa/interfejs Opis
AccelerateDecelerateInterpolator Interpolator, którego szybkość zmiany zaczyna się i kończy powoli, ale przyspiesza do środka.
AccelerateInterpolator Interpolator, którego tempo zmian zaczyna się powoli, a potem przyspiesza.
AnticipateInterpolator Interpolator, którego zmiana zaczyna się od tyłu, a potem przesuwa się do przodu.
AnticipateOvershootInterpolator Interpolator, którego zmiana rozpoczyna się wstecz, przesuwa do przodu i przebiega do wartości docelowej, a następnie wraca do ostatecznej wartości.
BounceInterpolator Interpolator, którego zmiana jest odbijana na końcu.
CycleInterpolator Interpolator, którego animacja powtarza się przez określoną liczbę cykli.
DecelerateInterpolator Interpolator, którego tempo zmian szybko rozpoczyna się, zwalnia.
LinearInterpolator Interpolator, którego szybkość zmian jest stała.
OvershootInterpolator Interpolator, którego zmiana przesuwa się do przodu i przekracza ostatnią wartość, wrócą.
TimeInterpolator Interfejs umożliwiający wdrożenie własnego interpolatora.

Animacja za pomocą ValueAnimator

Klasa ValueAnimator pozwala animować pewne wartości określonego typu w polu czas trwania animacji, określając zestaw int, float lub kolor. wartości animacji. Otrzymujesz ValueAnimator, dzwoniąc do jednego z jego metody fabryczne: ofInt(), ofFloat() lub ofObject(). Na przykład:

Kotlin

ValueAnimator.ofFloat(0f, 100f).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();

W tym kodzie ValueAnimator rozpoczyna obliczanie wartości funkcji od 0 do 100 animacji przez okres 1000 ms, gdy działa metoda start().

Możesz też określić niestandardowy typ animacji, wykonując te czynności:

Kotlin

ValueAnimator.ofObject(MyTypeEvaluator(), startPropertyValue, endPropertyValue).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

W tym kodzie ValueAnimator rozpoczyna obliczanie wartości funkcji animacji między startPropertyValue a endPropertyValue za pomocą funkcji logika dostarczana przez MyTypeEvaluator na czas trwania 1000 ms, gdy działa metoda start().

Możesz użyć wartości animacji, dodając element AnimatorUpdateListener do obiektu ValueAnimator, jak pokazano w ten kod:

Kotlin

ValueAnimator.ofObject(...).apply {
    ...
    addUpdateListener { updatedAnimation ->
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        textView.translationX = updatedAnimation.animatedValue as Float
    }
    ...
}

Java

animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

W: onAnimationUpdate() możesz uzyskać dostęp do zaktualizowanej wartości animacji i użyć jej we właściwości jeden z Twoich widoków. Więcej informacji o słuchaczach znajdziesz w sekcji Detektory animacji.

Animacja przy użyciu ObjectAnimator

ObjectAnimator to podklasa klasy ValueAnimator (omówiona w poprzedniej sekcji) łącząca sygnatury czasowe mechanizmu i obliczania wartości ValueAnimator z możliwością animowanie nazwanej właściwości obiektu docelowego. To znacznie ułatwia animowanie obiektów, nie muszą już implementować: ValueAnimator.AnimatorUpdateListener, ponieważ właściwość animowana jest aktualizowana automatycznie.

Tworzenie instancji ObjectAnimator jest podobne do ValueAnimator, ale dodatkowo musisz podać obiekt i nazwę jego właściwości (np. ciąg znaków) wraz z wartościami, które będą animowane między:

Kotlin

ObjectAnimator.ofFloat(textView, "translationX", 100f).apply {
    duration = 1000
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();

Aby mieć ObjectAnimator właściwości aktualizacji musisz wykonać te czynności:

  • Animowana właściwość obiektu, którą chcesz animować, musi mieć funkcję ustawiającą (w przypadku wielbłąda) w postaci set<PropertyName>() Ponieważ ObjectAnimator automatycznie aktualizuje właściwość podczas animacji, musi mieć dostęp do właściwości metody określania. Jeśli na przykład nazwa usługi to foo, musisz mają metodę setFoo(). Jeśli ta metoda ustawienia nie istnieje, są dostępne opcje:
    • Dodaj metodę ustawiającą do klasy, jeśli masz do tego uprawnienia.
    • Użyj klasy kodu, który możesz zmieniać i który powinien otrzymywać z prawidłową metodą ustawiającą i przekazać ją do pierwotnego obiektu.
    • Użyj w zamian zasady ValueAnimator.
  • Jeśli określisz tylko jedną wartość parametru values... w jednej z metod fabryki ObjectAnimator, przyjmuje się, że jest to wartość końcowa parametru animację. Dlatego właściwość obiektu, którą animujesz, musi mieć funkcję pobierania. służąca do uzyskania początkowej wartości animacji. Funkcja pobierania musi być w funkcji format get<PropertyName>(). Jeśli na przykład nazwa właściwości to foo, musisz mieć metodę getFoo().
  • Metody getter (w razie potrzeby) i metody ustawiania właściwości, którą animujesz, muszą działają na tym samym typie co wartości początkowa i końcowa określona w funkcji ObjectAnimator. Na przykład: targetObject.setPropName(float) i targetObject.getPropName() jeśli utworzysz następujący element ObjectAnimator:
    ObjectAnimator.ofFloat(targetObject, "propName", 1f)
    
  • W zależności od właściwości lub obiektu, które animujesz, konieczne może być wywołanie metody invalidate() w widoku danych, by wymusić ponowne przerysowanie ekranu za pomocą animowanych wartości. Robi się to w onAnimationUpdate() oddzwanianie. Na przykład animowanie właściwości koloru obiektu Drawable powoduje zaktualizowanie tylko atrybutu po ponownym wyświetleniu obiektu. Wszystkie kreatory właściwości w widoku danych, takie jak setAlpha() i setTranslationX() unieważnia widok, więc nie trzeba unieważniać go przy wywoływaniu tych z nowymi wartościami. Więcej informacji o słuchaczach znajdziesz w sekcji Detektory animacji.

Tworzenie choreografii do wielu animacji za pomocą narzędzia AnimatorSet

Często trzeba odtworzyć animację w zależności od tego, kiedy rozpocznie się inna animacja, na ich końcu. System Android umożliwia łączenie animacji w elementy AnimatorSet, dzięki którym można określić, czy mają się rozpoczynać. jednocześnie, sekwencyjnie lub po określonym opóźnieniu. Obiekty AnimatorSet możesz też zagnieżdżać w sobie.

Ten fragment kodu odtwarza Animator w następujący sposób:

  1. Odtwarzam bounceAnim.
  2. Odtwarza: squashAnim1, squashAnim2, stretchAnim1 i stretchAnim2.
  3. Odtwarzam bounceBackAnim.
  4. Odtwarzam fadeAnim.

Kotlin

val bouncer = AnimatorSet().apply {
    play(bounceAnim).before(squashAnim1)
    play(squashAnim1).with(squashAnim2)
    play(squashAnim1).with(stretchAnim1)
    play(squashAnim1).with(stretchAnim2)
    play(bounceBackAnim).after(stretchAnim2)
}
val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
}
AnimatorSet().apply {
    play(bouncer).before(fadeAnim)
    start()
}

Java

AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

Detektory animacji

Za pomocą detektorów opisanych poniżej możesz nasłuchiwać ważnych zdarzeń w czasie trwania animacji.

  • Animator.AnimatorListener
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate() – wywoływane przy każdej klatce animacji. Posłuchaj tego zdarzenia na: użyj obliczonych wartości wygenerowanych przez ValueAnimator podczas animację. Aby użyć tej wartości, wyślij zapytanie do obiektu ValueAnimator przekazywane do zdarzenia, by uzyskać bieżącą animowaną wartość za pomocą metody getAnimatedValue(). Wdrożenie Jeśli używasz ValueAnimator, wymagany jest detektor.

      W zależności od animowanej właściwości lub obiektu może być konieczne wywołanie invalidate() w widoku danych, aby wymusić stosowanie danego obszaru ekranu, aby ponownie wczytać się z nowymi animowanymi wartościami. Na przykład animowanie elementu Właściwość color obiektu Drawable aktualizuje ekran tylko wtedy, gdy ten obiekt i spowoduje to ponowne zarysowanie. Wszystkie osoby tworzące nieruchomości w widoku danych na przykład setAlpha() i setTranslationX() unieważnia widok Dzięki temu nie trzeba unieważniać widoku danych przy wywoływaniu tych metod z nowymi wartościami.

Możesz przedłużyć zajęcia AnimatorListenerAdapter zamiast nie implementujesz interfejsu Animator.AnimatorListener. chcesz wdrożyć wszystkie metody interfejsu Animator.AnimatorListener za pomocą prostego interfejsu online. Klasa AnimatorListenerAdapter zawiera puste implementacji metod, które można zastąpić.

Na przykład ten fragment kodu tworzy AnimatorListenerAdapter tylko za onAnimationEnd() wywołanie zwrotne:

Kotlin

ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
    addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            balls.remove((animation as ObjectAnimator).target)
        }
    })
}

Java

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}

Animuj zmiany układu w obiektach ViewGroup

System animacji właściwości umożliwia animowanie zmian obiektów ViewGroup. a także pozwalają w łatwy sposób animować same obiekty View.

Możesz animować zmiany układu w grupie widoków za pomocą LayoutTransition zajęcia. Widoki w grupie widoków pojawiają się i znikają animacje po dodaniu ich do by usunąć je z grupy widoków lub podczas wywoływania Metoda setVisibility() z VISIBLE, INVISIBLE lub GONE Pozostałe widoki w grupie widoków ich nowe pozycje przy dodawaniu lub usuwaniu widoków. Możesz zdefiniować te animacje w obiekcie LayoutTransition dzwoniąc pod numer setAnimator() i przekazywanie obiektu Animator z jedną z metod następujące stałe LayoutTransition:

  • APPEARING – flaga wskazująca animację, która jest odtwarzana na elementach, które są które wyświetlają się w kontenerze.
  • CHANGE_APPEARING – flaga wskazująca animację, która jest odtwarzana na elementach, które są zmienia się z powodu pojawienia się w kontenerze nowego elementu.
  • DISAPPEARING – flaga wskazująca animację, która jest odtwarzana na elementach, które są znika z kontenera.
  • CHANGE_DISAPPEARING – flaga wskazująca animację uruchamianą na elementach, które zmienia się, ponieważ element znika z kontenera.

Możesz definiować własne animacje dla tych 4 typów zdarzeń, aby dostosować ich wygląd. przejść do układu strony lub wskazać systemowi animacji, by używał animacji domyślnych.

Aby ustawić wartość atrybutu android:animateLayoutchanges na true dla: ViewGroup wykonuje te czynności:

<LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/verticalContainer"
    android:animateLayoutChanges="true" />

Ustawienie wartości prawda w atrybucie prawda powoduje automatyczne animowanie widoków danych, które zostały dodane lub usunięte z ViewGroup oraz pozostałych widoków w grupie ViewGroup.

Animacja zmian stanu widoku za pomocą StateListAnimator

Klasa StateListAnimator pozwala zdefiniować animacje, które działają, gdy stan widoku zmienia się. Obiekt ten zachowuje się jako otoka Animator obiekt, wywołując tę animację, gdy jest określony zmiany stanu wyświetlania (np. „naciśnięcie” lub „zaznaczenie”).

Element StateListAnimator można zdefiniować w zasobie XML z rdzeniem określony przez siebie element <selector> i elementy podrzędne <item>, inny stan widoku zdefiniowany przez klasę StateListAnimator. Każdy <item> zawiera definicję zestawu animacji właściwości.

Na przykład ten plik tworzy animator listy stanów, który zmienia skalę x i y. widoku po naciśnięciu:

res/xml/animate_scale.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- the pressed state; increase x and y size to 150% -->
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
        </set>
    </item>
    <!-- the default, non-pressed state; set x and y size to 100% -->
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>

Aby dołączyć do widoku animator listy stanów, dodaj android:stateListAnimator w ten sposób:

<Button android:stateListAnimator="@xml/animate_scale"
        ... />

Teraz animacje zdefiniowane w polu animate_scale.xml są używane, gdy przycisk tego przycisku zmian stanu.

Aby zamiast tego przypisać animator listy stanów do widoku w kodzie, użyj AnimatorInflater.loadStateListAnimator() i przypisz animatora do widoku za pomocą metody View.setStateListAnimator().

Zamiast animować właściwości widoku, możesz odtworzyć rysowalną animację między zmian stanu za pomocą funkcji AnimatedStateListDrawable. Niektóre widżety systemowe w Android 5.0 używa tych animacji domyślnie. Ten przykład pokazuje, aby zdefiniować AnimatedStateListDrawable jako zasób XML:

<!-- res/drawable/myanimstatedrawable.xml -->
<animated-selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- provide a different drawable for each state-->
    <item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
        android:state_pressed="true"/>
    <item android:id="@+id/focused" android:drawable="@drawable/drawableF"
        android:state_focused="true"/>
    <item android:id="@id/default"
        android:drawable="@drawable/drawableD"/>

    <!-- specify a transition -->
    <transition android:fromId="@+id/default" android:toId="@+id/pressed">
        <animation-list>
            <item android:duration="15" android:drawable="@drawable/dt1"/>
            <item android:duration="15" android:drawable="@drawable/dt2"/>
            ...
        </animation-list>
    </transition>
    ...
</animated-selector>

Użyj narzędzia TypeEvaluator

Jeśli chcesz animować typ, który jest nieznany systemowi Android, możesz utworzyć własne używając interfejsu TypeEvaluator. Typy, które są rozpoznawane przez system Android to int, float, czyli kolor, który jest obsługiwane przez typy IntEvaluator, FloatEvaluator i ArgbEvaluator weryfikatorami.

TypeEvaluator ma tylko 1 metodę implementacji metody evaluate(). Dzięki temu używany do zwrócenia odpowiedniej wartości dla właściwości animowanej w tagu bieżącego punktu animacji. Zajęcia FloatEvaluator zademonstrują jak to zrobić:

Kotlin

private class FloatEvaluator : TypeEvaluator<Any> {

    override fun evaluate(fraction: Float, startValue: Any, endValue: Any): Any {
        return (startValue as Number).toFloat().let { startFloat ->
            startFloat + fraction * ((endValue as Number).toFloat() - startFloat)
        }
    }

}

Java

public class FloatEvaluator implements TypeEvaluator {

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}

Uwaga: po uruchomieniu funkcji ValueAnimator (lub ObjectAnimator) oblicza bieżący ułamek czasu (wartość od 0 do 1), a następnie oblicza jej wersję interpolowaną w zależności jakiego interpolatora używasz. Ułamek interpolowany to wartość, jaką TypeEvaluator otrzymuje przez parametr fraction, więc nie trzeba uwzględniać interpolatora przy obliczaniu wartości animowanych.

Korzystanie z interpolatorów

Interpolator określa sposób obliczania konkretnych wartości w animacji jako funkcja obecnie się znajdujesz. Możesz na przykład określić, że animacje będą następować liniowo przez całą animację, co oznacza, że animacja przesuwa się równomiernie przez cały czas. Możesz też określić, które animacje będą używane. w czasie nieliniowym, np. z użyciem przyspieszania lub zwalniania na początku lub końcu animację.

Interpolatory w systemie animacji otrzymują ułamek od animatatorów, które reprezentują czasu trwania animacji. Interpolator modyfikuje ten ułamek, aby zbiegł się z typem i animację. System Android udostępnia zestaw typowych interpolatorów w android.view.animation package. Jeśli żadna z tych opcji nie pasuje możesz wdrożyć interfejs TimeInterpolator i utworzyć własnych.

Poniżej pokazujemy, jak domyślny interpolator AccelerateDecelerateInterpolator i LinearInterpolator obliczają ułamki interpolowane. LinearInterpolator nie ma wpływu na ułamek czasu, który upłynął. AccelerateDecelerateInterpolator przyspiesza do animacji i zwalnia. Logikę tych interpolatorów definiują następujące metody:

AccelerateDecelerateInterpolator,

Kotlin

override fun getInterpolation(input: Float): Float =
        (Math.cos((input + 1) * Math.PI) / 2.0f).toFloat() + 0.5f

Java

@Override
public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

Interpolator liniowy

Kotlin

override fun getInterpolation(input: Float): Float = input

Java

@Override
public float getInterpolation(float input) {
    return input;
}

Poniższa tabela przedstawia przybliżone wartości obliczane przez te interpolatory animacji trwających 1000 ms:

Upłynęło: ms Ułamek czasu/ułamek interpolowany (liniowy) Ułamek interpolowany (przyspiesz/zwolnij)
0 0 0
200 0,2 0,1
400 0,4 0,345
600 0,6 0,8
800 0,8 0,9
1000 1 1

Jak widać w tabeli, LinearInterpolator zmienia wartości. z tą samą prędkością, 0,2 na każde 200 ms. AccelerateDecelerateInterpolator zmienia wartości szybciej niż w przypadku parametru LinearInterpolator w zakresie od 200 do 600 ms i wolniej od 600 do 600 ms 1000ms.

Określanie klatek kluczowych

Obiekt Keyframe składa się z pary czas/wartość, która pozwala określić do określonego stanu w danym momencie animacji. Każda klatka kluczowa może też mieć własne interpolatorem do sterowania zachowaniem animacji w przedziale czasu między poprzednim czas klatki kluczowej oraz czas tej klatki kluczowej.

Aby utworzyć instancję obiektu Keyframe, musisz użyć jednej z fabryk ofInt(), ofFloat() lub ofObject(), aby uzyskać odpowiedni typ Keyframe. Następnie dzwonisz metody fabrycznej ofKeyframe() do uzyskać obiekt PropertyValuesHolder. Mając obiekt, możesz uzyskać animatora, przekazując obiekt PropertyValuesHolder obiektu do animacji. Fragment kodu ilustruje, jak to zrobić:

Kotlin

val kf0 = Keyframe.ofFloat(0f, 0f)
val kf1 = Keyframe.ofFloat(.5f, 360f)
val kf2 = Keyframe.ofFloat(1f, 0f)
val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2)
ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation).apply {
    duration = 5000
}

Java

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation);
rotationAnim.setDuration(5000);

Animuj wyświetlenia

System animacji obiektu umożliwia sprawne animowanie obiektów i ofert. kilka zalet w porównaniu do systemu animacji widoku. Widok system animacji przekształcił obiekty View, zmieniając sposób ich rysowania. To było w kontenerze każdego widoku danych, ponieważ sam widok nie miał żadnych właściwości, którymi można by manipulować. W efekcie widok danych był animowany, ale nie spowodował zmian w samym obiekcie widoku. Ten doprowadziło do zachowania, takiego jak obiekt wciąż istniał w pierwotnej lokalizacji, mimo że został narysowanych w innym miejscu na ekranie. W Androidzie 3.0 nowe usługi i odpowiadające im Aby wyeliminować tę wadę, dodano metody pobierania i ustawiania.

System animacji właściwości. mogą animować widoki na ekranie, zmieniając rzeczywiste właściwości obiektów widoku. W dodawanie, Widok automatycznie wywołuje też funkcję invalidate() odświeża ekran po każdej zmianie jego właściwości. Nowe właściwości klasy View, które ułatwiają tworzenie animacji właściwości, to:

  • translationX i translationY: te właściwości określają, gdzie element Widok jest położony jako delta od współrzędnych lewego i górnego, określone przez jego układ kontenera.
  • rotation, rotationX i rotationY: te usługi sterować obrotem w 2D (usługa rotation) i w 3D wokół punktu obrotu.
  • scaleX i scaleY: te właściwości sterują skalowaniem 2D obiektu Widok wokół punktu obrotu.
  • pivotX i pivotY: te właściwości kontrolują lokalizację punktu przestawnego, wokół którego odbywają się przekształcenia obrotu i skalowania. Domyślnie okrąg znajduje się na środku obiektu.
  • x i y: to proste właściwości użytkowe opisujące ostatecznych położenia widoku w jego kontenerze, jako sumy wartości dla lewego i górnego rogu oraz przesunięcieX i przesunięcieY.
  • alpha: reprezentuje przezroczystość w wersji alfa w widoku danych. Ta wartość wynosi 1 (nieprzezroczyste). domyślnie, gdzie wartość 0 oznacza pełną przezroczystość (niewidoczną).

Aby animować właściwość obiektu View, np. jego kolor lub wartość obrotu, wystarczy należy utworzyć animator właściwości i określić właściwość widoku, która ma być ani animacji. Na przykład:

Kotlin

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)

Java

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);

Więcej informacji na temat tworzenia animacji za pomocą tagów ValueAnimator i ObjectAnimator.

Animacja za pomocą ViewpropertyAnimator

ViewPropertyAnimator umożliwia proste animowanie kilku właściwości klasy View równolegle, przy użyciu jednego bazowego Animator obiektu. Zachowuje się jak ObjectAnimator, ponieważ modyfikuje domyślnych wartości właściwości widoku, ale działa efektywniej, gdy animujesz wiele właściwości w raz. Dodatkowo, korzystając z kodu ViewPropertyAnimator, były bardziej zwięzłe i czytelne. Poniższe fragmenty kodu pokazują różnice w stosowaniu ObjectAnimator obiekty, jeden ObjectAnimator oraz ViewPropertyAnimator, gdy jednocześnie animując właściwości x i y widoku.

Wiele obiektów ObjectAnimator

Kotlin

val animX = ObjectAnimator.ofFloat(myView, "x", 50f)
val animY = ObjectAnimator.ofFloat(myView, "y", 100f)
AnimatorSet().apply {
    playTogether(animX, animY)
    start()
}

Java

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

One ObjectAnimator,

Kotlin

val pvhX = PropertyValuesHolder.ofFloat("x", 50f)
val pvhY = PropertyValuesHolder.ofFloat("y", 100f)
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start()

Java

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start();

ViewPropertyAnimator

Kotlin

myView.animate().x(50f).y(100f)

Java

myView.animate().x(50f).y(100f);

Szczegółowe informacje o aplikacji ViewPropertyAnimator znajdziesz na odpowiednich stronach dla deweloperów aplikacji na Androida blog post.

Deklarowanie animacji w pliku XML

System animacji właściwości umożliwia deklarowanie animacji właściwości za pomocą kodu XML, zamiast wykonywać w sposób zautomatyzowany. Gdy zdefiniujesz animacje w formacie XML, możesz je łatwo ponownie wykorzystać. w wielu aktywnościach i łatwiej edytować sekwencję animacji.

Aby odróżnić pliki animacji korzystające z interfejsów API nowych właściwości od tych, które korzystają z metody starszą platformę view animacji, od Androida 3.1 musisz zapisać pliki XML animacji właściwości w katalogu res/animator/.

Poniższe klasy animacji właściwości obsługują deklarację XML z atrybutami następujące tagi XML:

Żeby znaleźć atrybuty, których możesz użyć w deklaracji XML, zapoznaj się z sekcją Animacje . Poniższy przykład odtwarza 2 zestawy animacji obiektu sekwencyjnie, przy czym pierwszy zagnieżdżony zestaw odtwarza razem dwie animacje obiektów:

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

Aby uruchomić tę animację, musisz zwiększyć zasoby XML w kodzie do obiektu AnimatorSet, a następnie ustawić obiekty docelowe dla wszystkich animacji przed uruchomieniem zestawu animacji. Wywołanie setTarget() ustawia dla wszystkich użytkowników jeden obiekt docelowy dla wszystkich elementów podrzędnych obiektu AnimatorSet. Jak to zrobić:

Kotlin

(AnimatorInflater.loadAnimator(myContext, R.animator.property_animator) as AnimatorSet).apply {
    setTarget(myObject)
    start()
}

Java

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.animator.property_animator);
set.setTarget(myObject);
set.start();

ValueAnimator możesz również zadeklarować w pliku XML jako w tym przykładzie:

<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueType="floatType"
    android:valueFrom="0f"
    android:valueTo="-100f" />

Aby użyć poprzedniego elementu ValueAnimator w kodzie, musisz musi rozszerzać obiekt, dodać parametr AnimatorUpdateListener, pobrać zaktualizowaną wartość animacji i użyć jej we właściwości jednego z widoków, jak w tym kodzie:

Kotlin

(AnimatorInflater.loadAnimator(this, R.animator.animator) as ValueAnimator).apply {
    addUpdateListener { updatedAnimation ->
        textView.translationX = updatedAnimation.animatedValue as Float
    }

    start()
}

Java

ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,
        R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

xmlAnimator.start();

Informacje o składni XML służącej do definiowania właściwości animacji znajdziesz w sekcji Animacje .

Potencjalny wpływ na wydajność interfejsu

Animatory, które aktualizują interfejs, powodują dodatkowe renderowanie każdej klatki w w którym ma być uruchamiana animacja. Dlatego korzystanie z animacji wymagających dużych ilości zasobów może negatywnie wpłynąć na wydajność aplikacji.

Elementy wymagane do animowania interfejsu użytkownika są dodawane do etapu animacji w: z potokiem renderowania. Możesz się dowiedzieć, czy Twoje animacje wpływają na wydajności aplikacji, włączając Renderowanie GPU w profilu oraz monitorowania etapu animacji. Aby uzyskać więcej informacji, przeczytaj artykuł Profilowanie renderowania GPU .