Tworzenie niestandardowej animacji przejścia

Niestandardowe przejście pozwala utworzyć animację, która jest niedostępna w żadnej z wbudowanych klas przejścia. Możesz np. zdefiniować niestandardowe przejście, które zmieni kolor pierwszego planu tekstów i pól do wprowadzania danych na szary, by wskazać, że na nowym ekranie pola są wyłączone. Dzięki tej zmianie użytkownicy będą mogli zobaczyć wyłączone pola.

Niestandardowe przejście, np. jeden z wbudowanych typów przejść, powoduje zastosowanie animacji do widoków podrzędnych zarówno sceny początkowej, jak i końcowej. Jednak w odróżnieniu od wbudowanych typów przejść musisz dostarczyć kod, który przechwytuje wartości właściwości i generuje animacje. Możesz też zdefiniować podzbiór widoków docelowych dla animacji.

Na tej stronie dowiesz się, jak rejestrować wartości właściwości i generować animacje, aby tworzyć niestandardowe przejścia.

Rozszerzanie zajęć

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

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 sekcjach poniżej dowiesz się, jak zastępować te funkcje.

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

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 określonym przedziale czasu wartość początkową na wartość końcową. Platforma musi mieć zarówno wartość początkową, jak i końcową właściwości, aby utworzyć animację.

W przypadku animacji właściwości potrzebny jest jednak zazwyczaj tylko niewielki podzbiór wszystkich wartości właściwości widoku. Na przykład animacja koloru wymaga wartości właściwości koloru, a animacja ruchu – wartości właściwości pozycji. Wartości właściwości potrzebne animacji są związane z konkretnym przejściem, więc platforma przejść nie podaje każdej wartości właściwości przejścia. Zamiast tego platforma wywołuje funkcje wywołań zwrotnych, które umożliwiają przechwycenie tylko potrzebnych wartości właściwości i zapisanie ich w platformie.

Przechwytywanie wartości początkowych

Aby przekazać do platformy wartości początkowego widoku, zaimplementuj funkcję captureStartValues(transitionValues). Platforma wywołuje tę funkcję w przypadku każdego widoku w scenie początkowej. Argumentem funkcji jest obiekt TransitionValues zawierający odniesienie do widoku i wystąpienie Map, w którym możesz przechowywać potrzebne wartości widoku. W swojej implementacji pobierz wartości właściwości i przekaż je z powrotem do platformy, zapisując je na mapie.

Aby upewnić się, że klucz wartości właściwości nie koliduje z innymi kluczami TransitionValues, użyj tego schematu nazewnictwa:

package_name:transition_name:property_name

Ten fragment kodu zawiera 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());
    }
    ...
}

Przechwyć wartości końcowe

Platforma wywołuje funkcję captureEndValues(TransitionValues) raz przy każdym wyświetleniu docelowym w scenie końcowej. We wszystkich pozostałych przypadkach captureEndValues() działa tak samo jak captureStartValues().

Ten fragment kodu zawiera 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(), jak i captureEndValues() wywołują metodę captureValues() w celu pobrania i przechowywania wartości. Właściwość widoku pobierana przez captureValues() jest taka sama, ale ma różne wartości w scenie początkowej i końcowej. Platforma tworzy oddzielne mapy stanu początkowego i końcowego widoku.

Tworzenie niestandardowych animacji

Aby animować zmiany w widoku między stanem w scenie początkowej a jego stanem w scenie końcowej, użyj animatora, zastępując funkcję createAnimator(). Gdy platforma wywołuje tę funkcję, przekazuje ją do widoku głównego sceny i do obiektów TransitionValues zawierających przechwycone wartości początkowe i końcowe.

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

Rozważmy np. animację z efektem rozjaśniania lub rozjaśniania jako niestandardowe przejście. Jeśli scena początkowa ma pięć celów, z których dwa są usuwane ze sceny końcowej, a scena końcowa zawiera trzy cele ze sceny początkowej i nowy cel, platforma wywołuje createAnimator() sześć razy. Trzy z nich animują zanikanie i rozjaśnianie celów, które pozostają w obu obiektach sceny. Dwa kolejne wywołania animują zanikanie celów usuniętych z ostatniej sceny. Jedno wywołanie animuje pojawienie się nowego celu w końcowej scenie.

W przypadku widoków docelowych, które występują zarówno w scenie początkowej, jak i końcowej, platforma udostępnia obiekt TransitionValues dla argumentów startValues i endValues. W przypadku widoków docelowych, które istnieją tylko na scenie początkowej lub końcowej, platforma udostępnia obiekt TransitionValues dla odpowiedniego argumentu i obiekt null dla drugiego argumentu.

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

Stosowanie niestandardowego przejścia

Przejścia niestandardowe działają tak samo jak przejścia wbudowane. Przejście niestandardowe możesz zastosować za pomocą menedżera przenoszenia zgodnie z opisem w sekcji Stosowanie przejścia.