Tworzenie niestandardowej animacji przejścia

Wypróbuj Compose
Jetpack Compose to zalecany zestaw narzędzi do tworzenia interfejsu na Androidzie. Dowiedz się, jak dodawać animacje w Compose.

Przejście niestandardowe umożliwia utworzenie animacji, która nie jest dostępna w żadnej z wbudowanych klas przejść. Możesz na przykład zdefiniować przejście niestandardowe, które zmienia kolor pierwszego planu tekstu i pól wejściowych na szary, aby wskazać, że pola są wyłączone na nowym ekranie. Ten typ zmiany pomaga użytkownikom zobaczyć wyłączone pola.

Przejście niestandardowe, podobnie jak jeden z wbudowanych typów przejść, stosuje animacje do widoków podrzędnych zarówno sceny początkowej, jak i końcowej. W przeciwieństwie jednak do wbudowanych typów przejść musisz podać kod, który przechwytuje wartości właściwości i generuje animacje. Możesz też zdefiniować podzbiór widoków docelowych dla animacji.

Z tej strony dowiesz się, jak przechwytywać wartości właściwości i generować animacje, aby tworzyć przejścia niestandardowe.

Rozszerzanie klasy Transition

Aby utworzyć przejście niestandardowe, dodaj do projektu klasę, która rozszerza klasę Transition, i zastąp funkcje pokazane w tym fragmencie kodu:

Kotlin

class CustomTransition : Transition() {

    override fun captureStartValues(transitionValues: TransitionValues) {}

    override fun captureEndValues(transitionValues: TransitionValues) {}

    override fun createAnimator(
        sceneRoot: ViewGroup,
        startValues: TransitionValues?,
        endValues: TransitionValues?
    ): Animator? {}

}

Java

public class CustomTransition extends Transition {

    @Override
    public void captureStartValues(TransitionValues values) {}

    @Override
    public void captureEndValues(TransitionValues values) {}

    @Override
    public Animator createAnimator(ViewGroup sceneRoot,
                                   TransitionValues startValues,
                                   TransitionValues endValues) {}
}

W kolejnych sekcjach dowiesz się, jak zastępować te funkcje.

Przechwytywanie wartości właściwości widoku

Animacje przejść korzystają z systemu animacji właściwości opisanego w artykule Omówienie animacji właściwości. Animacje właściwości zmieniają właściwość widoku od wartości początkowej do wartości końcowej w określonym czasie, dlatego framework musi mieć zarówno wartość początkową, jak i końcową właściwości, aby utworzyć animację.

Animacja właściwości zwykle potrzebuje jednak tylko niewielkiego podzbioru wszystkich wartości właściwości widoku. Na przykład animacja koloru potrzebuje wartości właściwości koloru, a animacja ruchu – wartości właściwości pozycji. Ponieważ wartości właściwości potrzebne do animacji są specyficzne dla przejścia, framework przejść nie udostępnia wszystkich wartości właściwości przejścia. Zamiast tego framework wywołuje funkcje wywołania zwrotnego, które umożliwiają przejście do przechwytywania tylko tych wartości właściwości, których potrzebuje, i przechowywania ich w frameworku.

Przechwytywanie wartości początkowych

Aby przekazać do frameworka wartości początkowe widoku, zaimplementuj funkcję captureStartValues(transitionValues). Framework wywołuje tę funkcję dla każdego widoku w scenie początkowej. Argumentem funkcji jest obiekt TransitionValues, który zawiera odwołanie do widoku i instancję Map, w której możesz przechowywać wartości widoku. W implementacji pobierz te wartości właściwości i przekaż je z powrotem do platformy, przechowując je w mapie.

Aby klucz wartości właściwości nie powodował konfliktu z innymi kluczami TransitionValues, użyj tego schematu nazewnictwa:

package_name:transition_name:property_name

Ten fragment kodu pokazuje implementację funkcji captureStartValues():

Kotlin

class CustomTransition : Transition() {

    // Define a key for storing a property value in
    // TransitionValues.values with the syntax
    // package_name:transition_class:property_name to avoid collisions
    private val PROPNAME_BACKGROUND = "com.example.android.customtransition:CustomTransition:background"

    override fun captureStartValues(transitionValues: TransitionValues) {
        // Call the convenience method captureValues
        captureValues(transitionValues)
    }

    // For the view in transitionValues.view, get the values you
    // want and put them in transitionValues.values
    private fun captureValues(transitionValues: TransitionValues) {
        // Get a reference to the view
        val view = transitionValues.view
        // Store its background property in the values map
        transitionValues.values[PROPNAME_BACKGROUND] = view.background
    }

    ...

}

Java

public class CustomTransition extends Transition {

    // Define a key for storing a property value in
    // TransitionValues.values with the syntax
    // package_name:transition_class:property_name to avoid collisions
    private static final String PROPNAME_BACKGROUND =
            "com.example.android.customtransition:CustomTransition:background";

    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        // Call the convenience method captureValues
        captureValues(transitionValues);
    }


    // For the view in transitionValues.view, get the values you
    // want and put them in transitionValues.values
    private void captureValues(TransitionValues transitionValues) {
        // Get a reference to the view
        View view = transitionValues.view;
        // Store its background property in the values map
        transitionValues.values.put(PROPNAME_BACKGROUND, view.getBackground());
    }
    ...
}

Przechwytywanie wartości końcowych

Framework wywołuje funkcję captureEndValues(TransitionValues) raz dla każdego widoku docelowego w scenie końcowej. Pod każdym innym względem funkcja captureEndValues() działa tak samo jak captureStartValues().

Ten fragment kodu pokazuje implementację funkcji captureEndValues():

Kotlin

override fun captureEndValues(transitionValues: TransitionValues) {
    captureValues(transitionValues)
}

Java

@Override
public void captureEndValues(TransitionValues transitionValues) {
    captureValues(transitionValues);
}

W tym przykładzie zarówno funkcje captureStartValues() i captureEndValues() wywołują funkcję captureValues() w celu pobrania i zapisania wartości. Właściwość widoku, którą pobiera funkcja captureValues(), jest taka sama, ale ma różne wartości w scenie początkowej i końcowej. Framework utrzymuje oddzielne mapy dla stanu początkowego i końcowego widoku.

Tworzenie niestandardowego animatora

Aby animować zmiany w widoku między jego stanem w scenie początkowej a stanem w scenie końcowej, podaj animatora, zastępując funkcję createAnimator(). Gdy framework wywołuje tę funkcję, przekazuje widok główny sceny i obiekty TransitionValues, które zawierają przechwycone wartości początkowe i końcowe.

Liczba wywołań funkcji createAnimator() przez framework zależy od zmian, które zachodzą między sceną początkową a końcową.

Rozważ na przykład animację zanikania lub pojawiania się zaimplementowaną jako przejście niestandardowe. Jeśli scena początkowa ma 5 celów, z których 2 są usuwane ze sceny końcowej, a scena końcowa ma 3 cele ze sceny początkowej oraz nowy cel, framework wywołuje funkcję createAnimator() 6 razy. 3 wywołania animują zanikanie i pojawianie się celów, które pozostają w obu obiektach sceny. 2 kolejne wywołania animują zanikanie celów usuniętych ze sceny końcowej. 1 wywołanie animuje pojawianie się nowego celu w scenie końcowej.

W przypadku widoków docelowych, które istnieją zarówno w scenie początkowej, jak i końcowej, framework udostępnia obiekt TransitionValues dla argumentów startValues i endValues. W przypadku widoków docelowych, które istnieją tylko w scenie początkowej lub końcowej, framework udostępnia obiekt TransitionValues dla odpowiedniego argumentu, a dla drugiego argumentu – wartość null.

Aby zaimplementować funkcję createAnimator(ViewGroup, TransitionValues, TransitionValues) podczas tworzenia przejścia niestandardowego, użyj przechwyconych wartości właściwości widoku, aby utworzyć obiekt Animator i zwróć go do frameworka. Przykładową implementację znajdziesz w klasie ChangeColor w przykładzie CustomTransition. Więcej informacji o animatorach właściwości znajdziesz w artykule Animacja właściwości.

Stosowanie przejścia niestandardowego

Przejścia niestandardowe działają tak samo jak przejścia wbudowane. Przejście niestandardowe możesz zastosować za pomocą menedżera przejść, jak opisano w artykule Stosowanie przejścia.