MotionLayout – tworzymy efektowne animacje

okładka-motion-layout

Mimo, że MotionLayout nie został jeszcze wydany w stabilnej wersji (obecnie beta4), to wielu programistów zaczęło już z nim eksperymentować. Sam należę do tej grupy i muszę przyznać, że możliwości tego narzędzia są imponujące.

W tym wpisie zostaną przedstawione podstawowe zagadnienia związane z MotionLayout pozwalające na swobodne korzystanie z tego narzędzia. Poniżej znajdziesz przykłady animacji jakie będą tworzone w ramach tego wpisu.

Jeśli ten temat Cię zaciekawi, to zachęcam do przejrzenia serii Introduction to MotionLayout na Medium, gdzie znajdziesz bardziej szczegółowe przykłady.

Property Animator

Zanim zaczniesz korzystać z MotionLayout spróbuj użyć PropertyAnimator. Google CodeLabs w pierwszej kolejności zachęca do nauki animatorów pojedynczych właściwości elementów widoku, z których później można budować bardziej skomplikowane przejścia. Takie podejście gwarantuje łatwiejszą pracę z MotionLayout ze względu na sporą analogię. W nim także określamy konkretnie jakie właściwości mają być zmieniane oraz w jaki sposób ma się to odbywać.

Powyższe przekształcenie można uzyskać wywołując jedną metodę.

Zalety i wady MotionLayout

Łatwy sposób uzyskania efektu z powyższego przykładu daje złudną pokusę, że wszystkie inne rzeczy będą takie proste. Co w przypadku kiedy chcemy animować kartę przeciągając palcem po innym elemencie lub w zależności od warunków zmieniać dane przejście? Wizja wielu animatorów i listenerów nie jest już taka obiecująca.

Wypunktujmy więc plusy tego rozwiązania:

  • Reagowanie na przeciąganie i kliknięcia.
  • Konkretna scena zamknięta w xml’u.
  • Podgląd początku i końca (stan początkowy, przejściowy i końcowy jest odwzorowywany w edytorze widoku).
  • Dynamiczna zmiana scen z poziomu kodu.
  • Łatwe dodawanie interpolatorów.
  • Dodawanie stanów pomiędzy początkiem i końcem (KeyFrameSet).

Oczywiście liczba przydatnych opcji oraz atrybutów z czasem będzie rosła. Przypominam, że MotionLayout jest wciąż w wersji testowej.

Oczywiście nie brakuje też minusów:

  • Konieczność utrzymania minimum dwóch plików xml.
  • Każdy błąd w scenie nie odświeża poprawnie głównego widoku. Brak jeszcze dobrego powiadomienia programisty co jest nie tak.
  • Naprzemienne używanie przedrostka android i motion do różnych atrybutów jest mylące.
  • Każdy komponent musi posiadać identyfikator.
  • Wymuszanie budowy widoku w ConstraintLayout.

Konfiguracja i opis komponentów

Aby zacząć korzystać z MotionLayout trzeba zaimportować ConstraintLayout w wersji 2.0.0. Dodatkowo dla walorów estetycznych można dodać bibliotekę MaterialComponents.

Animację budujemy z czterech podstawowych komponentów:

  • MotionScene – Główny layout dla danej sceny. W nim definiujemy wszystkie potrzebne elementy.
  • ConstraintSet – Określa na jakie komponenty będzie oddziaływać MotionLayout. Aby doszło do przejścia potrzebny jest minimum układ początkowy i końcowy.
  • Constraint – Określa parametry komponentów np. alpha, margin itp.
  • Transition – Opisuje zachowanie przejścia np. duration, interpolation i czy wyzwalaczem jest kliknięcie czy przeciągnięcie. Na ten moment nie najlepiej działa korzystanie z wielu Transition.

Ten układ zapisujemy pod nazwą naszej sceny do folderu res/xml/ z rozszerzeniem .xml.

Aby sprawnie podglądać zachowanie sceny w naszym układzie warto znać parametry:

  • app:applyMotionScene="boolean" – czy scena ma być zaaplikowana.
  • app:currentState=”reference” – pokazuje w layoucie wcześniej zdefiniowany stan np. początek lub koniec.
  • app:layoutDescription=”reference” – definiuje stworzoną scenę.
  • app:motionProgress=”float” – stan sceny w danym punkcie. Przyjmuje wartości od 0 do 1.
  • app:showPaths=”boolean” – pokazuje ścieżki ruchu w celach testowych.

Przejście FloatingActionButton w CardView

Layout został przygotowany do zaprezentowania animacji przejścia do pseudo BottonSheetDialog po kliknięciu w FloatingActionButton. Tak na prawdę rozwijanym z dołu elementem będzie MaterialCardView.

Scena prezentuje się następująco:

W clickAction została ustawiona wartość transitionToEnd, co gwarantuje tylko rozwinięcie, a sama karta nie zwinie się przy ponownym kliknięciu. Podstawowe parametry jak elevation, alpha czy visibility (z tym trzeba uważać, bywa przydatna flaga visibilityMode) mogą być określone bezpośrednio w sekcji Constraint. Dla specyficznych atrybutów widoku korzystamy z CustomAttribute i dostępnych parametrów. Na koniec warto zauważyć jeszcze, że Constraint dla widoku poprzedzamy słówkiem motion, a nie app.

Efekt po tych działaniach został zaprezentowany poniżej.

Nasłuchiwanie animacji z poziomu kodu

Jeżeli na bieżąco uważnie śledzisz kod, to czegoś powinno Ci tutaj brakować. Brakuje EditText, który powinien znajdować się na górze rozwiniętej karty. To dobry moment, żeby podkreślić coś ważnego:

MotionLayout nie działa dla zagnieżdżonych widoków!

Oznacza to, że aby animować pozostałe komponenty musimy dowiedzieć się w jakim stanie znajduje się nasza scena. Z pomocą przychodzi MotionLayout.TransitionListener.

Na potrzeby nasłuchiwania zmiany progresu, interfejs MotionLayout.TransitionListener został opakowany w sposób zaprezentowany powyżej. W MainActivity wystarczy tylko dodać taki fragment kodu:

Tą zmianą osiągnęliśmy efekt pojawiającego się pola tekstowego i chowającej się strzałki.

Reagowanie na przesunięcie listy

Czym byłoby dynamiczne dodawanie elementów bez umieszczania ich w liście? W naszym przykładzie powinniśmy ukryć dużą kartę kiedy użytkownik zaczyna przesuwać listę. Jak już wcześniej wspomniałem, na razie niezbyt dobrze MotionLayout radzi sobie z wieloma typami tranzycji. Jest to dobry pretekst aby ręcznie sprawdzić przewijanie listy.

Jak widać animowanie do początku to po prostu transitionToStart(). Dodatkowo czyścimy wtedy pole tekstowe. Dodajmy jeszcze animację rozwijania karty wywoływaną kliknięciem na element. Jest to równie prosta operacja.

A tak będzie się prezentował nasz ekran po wprowadzonych zmianach:

Za mało animacji… Dodajmy Lottie!

Lottie to bardzo popularna biblioteka od Airbnb do renderowania animacji After Effects. Dodajmy ją do naszego projektu.

Do głównego widoku dodam własny Toolbar zawierający kontrolkę LottieAnimationView.

Dodatkowo z oficjalnej strony została pobrana i zaimportowana animacja ołówka.

Teraz wystarczy połączyć te wszystkie części w całość, powiadomić Lottie o progresie i Voilla!

Dynamiczne podmienianie sceny

W jednym z pierwszych akapitów zostało wyszczególnione, że możemy dynamicznie zmieniać scenę. Daje to ogromne możliwości zmiany układów, animowania tych samych widoków na wiele sposobów. Na potrzeby demonstracji do toolbara został dodany prosty switch, który podmieni dużą kartę na końcu sceny na małą. Teraz trzeba stworzyć wariacje. Ja skopiowałem poprzednią scenę i zmieniłem tylko niektóre parametry w stanie końcowym. Początek zostaje bez zmian.

Poprzednią scenę nazwałem expandable_bottom_sheet_big.xml, a nową expandable_bottom_sheet_small.xml. W kodzie tylko trzeba obsłużyć przeładowanie sceny na kliknięcie switcha.

Na koniec tylko dodam, że warto po czasie zacząć używać flagi deriveConstraintsFrom="id", bo dzięki niej możemy kopiować powtarzający się ConstraintSet.

Podsumowanie

MotionLayout już w obecnej wersji wydaje się być potężnym narzędziem i dawno nie miałem takiej frajdy z animowania widoków w Androidzie. Aktualnie Google zaleca, żeby używać go tylko do animowania widoku reagującego na akcje użytkownika. Zgadzam się z tym podejściem bo, MotionLayout potrafi być momentami uciążliwy przy przebudowie lub rozbudowie widoku. Występują też pewne zawiłości związane z widocznością pojedynczych elementów, którą chcemy zmieniać z poziomu kodu, a jest ona już zdefiniowana w scenie.

Źródła

Link do repozytorium:
https://github.com/tmaxxdd/MotionLayoutAnimatedBottomSheet

Tomasz Kądziołka
Tomasz Kądziołka

Jestem programistą Android, który wierzy, że najlepszą formą doskonalenia się jest edukowanie innych. To podejście zaowocowało różnorodnymi wpisami na blogu oraz kilkoma kursami. W pracy jestem pasjonatem języka Kotlin, za pomocą którego dążę do maksymalnej czytelności kodu, a prywatnie zapalonym biegaczem i miłośnikiem piwa.

.

1 myśl na “MotionLayout – tworzymy efektowne animacje”

Pozostaw odpowiedź Oskar Anuluj pisanie odpowiedzi

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *