Omówienie animacji właściwości

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

System animacji obiektów to solidna platforma, która umożliwia animację niemal wszystkiego. Możesz zdefiniować animację, która zmienia dowolną właściwość obiektu w czasie, niezależnie od tego, czy obiekt jest widoczny na ekranie. Animacja właściwości zmienia wartość właściwości (pola w obiekcie) w określonym czasie. Aby coś animować, musisz określić właściwość obiektu, którą chcesz animować, np. jego położenie na ekranie, czas trwania animacji oraz wartości, między którymi chcesz ją wykonać.

System animacji właściwości umożliwia określenie tych właściwości animacji:

  • 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 się powtarzać po zakończeniu odtwarzania oraz ile razy ma się powtórzyć. Możesz też określ, czy animacja ma być odtwarzana wstecz. Ustawienie go na odwrotne odtwarzanie powoduje, że animacja jest odtwarzana najpierw do przodu, a potem do tyłu, aż do osiągnięcia liczby powtórzeń.
  • Zestawy animacji: możesz grupować animacje w logiczne zestawy, które odtwarzają się razem lub kolejno albo 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 w zależności od ogólnego obciążenia systemu i tego, 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 wyjaśnimy, jak działa animacja, na prostym przykładzie. Rysunek 1 przedstawia hipotetyczny obiekt, który jest animowany za pomocą właściwości x, która reprezentuje jego położenie poziome na ekranie. Czas trwania animacji wynosi 40 ms, a odległość do przebycia – 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. Oto przykład animacji z interpolacją liniową, czyli obiekt porusza się z niezmienną 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ę szczegółowo, jak ważne komponenty systemu animacji właściwości obliczają 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.

Parametr ValueAnimator zawiera zasadę TimeInterpolator, która 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 rysunku 2 wartość TimeInterpolator to AccelerateDecelerateInterpolator, a wartość 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 animacji. Gdy zadzwonisz pod numer start(), rozpocznie się animacja. 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ął. Upływający ułamek reprezentuje odsetek czasu, przez który trwała animacja: 0 oznacza 0%, a 1 to 100%. Na przykład na rysunku 1 ułamek czasu w miejscu t = 10 ms wynosiłby 0,25, ponieważ łączny czas to t = 40 ms.

Gdy funkcja ValueAnimator zakończy obliczanie ułamka, funkcja wywołuje aktualnie ustawioną funkcję TimeInterpolator, aby obliczyć ułamek interpolowany. Interpolowana iloraz mapuje upływający ułamek na nowy ułamek, który uwzględnia ustawioną interpolację czasu. 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 obiektów View. Jeśli chcesz animować obiekty inne niż View, musisz zaimplementować własny kod. System animacji widoku jest też ograniczony tym, że udostępnia tylko kilka aspektów obiektu View do animowania, takich jak skalowanie i obrót widoku, ale nie kolor tła.

Kolejną wadą systemu animacji widoku jest to, że modyfikował on tylko miejsce, w którym widok został narysowany, a nie sam widok. Jeśli na przykład animujesz przycisk, aby przesuwał się po ekranie, przycisk jest prawidłowo rysowany, ale rzeczywista lokalizacja, w której można go kliknąć, się nie zmienia, więc musisz zaimplementować własną logikę, aby sobie z tym poradzić.

System animacji właściwości całkowicie usuwa te ograniczenia. Możesz animować dowolną właściwość dowolnego obiektu (widoków i niewidocznych) i w ten sposób modyfikować sam obiekt. 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 Twoje wymagania lub jeśli dotychczasowy kod działa już tak, jak chcesz, nie musisz używać systemu animacji w usłudze. W niektórych sytuacjach może też być sensowne użycie obu systemów animacji.

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 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. Te podklasy rozszerzają klasę Animator:

Tabela 1. Animatorzy

Kategoria Opis
ValueAnimator Główny mechanizm ustawiania czasu animacji właściwości, który oblicza też wartości właściwości, która ma być animowana. Zawiera ona wszystkie podstawowe funkcje, które obliczają wartości animacji i zawierają szczegóły dotyczące czasu trwania każdej animacji, informacje o tym, czy animacja się powtarza, a także możliwość ustawiania typów niestandardowych do oceny. Animacja właściwości składa się z 2 części: obliczenia wartości animowanych i ustawienia tych wartości w obiekcie oraz właściwości, która jest animowana. ValueAnimator nie wykonuje drugiej części, więc musisz nasłuchiwać aktualizacji wartości obliczanych przez ValueAnimator i modyfikować obiekty, które chcesz animować, za pomocą własnej logiki. Więcej informacji znajdziesz w sekcji Animowanie za pomocą 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 Udostępnia mechanizm grupowania animacji, aby mogły one działać w zależności od siebie. Możesz ustawić odtwarzanie animacji po kolei, po kolei lub później. określonego opóźnienia. Więcej informacji znajdziesz w sekcji Koordynowanie wielu animacji za pomocą zestawów animatorów.

Weryfikatorzy informują system animacji właściwości, jak obliczyć wartości danej usłudze. Wykorzystują one dane dotyczące czasu, które są dostarczane przez klasę Animator, wartość początkową i końcową animacji oraz na podstawie tych danych obliczają animowane wartości właściwości. System animacji obiektów udostępnia te funkcje oceny:

Tabela 2. Weryfikatorzy

Klasa/interfejs Opis
IntEvaluator Domyślny tester do obliczania wartości właściwości int.
FloatEvaluator Domyślny oceniający do obliczania wartości właściwości float.
ArgbEvaluator Domyślny oceniający do obliczania wartości właściwości kolorów, które są reprezentowane jako wartości szesnastkowe.
TypeEvaluator Interfejs umożliwiający tworzenie własnych oceniaczy. 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 o pisaniu niestandardowego oceniacza znajdziesz w sekcji Korzystanie z TypeEvaluator.

Interpolator czasowy określa, jak określone wartości w animacji są obliczane jako funkcja czasu. Możesz na przykład określić, że animacje mogą pojawiać się 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 zawiera opis interpolacji zawartych w elementach 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 jest na początku i na końcu powolna, ale przyspiesza w środku.
AccelerateInterpolator Interpolator, którego szybkość zmiany 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 szybkość zmian początkowo jest duża, a potem maleje.
LinearInterpolator Interpolator, którego szybkość zmian jest stała.
OvershootInterpolator Interpolator, którego zmiana przesuwa się do przodu i przestrzeliwuje ostatnią wartość, a potem wraca.
TimeInterpolator Interfejs umożliwiający wdrożenie własnego interpolatora.

Tworzenie animacji 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 funkcja ValueAnimator zaczyna obliczać wartości animacji w zakresie od 0 do 100 przez 1000 ms, gdy uruchomiona jest 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 element ValueAnimator zaczyna obliczać wartości animacji między elementami startPropertyValueendPropertyValue, używając logiki dostarczonej przez MyTypeEvaluator przez 1000 ms, gdy wykonywana jest metoda start().

Aby używać wartości animacji, dodaj do obiektu ValueAnimator parametr AnimatorUpdateListener, jak w tym kodzie:

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

Obiekt ObjectAnimator jest podklasą obiektu ValueAnimator (omówionego w poprzedniej sekcji) i łączy mechanizm ustalania czasu oraz obliczanie wartości obiektu ValueAnimator z możliwością animowania nazwanej właściwości obiektu docelowego. Dzięki temu animacja dowolnego obiektu jest znacznie łatwiejsza, ponieważ nie musisz już implementować ValueAnimator.AnimatorUpdateListener, ponieważ animowana właściwość 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 usługi ObjectAnimator były prawidłowo aktualizowane, musisz:

  • 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ć możliwość dostępu do tej właściwości za pomocą tej metody ustawiania. 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 do klasy metodę settera, jeśli masz do tego odpowiednie 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.
    • Zamiast tego użyj 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 gettera musi mieć postać get<PropertyName>(). Jeśli na przykład nazwa właściwości to foo, musisz mieć metodę getFoo().
  • Metody getter (jeśli są potrzebne) i setter właściwości, którą animujesz, muszą działać na tym samym typie co wartości początkowa i końcowa, które podajesz 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 tego, jaką właściwość lub jaki obiekt animujesz, możesz potrzebować wywołania metody invalidate() w widoku, aby wymusić ponowne narysowanie ekranu z aktualizowanymi wartościami animacji. 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 metody właściwości w widoku, np. setAlpha()setTranslationX(), powodują nieważność widoku, więc nie musisz go unieważniać, gdy wywołujesz te metody z nowymi wartościami. Więcej informacji o słuchaczach znajdziesz w sekcji Detektory animacji.

Choreografia wielu animacji za pomocą zestawu animatorów

W wielu przypadkach chcesz odtwarzać animację w zależności od tego, kiedy rozpoczyna się lub kończy inna animacja. System Android umożliwia grupowanie animacji w jedną AnimatorSet, dzięki czemu możesz określić, czy animacje mają być uruchamiane jednocześnie, sekwencyjnie czy po określonym opóźnieniu. Obiekty AnimatorSet możesz też zagnieżdżać wewnątrz siebie.

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

Podczas trwania animacji możesz słuchać ważnych zdarzeń za pomocą opisanych poniżej obiektów nasłuchujących.

  • Animator.AnimatorListener
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate() – wywoływane przy każdej klatce animacji. Odsłuchuj to zdarzenie, aby używać wartości obliczanych przez ValueAnimator podczas animacji. 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(). Jeśli używasz ValueAnimator, musisz zaimplementować ten listener.

      W zależności od tego, jaką właściwość lub jaki obiekt animujesz, możesz potrzebować wywołania funkcji invalidate() w przypadku widoku, aby wymusić ponowne narysowanie tego obszaru ekranu z nowymi wartościami animacji. Na przykład animowanie właściwości koloru obiektu rysowanego powoduje aktualizację ekranu tylko wtedy, gdy obiekt ponownie się rysuje. Wszystkie metody właściwości w klasie View, takie jak setAlpha()setTranslationX(), powodują nieważność obiektu View, więc nie musisz anulować jego ważności, gdy wywołujesz te metody z nowymi wartościami.

Jeśli nie chcesz implementować wszystkich metod interfejsu Animator.AnimatorListener, możesz rozszerzyć klasę AnimatorListenerAdapter zamiast implementować interfejs Animator.AnimatorListener. Klasa AnimatorListenerAdapter zawiera puste implementacji metod, które można zastąpić.

Na przykład ten fragment kodu tworzy obiekt AnimatorListenerAdapter tylko do wywołania zwrotnego onAnimationEnd():

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());
}

Animowanie zmian układu obiektów ViewGroup

System animacji właściwości umożliwia animowanie zmian w obiektach ViewGroup, a także łatwe animowanie samych obiektów View.

Zmiany układu w grupie widoków możesz animować za pomocą klasy LayoutTransition. Widoki w grupie widoków mogą pojawiać się i znikać. 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 w przypadku elementów wyświetlanych 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 uruchamiana w przypadku elementów znikających z kontenera.
  • CHANGE_DISAPPEARING – flaga wskazująca animację, która działa na elementach zmieniających się z powodu zniknięcia elementu z kontenera.

Możesz zdefiniować własne animacje niestandardowe dla tych 4 typów zdarzeń, aby dostosować wygląd przejść układu, lub po prostu wskazać systemowi animacji, aby 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 tego atrybutu na wartość true powoduje automatyczne animowanie widoków dodanych lub usuniętych z grupy widoków, a także pozostałych widoków w tej grupie.

Animowanie zmian stanu widoku za pomocą klasy StateListAnimator

Klasa StateListAnimator umożliwia definiowanie animatorów, które działają, gdy zmienia się stan widoku. 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 element <selector> i podrzędne elementy <item> określone przez każdy z nich 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, gdy zmienia się stan tego przycisku, używane są animacje zdefiniowane w elementach animate_scale.xml.

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żywanie funkcji TypeEvaluator

Jeśli chcesz animować typ nieznany systemowi Android, możesz utworzyć własny evaluator, implementując interfejs 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. Interpolowana iloraz jest tym, co TypeEvaluator otrzymuje za pomocą parametru fraction, więc podczas obliczania wartości animowanych nie musisz uwzględniać interpolatora.

Używanie interpolacji

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 animatorów, który reprezentuje upływ czasu animacji. Interpolator modyfikuje ten ułamek, aby zbiegł się z typem i animację. System Android udostępnia zestaw popularnych interpolatorów, android.view.animation package. Jeśli żaden z nich nie odpowiada Twoim potrzebom, możesz wdrożyć interfejs TimeInterpolator i utworzyć własny.

Poniżej porównujemy sposób obliczania interpolowanych ułamków przez domyślny interpolator AccelerateDecelerateInterpolator i interpolator LinearInterpolator. LinearInterpolator nie ma wpływu na ułamek czasu, który upłynął. AccelerateDecelerateInterpolator przyspiesza w ramach animacji i zwalnia na jej końcu. Te metody definiują logikę tych interpolacji:

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

LinearInterpolator

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) Interpolowana cześć (przyspieszanie/zwalnianie)
0 0 0
200 .2 0,1
400 0,4 0,345
600 0,6 0,654
800 0,8 .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. W okresie od 200 do 600 ms model AccelerateDecelerateInterpolator zmienia wartości szybciej niż model LinearInterpolator, a w okresie od 600 do 1000 ms – wolniej.

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łasny interpolator, który kontroluje zachowanie animacji w interwale między czasem poprzedniej klatek kluczowej a czasem tej klatek.

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. Gdy już go masz, możesz uzyskać animatora, przekazując obiekt PropertyValuesHolder i obiekt do animowania. Jak to zrobić, pokazuje poniższy fragment kodu:

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. System animacji widoku przekształcił obiekty widoku, 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. prowadziło to do takich zachowań jak obiekt nadal znajdujący się w pierwotnej lokalizacji, mimo że został narysowany 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.
  • scaleXscaleY: te właściwości kontrolują skalowanie 2D widoku wokół punktu obrotu.
  • pivotXpivotY: te właściwości określają położenie osi obrotu, wokół której zachodzą transformacje obrotu i skalowania. Domyślnie okrąg znajduje się na środku obiektu.
  • xy: to proste właściwości pomocnicze opisujące ostateczne położenie widoku w kontenerze jako suma wartości lewej i górnej oraz wartości przesunięcia X i Y.
  • alpha: reprezentuje przezroczystość w wersji alfa w widoku danych. Domyślnie ma ona wartość 1 (nieprzezroczysta), a wartość 0 oznacza pełną przezroczystość (niewidoczna).

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 o tworzeniu animatorów znajdziesz w sekcjach poświęconych animacji za pomocą komponentów ValueAnimatorObjectAnimator.

Tworzenie animacji za pomocą ViewPropertyAnimator

Element ViewPropertyAnimator zapewnia prosty sposób na animowanie kilku właściwości obiektu View równolegle za pomocą jednego obiektu bazowego Animator. 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 kod używany do wywoływania funkcji ViewPropertyAnimator jest znacznie bardziej zwięzły i łatwiejszy do odczytania. 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 obiektu umożliwia deklarowanie animacji obiektu za pomocą kodu XML zamiast programowo. Definiując animacje w pliku XML, możesz je łatwo używać w różnych działaniach 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:

Aby znaleźć atrybuty, których możesz używać w deklaracji XML, zapoznaj się z zasobami dotyczącymi animacji. W tym przykładzie 2 zestawy animacji obiektów są odtwarzane kolejno, a pierwszy zagnieżdżony zestaw odtwarza 2 animacje obiektów razem:

<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 wczytać zasoby XML w kodzie do obiektu AnimatorSet, a potem przed uruchomieniem zestawu animacji ustawić obiekty docelowe dla wszystkich 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();

Możesz też zadeklarować ValueAnimator w pliku XML, jak 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ć w kodzie poprzedniej wartości ValueAnimator, musisz zainicjować obiekt, dodać element AnimatorUpdateListener, uzyskać zaktualizowaną wartość animacji i użyć jej we właściwości jednej z widoków, jak pokazano 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. Aby sprawdzić, czy animacje wpływają na wydajność aplikacji, włącz Profilowanie renderowania GPU i obserwuj etap animacji. Więcej informacji znajdziesz w przewodniku po profilowaniu renderowania GPU.