Ruch w zależności od fizyki jest spowodowany siłą. Siła sprężyna to jedna z tych sił, które kierują interaktywność i ruchem. Siła sprężyna ma takie właściwości: tłumienie i sztywność. W animacji opartej na sprężynie wartość i prędkość są obliczane na podstawie siły sprężysty stosowanej do każdej klatki.
Jeśli chcesz, by animacje w aplikacji były zwalniane tylko w jednym kierunku, rozważ użycie animacji przesuwu opartej na tarciu.
Cykl życia animacji sprężyn
W animacji sprężynowej klasa SpringForce
pozwala dostosować sztywność sprężyny, jej współczynnik tłumienia i jej ostateczną pozycję. Po rozpoczęciu animacji siła sprężynia aktualizuje wartość animacji i prędkość na każdej klatce. Animacja trwa, dopóki siła sprężyna nie osiągnie równowagi.
Jeśli na przykład przeciągniesz ikonę aplikacji wokół ekranu, a później ją zwolnisz, unosząc palec z ikony, ikona wróci na swoje miejsce dzięki niewidocznej, ale znanej siły.
Podobny efekt sprężyny przedstawia Rysunek 1. Znak plusa (+) w środku okręgu wskazuje siłę działania gestu dotykowego.
Utwórz animację wiosny
Ogólne czynności, które musisz wykonać, aby utworzyć animację wiosenną w Twojej aplikacji, to:
- Dodaj bibliotekę pomocy Aby używać klas animacji wiosennej, musisz dodać do projektu bibliotekę pomocniczą.
- Tworzenie animacji sprężynowe: głównym krokiem jest utworzenie instancji klasy
SpringAnimation
i ustawienie parametrów działania ruchu. - (Opcjonalnie) Zarejestruj detektory: zarejestruj detektory, które będą obserwować zmiany w cyklu życia animacji i aktualizacje wartości animacji.
Uwaga: odbiornik aktualizacji należy zarejestrować tylko wtedy, gdy potrzebna jest aktualizacja wartości animacji w przypadku poszczególnych klatek. Detektor aktualizacji uniemożliwia uruchomienie animacji w oddzielnym wątku.
- (Opcjonalnie) Usuń detektory: usuń detektory, które nie są już używane.
- (Opcjonalnie) Ustaw wartość początkową: dostosuj wartość początkową animacji.
- (Opcjonalnie) Ustaw zakres wartości: ustaw zakres wartości animacji, by ograniczyć wartości z zakresu minimalnego do maksymalnego.
- (Opcjonalnie) Ustaw prędkość początkową: ustaw prędkość początkową animacji.
- (Opcjonalnie) Ustaw właściwości sprężyny: ustaw współczynnik tłumienia i sztywność sprężyny.
- (Opcjonalnie) Utwórz niestandardową sprężynę: utwórz sprężynę niestandardową, jeśli nie chcesz używać domyślnej sprężyny lub chcesz używać jej wspólnej w całej animacji.
- Rozpocznij animację: uruchamia animację wiosny.
- (Opcjonalnie) Anuluj animację: anuluj animację, jeśli użytkownik nagle zamknie aplikację lub widok stanie się niewidoczny.
W sekcjach poniżej szczegółowo omówiono ogólne etapy tworzenia animacji wiosennej.
Dodawanie biblioteki pomocy
Aby korzystać z biblioteki pomocy opartej na fizyce, musisz dodać ją do projektu w ten sposób:
- Otwórz plik
build.gradle
modułu aplikacji. Dodaj bibliotekę pomocy do sekcji
dependencies
.Odlotowy
dependencies { def dynamicanimation_version = '1.0.0' implementation "androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version" }
Kotlin
dependencies { val dynamicanimation_version = "1.0.0" implementation("androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version") }
Aby wyświetlić bieżące wersje tej biblioteki, zapoznaj się z informacjami o animacji dynamicznej na stronie wersji.
Utwórz animację wiosny
Klasa SpringAnimation
pozwala utworzyć dla obiektu animację sprężyny. Aby utworzyć animację sprężyn, musisz utworzyć instancję klasy SpringAnimation
i podać obiekt, właściwość obiektu, którą chcesz animować, oraz opcjonalną końcową pozycję sprężyny, w której ma się zatrzymać animacja.
Uwaga: w momencie tworzenia animacji sprężyny jej końcowe położenie jest opcjonalne. Trzeba jednak go zdefiniować przed rozpoczęciem animacji.
Kotlin
val springAnim = findViewById<View>(R.id.imageView).let { img -> // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0f) }
Java
final View img = findViewById(R.id.imageView); // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. final SpringAnimation springAnim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0);
Animacja sprężynowa może animować widoki na ekranie, zmieniając ich rzeczywiste właściwości. W systemie dostępne są te widoki:
ALPHA
: reprezentuje przezroczystość widoku alfa. Domyślna wartość wynosi 1 (nieprzezroczyste), a 0 oznacza pełną przezroczystość (niewidoczną).TRANSLATION_X
,TRANSLATION_Y
iTRANSLATION_Z
: te właściwości określają, gdzie znajduje się widok jako delta od jego lewej współrzędnych, górnej współrzędnej oraz wysokości, które są ustawiane przez kontener układu.TRANSLATION_X
opisuje lewą współrzędną.TRANSLATION_Y
opisuje górną współrzędną.TRANSLATION_Z
określa głębokość widoku względem jego wysokości.
ROTATION
,ROTATION_X
iROTATION_Y
: te właściwości określają obrót w 2D (właściwośćrotation
) i 3D wokół punktu obrotu.SCROLL_X
iSCROLL_Y
: te właściwości wskazują odsunięcie strony źródła od lewej i górnej krawędzi w pikselach. Wskazuje też pozycję w postaci stopnia przewinięcia strony.SCALE_X
iSCALE_Y
: te właściwości określają skalowanie 2D widoku wokół jego punktu obrotu.X
,Y
iZ
: to podstawowe właściwości narzędziowe, które opisują końcową lokalizację widoku w jego kontenerze.X
to suma wartości po lewej stronie iTRANSLATION_X
.Y
to suma wartości najwyższego poziomu iTRANSLATION_Y
.Z
to suma wartości wysokości iTRANSLATION_Z
.
Zarejestruj detektory
Klasa DynamicAnimation
udostępnia 2 detektory: OnAnimationUpdateListener
i OnAnimationEndListener
.
Te detektory nasłuchują aktualizacji animacji, np. informacji o zmianie jej wartości lub końca animacji.
Moduł OnAnimationUpdateListener
Jeśli chcesz animować wiele widoków, by utworzyć animację łańcuchową, możesz skonfigurować OnAnimationUpdateListener
tak, by odbierał wywołanie zwrotne za każdym razem, gdy nastąpi zmiana właściwości bieżącego widoku. Wywołanie zwrotne powiadamia drugi widok, aby zaktualizował pozycję sprężyny na podstawie zmian wprowadzonych we właściwości bieżącego widoku. Aby zarejestrować odbiornik, wykonaj te czynności:
-
Wywołaj metodę
addUpdateListener()
i dołącz do animacji detektor.Uwaga: przed rozpoczęciem animacji musisz zarejestrować odbiornik aktualizacji. Detektor aktualizacji powinien być jednak zarejestrowany tylko wtedy, gdy potrzebna jest aktualizacja wartości animacji w przypadku poszczególnych klatek. Detektor aktualizacji uniemożliwia uruchomienie animacji w oddzielnym wątku.
-
Zastąp metodę
onAnimationUpdate()
, aby powiadomić element wywołujący o zmianie w bieżącym obiekcie. Poniższy przykładowy kod ilustruje ogólne użycie atrybutuOnAnimationUpdateListener
.
Kotlin
// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties val (anim1X, anim1Y) = findViewById<View>(R.id.view1).let { view1 -> SpringAnimation(view1, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y) } val (anim2X, anim2Y) = findViewById<View>(R.id.view2).let { view2 -> SpringAnimation(view2, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y) } // Registering the update listener anim1X.addUpdateListener { _, value, _ -> // Overriding the method to notify view2 about the change in the view1’s property. anim2X.animateToFinalPosition(value) } anim1Y.addUpdateListener { _, value, _ -> anim2Y.animateToFinalPosition(value) }
Java
// Creating two views to demonstrate the registration of the update listener. final View view1 = findViewById(R.id.view1); final View view2 = findViewById(R.id.view2); // Setting up a spring animation to animate the view1 and view2 translationX and translationY properties final SpringAnimation anim1X = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim1Y = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y); final SpringAnimation anim2X = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim2Y = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y); // Registering the update listener anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { // Overriding the method to notify view2 about the change in the view1’s property. @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2X.animateToFinalPosition(value); } }); anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2Y.animateToFinalPosition(value); } });
Parametr OnAnimationEndListener
OnAnimationEndListener
powiadamia o końcu animacji. Możesz skonfigurować odbiornik, aby odbierał wywołanie zwrotne, gdy animacja osiągnie równowagę lub zostanie anulowana. Aby zarejestrować odbiornik, wykonaj te czynności:
-
Wywołaj metodę
addEndListener()
i dołącz do animacji detektor. -
Zastąp metodę
onAnimationEnd()
, aby otrzymywać powiadomienia, gdy animacja osiągnie równowagę lub zostanie anulowana.
Usuń detektory
Aby przestać otrzymywać wywołania zwrotne aktualizacji animacji i wywołania zwrotne animacji, wywołaj odpowiednio metody removeUpdateListener()
i removeEndListener()
.
Ustaw wartość początkową animacji
Aby ustawić wartość początkową animacji, wywołaj metodę setStartValue()
i przekaż wartość początkową animacji. Jeśli nie ustawisz wartości początkowej, jako wartości początkowej animacja użyje bieżącej wartości właściwości obiektu.
Ustaw zakres wartości animacji
Jeśli chcesz ograniczyć wartość właściwości do określonego zakresu, możesz ustawić minimalne i maksymalne wartości animacji. Pomaga też kontrolować zakres w przypadku animowanych właściwości o wbudowanym zakresie, np. alfa (od 0 do 1).
-
Aby ustawić wartość minimalną, wywołaj metodę
setMinValue()
i przekaż minimalną wartość właściwości. -
Aby ustawić wartość maksymalną, wywołaj metodę
setMaxValue()
i przekaż maksymalną wartość właściwości.
Obie metody zwracają animację, dla której ustawiana jest wartość.
Uwaga: jeśli masz ustawioną wartość początkową i zdefiniowany zakres wartości animacji, upewnij się, że wartość początkowa mieści się w zakresie wartości minimalnym i maksymalnym.
Ustaw prędkość początkową
Prędkość początkowa określa szybkość, z jaką zmienia się właściwość animacji na początku animacji. Domyślna prędkość początkowa to zero pikseli na sekundę. Prędkość można ustawić szybkością gestów dotykowych lub ustawiając stałą wartość jako prędkość początkową. Jeśli zdecydujesz się podać stałą wartość, najlepiej określ ją w dp na sekundę, a potem przekonwertuj ją na piksele na sekundę. Określenie wartości w dp na sekundę pozwala określić prędkość niezależnie od gęstości i formatów. Więcej informacji o konwertowaniu wartości na piksele na sekundę znajdziesz w sekcji Konwertowanie dp na sekundę na piksele na sekundę.
Aby ustawić prędkość, wywołaj metodę setStartVelocity()
i przekaż ją w pikselach na sekundę. Metoda zwraca obiekt siły sprężyny, na który ustawiono prędkość.
Uwaga: użyj metody klas GestureDetector.OnGestureListener
lub VelocityTracker
do pobierania i obliczania szybkości gestów dotykowych.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000) val velocity = vt.yVelocity setStartVelocity(velocity) } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000); float velocity = vt.getYVelocity(); anim.setStartVelocity(velocity);
Konwertuję dp na sekundę na piksele na sekundę
Prędkość sprężyny musi być wyrażona w pikselach na sekundę. Jeśli jako początek prędkości wybierzesz stałą wartość, podaj wartość w dp na sekundę, a potem przekonwertuj ją na piksele na sekundę. Do konwersji użyj metody applyDimension()
z klasy TypedValue
. Zapoznaj się z tym przykładowym kodem:
Kotlin
val pixelPerSecond: Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, resources.displayMetrics)
Java
float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());
Określ właściwości sprężyny
Klasa SpringForce
określa metody pobierania i ustawiania dla poszczególnych właściwości sprężyny, takich jak współczynnik tłumienia i sztywność. Aby ustawić właściwości sprężyny, musisz pobrać obiekt sił sprężyny lub utworzyć własną siłę sprężyny, według której możesz określić te właściwości. Więcej informacji o tworzeniu niestandardowej siły sprężyny znajdziesz w sekcji Tworzenie niestandardowej siły sprężyny.
Wskazówka: korzystając z metod ustawiających, możesz utworzyć łańcuch metod, ponieważ wszystkie metody ustawiające zwracają obiekt siły sprężysty.
Współczynnik tłumienia
Współczynnik tłumienia oznacza stopniowe zmniejszenie oscylacji sprężyny. Korzystając z współczynnika tłumienia, możesz określić, jak szybko zanikają oscylacje między jednym odbiciem a drugim. Wiosnę można zwilżyć na 4 sposoby:
- Nadmiarowe tłumienie ma miejsce, gdy współczynnik tłumienia jest większy niż 1. Obiekt delikatnie wróci do pozycji spoczynkowej.
- Tłumienie krytyczne ma miejsce, gdy współczynnik tłumienia jest równy 1. Pozwala on obiektowi wrócić do pozycji spoczynkowej w najkrótszym czasie.
- Wyciszanie tłumienia występuje, gdy współczynnik tłumienia jest niższy niż 1. Pozwala on wielokrotnie przekroczyć limit obiektów, przechodząc pozycję spoczynku, a następnie stopniowo osiąga pozycję spoczynku.
- Brak tłumienia występuje, gdy współczynnik tłumienia wynosi zero. Pozwala on obiektowi oscylować w nieskończoność.
Aby dodać współczynnik tłumienia do sprężyny, wykonaj te czynności:
-
Wywołaj metodę
getSpring()
, aby pobrać sprężynę i dodać współczynnik tłumienia. -
Wywołaj metodę
setDampingRatio()
i prześlij współczynnik tłumienia, który chcesz dodać do sprężyny. Metoda zwraca obiekt siły sprężyny, dla którego ustawiono współczynnik tłumienia.Uwaga: współczynnik tłumienia musi być liczbą nieujemną. Jeśli ustawisz współczynnik tłumienia na 0, sprężyna nigdy nie dotrze do pozycji spoczynkowej. Oznacza to, że oscyluje w nieskończoność.
W systemie dostępne są takie stałe współczynniki tłumienia:
DAMPING_RATIO_HIGH_BOUNCY
DAMPING_RATIO_MEDIUM_BOUNCY
DAMPING_RATIO_LOW_BOUNCY
DAMPING_RATIO_NO_BOUNCY
Rys. 2. Wysokie odrzucenie
Rys. 3. Średnie odbicie
Rys. 4. Niskie odrzucenie
Rys. 5. Brak odrzuceń
Domyślny współczynnik tłumienia ustawiony jest na DAMPING_RATIO_MEDIUM_BOUNCY
.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Setting the damping ratio to create a low bouncing effect. spring.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Setting the damping ratio to create a low bouncing effect. anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY); …
Sztywność
Sztywność określa stałą sprężynową, która mierzy jej siłę. Sztywna sprężyna działa z większą siłą na przymocowany obiekt, gdy sprężyna nie jest w pozycji spoczynkowej. Aby dodać sztywność sprężyny, wykonaj te czynności:
-
Wywołaj metodę
getSpring()
, aby pobrać sprężynę i dodać sztywność. -
Wywołaj metodę
setStiffness()
i przekaż wartość sztywności, którą chcesz dodać do sprężyny. Metoda zwraca obiekt siły sprężyny, dla której ustawiono sztywność.Uwaga: sztywność musi być liczbą dodatnią.
W układzie dostępne są takie stałe sztywność:
Rysunek 6. Wysoka sztywność
Rysunek 7. Średnia sztywność
Rysunek 8. Niska sztywność
Rysunek 9. Bardzo niska sztywność
Domyślna sztywność to STIFFNESS_MEDIUM
.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Setting the spring with a low stiffness. spring.stiffness = SpringForce.STIFFNESS_LOW … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Setting the spring with a low stiffness. anim.getSpring().setStiffness(SpringForce.STIFFNESS_LOW); …
Utwórz niestandardową siłę sprężyny
Zamiast używać domyślnej siły sprężyny, możesz utworzyć własną siłę sprężyny. Niestandardowa siła sprężynowa pozwala współdzielić tę samą instancję siły sprężystości w wielu animacjach sprężyny. Po utworzeniu siły sprężyny możesz ustawić takie właściwości jak współczynnik tłumienia i sztywność.
-
Utwórz obiekt
SpringForce
.SpringForce force = new SpringForce();
-
Przypisz właściwości, wywołując odpowiednie metody. Możesz też utworzyć łańcuch metod.
force.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY).setStiffness(STIFFNESS_LOW);
-
Wywołaj metodę
setSpring()
, aby ustawić sprężynę na animację.setSpring(force);
Rozpocznij animację
Animację wiosenną możesz rozpocząć na 2 sposoby: wywołując start()
lub wywołując metodę animateToFinalPosition()
. Obie metody muszą być wywoływane w wątku głównym.
Metoda animateToFinalPosition()
wykonuje 2 zadania:
- Określa końcowe położenie sprężyny.
- Uruchamia animację, jeśli jeszcze się nie rozpoczęła.
Ponieważ metoda aktualizuje ostatnią pozycję sprężyny i w razie potrzeby uruchamia animację, możesz ją wywołać w dowolnym momencie, aby zmienić przebieg animacji. Na przykład w animacji sprężyny łańcuchowej animacja jednego widoku zależy od innego. Do takiej animacji lepiej użyć metody animateToFinalPosition()
. Dzięki tej metodzie w animacji sprężyny łańcuchowej nie musisz martwić się, czy animacja, którą chcesz zaktualizować jako następną, jest obecnie uruchomiona.
Rysunek 10 przedstawia animację sprężyny łańcuchowej, w której animacja jednego widoku zależy od innego.
Aby użyć metody animateToFinalPosition()
, wywołaj metodę animateToFinalPosition()
i przekaż resztę sprężyny. Możesz też ustawić spoczynkową pozycję sprężyny, wywołując metodę setFinalPosition()
.
Metoda start()
nie ustawia od razu wartości właściwości na wartość początkową. Wartość właściwości zmienia się przy każdym pulsie animacji, który ma miejsce przed przejściem przez rysowanie.
W efekcie zmiany są odzwierciedlane w następnej ramce, tak jakby wartości były ustawiane natychmiast.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Starting the animation start() … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Starting the animation anim.start(); …
Anuluj animację
Możesz anulować lub przejść do końca animacji. Idealną sytuacją, w której trzeba anulować lub przejść do jej końca, jest sytuacja, w której interakcja użytkownika wymaga natychmiastowego zakończenia animacji. Najczęściej dzieje się tak, gdy użytkownik nagle zamknie aplikację lub widok staje się niewidoczny.
Istnieją 2 metody zakończenia animacji.
Metoda cancel()
kończy animację w miejscu, w którym się znajduje. Metoda skipToEnd()
pomija animację do wartości końcowej, a potem ją kończy.
Przed zakończeniem animacji musisz najpierw sprawdzić stan sprężyny. Jeśli stan jest niewyciszony, animacja nie osiągnie pozycji spoczynku.
Aby sprawdzić stan sprężyny, wywołaj metodę canSkipToEnd()
. Jeśli sprężyna jest tłumiona, metoda zwraca true
, w przeciwnym razie false
.
Gdy poznasz stan sprężyny, możesz zakończyć animację, korzystając z metody skipToEnd()
lub cancel()
. Metoda cancel()
musi być wywoływana tylko w wątku głównym.
Uwaga: ogólnie metoda skipToEnd()
powoduje wizualny skok.