Zarządzanie ruchem i animacją widżetu za pomocą Motion Layout

MotionLayout to typ układu, który pomaga zarządzać ruchem i animacją widżetu w aplikacji. MotionLayout jest podklasą ConstraintLayout i opiera się na bogatym możliwości układu graficznego. W ramach biblioteki ConstraintLayout, MotionLayout jest dostępna jako biblioteka pomocy.

MotionLayout wypełnia lukę między przejściami układu a złożonym ruchem różne funkcje, oferując połączenie różnych funkcji z animacją właściwości. platformy, TransitionManager i CoordinatorLayout.

. Rysunek 1. Podstawowe sterowanie dotykowe.

Oprócz opisu przejścia między układami w MotionLayout możesz też: ani animować właściwości układu. Dodatkowo wspiera też szybko wyszukiwane słowa przejścia. Oznacza to, że można natychmiast wyświetlić dowolny punkt przejścia tylko na podstawie pewnych warunków, np. sterowania dotykowego. MotionLayout obsługuje też klatki kluczowe, które pozwalają w pełni dostosować przejścia do Twoich potrzeb.

Funkcja MotionLayout jest w pełni deklaratywna, co oznacza, że możesz opisać dowolne przejścia w języku: nawet w formacie XML.

Uwagi dotyczące projektu

MotionLayout służy do przenoszenia i animowania elementów interfejsu oraz zmieniania ich rozmiaru, za pomocą których interakcji użytkowników, np. przycisków i pasków tytułu. Nie używaj ruchu w aplikacji jako: nieuzasadniony efekt specjalny. Pokaż użytkownikom, czym jest Twoja aplikacja co robię. Więcej informacji o projektowaniu aplikacji z ruchem ruchomym znajdziesz w Sekcja Material Design Zrozumienie ruchu.

Rozpocznij

Aby zacząć używać narzędzia MotionLayout w projekcie, wykonaj te czynności.

  1. Dodaj zależność ConstraintLayout:, aby użyć MotionLayout w projekcie, dodaj parametr ConstraintLayout 2.0 zależność od build.gradle. Jeśli używasz AndroidaX, dodaj parametr tę zależność:

    Groovy

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha14"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha14"
    }
    

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha14")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha14")
    }
    
  2. Utwórz plik MotionLayout: MotionLayout jest podklasą klasy ConstraintLayout, więc możesz przekształcić dowolną istniejące ConstraintLayout w MotionLayout przez zastępując nazwę klasy w pliku zasobów układu, jak widać w pliku następujące przykłady:

    AndroidX

    <!-- before: ConstraintLayout -->
    <androidx.constraintlayout.widget.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <androidx.constraintlayout.motion.widget.MotionLayout .../>
              

    Biblioteka pomocy

    <!-- before: ConstraintLayout -->
    <android.support.constraint.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <android.support.constraint.motion.MotionLayout .../>
              

    Oto pełny przykład pliku MotionLayout, który definiuje układ widoczny na ilustracji 1:

    AndroidX

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <androidx.constraintlayout.motion.widget.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </androidx.constraintlayout.motion.widget.MotionLayout>
            

    Biblioteka pomocy

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <android.support.constraint.motion.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </android.support.constraint.motion.MotionLayout>
            
  3. Utwórz MotionScene: w poprzednim MotionLayout przykładowy atrybut app:layoutDescription odwołuje się do scenę ruchu. Scena ruchu to plik zasobów XML. W <MotionScene> pierwiastek, scena ruchu zawiera wszystkie opisy odpowiadającego mu układu. Aby oddzielić informacje o układzie od ruchu opisy, każdy element MotionLayout odwołuje się do osobnego ruchu scena. Definicje w scenie animacji mają pierwszeństwo przed podobnymi definicje: MotionLayout.

    Oto przykładowy plik ze scenami ruchu, który opisuje podstawowy obraz poziomy ruch na ilustracji 1:

    <?xml version="1.0" encoding="utf-8"?>
    <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:motion="http://schemas.android.com/apk/res-auto">
    
        <Transition
            motion:constraintSetStart="@+id/start"
            motion:constraintSetEnd="@+id/end"
            motion:duration="1000">
            <OnSwipe
                motion:touchAnchorId="@+id/button"
                motion:touchAnchorSide="right"
                motion:dragDirection="dragRight" />
        </Transition>
    
        <ConstraintSet android:id="@+id/start">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginStart="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
        <ConstraintSet android:id="@+id/end">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginEnd="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
    </MotionScene>
        

    Uwaga:

    • <Transition> zawiera podstawową definicję ruchu.

      • motion:constraintSetStart i motion:constraintSetEnd to odwołania do między punktami końcowymi ruchu. Te punkty końcowe są zdefiniowane w sekcji <ConstraintSet> elementów później w scenie ruchu.

      • motion:duration określa liczbę milisekund który jest potrzebny do ukończenia ruchu.

    • <OnSwipe> umożliwia utworzenie sterowania dotykowego dla ruchu.

      • motion:touchAnchorId odnosi się do widoku, który użytkownik może przesuń palcem i przeciągnij.

      • motion:touchAnchorSide oznacza widok jest przeciągany z prawej strony.

      • motion:dragDirection oznacza postęp. kierunku przeciągania. Przykład: motion:dragDirection="dragRight" oznacza postęp rośnie w miarę przeciągania widoku w prawo.

    • <ConstraintSet> gdzie definiuje się różne ograniczenia opisujące ruch. W tym przykładzie jeden <ConstraintSet> jest zdefiniowany dla każdego punktu końcowego ruchu. Te punkty końcowe są wyśrodkowane w pionie za pomocą: app:layout_constraintTop_toTopOf="parent" i app:layout_constraintBottom_toBottomOf="parent" W poziomie punkty końcowe znajdują się po lewej i prawej stronie ekranu.

    Bardziej szczegółowe omówienie różnych elementów sceny ruchu , zobacz Przykłady MotionLayout.

Atrybuty interpolowane

W pliku scen ruchu elementy ConstraintSet mogą zawierać dodatkowe które są interpolowane podczas przejścia. Oprócz pozycji i granicy, następujące atrybuty są interpolowane przez funkcję MotionLayout:

  • alpha
  • visibility
  • elevation
  • rotation, rotationX, rotationY
  • translationX, translationY, translationZ
  • scaleX, scaleY

Atrybuty niestandardowe

W polu <Constraint> możesz użyć elementu <CustomAttribute>, aby określić przejście dla atrybutów, które nie są powiązane tylko z pozycją lub View .

<Constraint
    android:id="@+id/button" ...>
    <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60"/>
</Constraint>

Pole <CustomAttribute> zawiera 2 osobne atrybuty:

  • Pole motion:attributeName jest wymagane i musi pasować do obiektu z użyciem metody getter i metody ustawiania. Metoda pobierania i ustawiająca muszą pasować do konkretnego wzorca. Dla: np. backgroundColor jest obsługiwany, ponieważ widok zawiera Metody getBackgroundColor() i setBackgroundColor().
  • Drugi atrybut, który musisz podać, zależy od typu wartości. Wybierz spośród tych obsługiwanych typów:
    • motion:customColorValue za kolory
    • motion:customIntegerValue w przypadku liczb całkowitych
    • motion:customFloatValue w przypadku liczby zmiennoprzecinkowej
    • motion:customStringValue – ciągi tekstowe
    • motion:customDimension dla wymiarów
    • motion:customBoolean dla wartości logicznych

Przy określaniu atrybutu niestandardowego określ wartości punktów końcowych zarówno na początku, jak i na końcu <ConstraintSet> elementów.

Zmiana koloru tła

Kontynuując poprzedni przykład, załóżmy, że chcesz zmienić kolory widoku. jako część jego ruchu, jak widać na rysunku 2.

. Rysunek 2. W miarę przesuwania widoku kolor tła się zmienia.

Dodaj element <CustomAttribute> do każdego elementu ConstraintSet, tak jak na ilustracji ten fragment kodu:

<ConstraintSet android:id="@+id/start">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginStart="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintStart_toStartOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60" />
    </Constraint>
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginEnd="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintEnd_toEndOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#9999FF" />
    </Constraint>
</ConstraintSet>

Dodatkowe atrybuty MotionLayout

Oprócz atrybutów z poprzedniego przykładu atrybut MotionLayout ma inne atrybutami, które możesz określić:

  • app:applyMotionScene="boolean" wskazuje, czy chcesz zastosować scenę ruchu. Domyślna wartość tego atrybutu to true.
  • app:showPaths="boolean" wskazuje, czy ścieżki animacji mają być wyświetlane jako jest aktywny. Domyślna wartość tego atrybutu to false.
  • app:progress="float" pozwala wprost określić postęp przejścia. Ty może używać dowolnej wartości zmiennoprzecinkowej z zakresu 0 (początek przejścia) do 1 (koniec przejścia).
  • app:currentState="reference" umożliwia określenie konkretnego elementu ConstraintSet.
  • app:motionDebug umożliwia wyświetlanie dodatkowych informacji na temat debugowania ruchu. Możliwe wartości to "SHOW_PROGRESS", "SHOW_PATH" oraz "SHOW_ALL".

Dodatkowe materiały

Więcej informacji o funkcji MotionLayout znajdziesz w tych materiałach: