Tworzenie niestandardowej animacji przejścia

Wypróbuj tworzenie wiadomości
Jetpack Compose to zalecany zestaw narzędzi interfejsu na Androida. Dowiedz się, jak dodawać animacje w edytorze.

Przejście niestandardowe umożliwia tworzenie animacji, która nie jest dostępna w żadnej z wbudowanych klas przejść. Możesz na przykład zdefiniować niestandardowe przejście, które powoduje przyciemnienie koloru pierwszego planu tekstu i pol wejściowych, aby wskazać, że pola są wyłączone na nowym ekranie. Dzięki temu użytkownicy będą mogli zobaczyć wyłączone pola.

Przejście niestandardowe, takie jak jeden z wbudowanych typów przejść, stosuje animacje do podrzędnych widoków zarówno początkowej, jak i końcowej sceny. W przeciwieństwie do wbudowanych typów przejść musisz jednak podać kod, który rejestruje 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.

Rozszerzenie klasy Transition

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

KotlinJava
class CustomTransition : Transition() {

    override fun captureStartValues(transitionValues: TransitionValues) {}

    override fun captureEndValues(transitionValues: TransitionValues) {}

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

}
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 poniższych sekcjach znajdziesz informacje o tym, jak zastąpić te funkcje.

Przechwyć wartości właściwości widoku

Animacje przejścia korzystają z systemu animacji właściwości opisanego w artykule Omówienie animacji właściwości. Animacje właściwości zmieniają wartość początkową właściwości widoku na wartość końcową w określonym przedziale czasu, więc framework musi mieć zarówno wartość początkową, jak i końcową właściwości, aby móc utworzyć animację.

Jednak animacja właściwości wymaga zwykle tylko niewielkiej podgrupy 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 do animacji są specyficzne dla przejścia, dlatego framework nie udostępnia wszystkich wartości właściwości. Zamiast tego wywołuje funkcje wywołania zwrotnego, które umożliwiają przejście do rejestrowania tylko tych wartości właściwości, których potrzebuje framework, i przechowywanie ich w ramach frameworka.

Przechwyć wartości początkowe

Aby przekazać wartości początkowego widoku do frameworku, zastosuj funkcję captureStartValues(transitionValues). Framework wywołuje tę funkcję dla każdego widoku w scenie początkowej. Argument funkcji to obiekt TransitionValues zawierający odwołanie do widoku i wyjątek Map, w którym można przechowywać wybrane wartości widoku. W swojej implementacji pobieraj te wartości właściwości i przekazuj je z powrotem do frameworku, przechowując je na mapie.

Aby mieć pewność, ż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 pokazuje implementację funkcji captureStartValues():

KotlinJava
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
    }

    ...

}
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 docelowego widoku w scenie końcowej. W pozostałych aspektach captureEndValues() działa tak samo jak captureStartValues().

Ten fragment kodu pokazuje implementację funkcji captureEndValues():

KotlinJava
override fun captureEndValues(transitionValues: TransitionValues) {
    captureValues(transitionValues)
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
    captureValues(transitionValues);
}

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

Tworzenie niestandardowego animatora

Aby animować zmiany widoku między stanem w scenie początkowej a stanem w scenie końcowej, podaj animatora, zastępując funkcję createAnimator(). Gdy wywołuje tę funkcję, przekazuje widok sceny skojarzonej z obiektem TransitionValues, który zawiera zarejestrowane wartości początkowe i końcowe.

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

Możesz na przykład zastosować animację znikania lub pojawiania się jako przejście niestandardowe. Jeśli scena początkowa zawiera 5 celów, z których 2 są usunięte ze sceny końcowej, a scena końcowa zawiera 3 cele ze sceny początkowej oraz nowy cel, framework wywołuje funkcję createAnimator() 6 razy. Trzy z tych wywołań animują zniknięcie i pojawianie się obiektów docelowych, które pozostają w obu scenach. Kolejne 2 wywołania animują znikanie celów usuniętych ze sceny końcowej. Jedna z nich animuje stopniowe pojawianie się nowego celu w scenie końcowej.

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

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

Stosowanie przejścia niestandardowego

Niestandardowe przejścia działają tak samo jak wbudowane przejścia. Możesz zastosować niestandardową zmianę za pomocą menedżera zmian zgodnie z opisem w artykule Stosowanie przejścia.