Mithilfe von Animationen zwischen Fragmenten wechseln

Die Fragment API bietet zwei Möglichkeiten, Bewegungseffekte und Transformationen zu verwenden um Fragmente während der Navigation visuell zu verbinden. Eine davon ist die Animation Framework, das sowohl Animation und Animator Die Das andere ist das Framework für die Umstellung, das Folgendes umfasst: von gemeinsam genutzten Elementen.

Sie können benutzerdefinierte Effekte für das Ein- und Ausblenden von Fragmenten sowie für Übergänge gemeinsam genutzter Elemente zwischen Fragmenten.

  • Mit dem Eingabe-Effekt wird festgelegt, wie ein Fragment auf dem Bildschirm erscheint. Beispiel: können Sie einen Effekt erzeugen, um das Fragment vom Rand des wenn Sie dorthin navigieren.
  • Ein Exit-Effekt bestimmt, wie ein Fragment den Bildschirm verlässt. Beispiel: können Sie einen Effekt erzeugen, um das Fragment beim Verlassen der Seite auszublenden. daraus entfernt werden.
  • Durch einen Übergang mit gemeinsam genutzten Elementen wird festgelegt, wie eine Ansicht zwischen zwischen zwei Fragmenten. Beispiel: Ein angezeigtes Bild in einer ImageView in Fragment A geht einmal B zu Fragment B über. sichtbar wird.

Animationen festlegen

Zunächst müssen Sie Animationen für Ihre Ein- und Exit-Effekte erstellen. beim Navigieren zu einem neuen Fragment. Sie können Animationen als Tween-Animationsressourcen. Mit diesen Ressourcen können Sie definieren, wie Fragmente sich während der Animation bewegen. Vielleicht möchten Sie das aktuelle Fragment und das neue Fragment, das sich vom rechten Bildschirmrand öffnet, wie in Abbildung 1 dargestellt.

<ph type="x-smartling-placeholder">
</ph> Animationen starten und beenden. Das aktuelle Fragment wird ausgeblendet, während
            das nächste Fragment von rechts ein.
Abbildung 1: Animationen starten und beenden. Das aktuelle Fragment wird ausgeblendet, während das nächste Fragment von rechts eingeblendet wird.

Diese Animationen können im Verzeichnis res/anim definiert werden:

<!-- res/anim/fade_out.xml -->
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_shortAnimTime"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:fromAlpha="1"
    android:toAlpha="0" />
<!-- res/anim/slide_in.xml -->
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_shortAnimTime"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:fromXDelta="100%"
    android:toXDelta="0%" />

Sie können auch Animationen für die Ein- und Ausstiegseffekte festlegen, die ausgeführt werden. beim Heranzoomen des Back-Stacks, was passieren kann, wenn Nutzende auf die Schaltfläche Schaltfläche „Zurück“ Diese werden als popEnter- und popExit-Animationen bezeichnet. Für Wenn z. B. ein Nutzer zu einem vorherigen Bildschirm zurückkehrt, Aktuelles Fragment, das vom rechten Bildschirmrand und vom vorherigen weg verschoben wird Fragment, das eingeblendet werden soll.

<ph type="x-smartling-placeholder">
</ph> popEnter und popExit enthält. Das aktuelle Fragment gleitet aus
            Bildschirm nach rechts, während das vorherige
Fragment eingeblendet wird.
Abbildung 2: popEnter und popExit Animationen. Das aktuelle Fragment verschwindet vom Bildschirm. nach rechts, während das vorherige Fragment eingeblendet wird.

Diese Animationen können so definiert werden:

<!-- res/anim/slide_out.xml -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_shortAnimTime"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:fromXDelta="0%"
    android:toXDelta="100%" />
<!-- res/anim/fade_in.xml -->
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_shortAnimTime"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:fromAlpha="0"
    android:toAlpha="1" />

Nachdem Sie Ihre Animationen definiert haben, rufen Sie FragmentTransaction.setCustomAnimations(), und übergeben Ihre Animationsressourcen anhand ihrer Ressourcen-ID, wie in den folgendes Beispiel:

Kotlin

supportFragmentManager.commit {
    setCustomAnimations(
        R.anim.slide_in, // enter
        R.anim.fade_out, // exit
        R.anim.fade_in, // popEnter
        R.anim.slide_out // popExit
    )
    replace(R.id.fragment_container, fragment)
    addToBackStack(null)
}

Java

Fragment fragment = new FragmentB();
getSupportFragmentManager().beginTransaction()
    .setCustomAnimations(
        R.anim.slide_in,  // enter
        R.anim.fade_out,  // exit
        R.anim.fade_in,   // popEnter
        R.anim.slide_out  // popExit
    )
    .replace(R.id.fragment_container, fragment)
    .addToBackStack(null)
    .commit();

Übergänge festlegen

Sie können Übergänge auch verwenden, um Ein- und Exit-Effekte zu definieren. Diese Übergänge können in XML-Ressourcendateien definiert werden. Zum Beispiel könnten Sie soll das aktuelle Fragment ausgeblendet und das neue Fragment rechten Bildschirmrand. Diese Übergänge können so definiert werden:

<!-- res/transition/fade.xml -->
<fade xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_shortAnimTime"/>
<!-- res/transition/slide_right.xml -->
<slide xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_shortAnimTime"
    android:slideEdge="right" />

Nachdem Sie Ihre Übergänge definiert haben, wenden Sie sie an, indem Sie setEnterTransition() auf das eingegebene Fragment und setExitTransition() beim schließenden Fragment, wobei die überhöhten Übergangsressourcen übergeben werden nach ihrer Ressourcen-ID sortiert, wie im folgenden Beispiel gezeigt:

Kotlin

class FragmentA : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val inflater = TransitionInflater.from(requireContext())
        exitTransition = inflater.inflateTransition(R.transition.fade)
    }
}

class FragmentB : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val inflater = TransitionInflater.from(requireContext())
        enterTransition = inflater.inflateTransition(R.transition.slide_right)
    }
}

Java

public class FragmentA extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TransitionInflater inflater = TransitionInflater.from(requireContext());
        setExitTransition(inflater.inflateTransition(R.transition.fade));
    }
}

public class FragmentB extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TransitionInflater inflater = TransitionInflater.from(requireContext());
        setEnterTransition(inflater.inflateTransition(R.transition.slide_right));
    }
}

Unterstützung von Fragmenten AndroidX-Übergänge Fragmente unterstützen zwar auch Framework-Umstellungen zu verfolgen, empfehlen AndroidX-Umstellungen, da diese in API-Levels 14 unterstützt werden. und höher und enthalten Fehlerbehebungen, die in älteren Versionen der Framework-Umstellungen.

Übergänge mit gemeinsam genutzten Elementen verwenden

Teil des Frameworks für die Umstellung Übergänge mit gemeinsam genutzten Elementen bestimmen, wie entsprechende Ansichten zwischen während eines Fragmentübergangs zwei Fragmente. Zum Beispiel könnten Sie eine Bild, das in einem ImageView in Fragment A angezeigt wird, um zu Fragment B zu wechseln sobald B sichtbar wird (siehe Abbildung 3).

<ph type="x-smartling-placeholder">
</ph> Ein Fragmentübergang mit einem gemeinsamen Element. <ph type="x-smartling-placeholder">
</ph> Abbildung 3: Ein Fragmentübergang mit einem gemeinsamen Element.

Im Folgenden erfahren Sie, wie Sie einen Fragmentübergang mit gemeinsam genutzten Elementen erstellen:

  1. Weisen Sie jeder Ansicht gemeinsam genutzter Elemente einen eindeutigen Übergangsnamen zu.
  2. Fügen Sie gemeinsam genutzte Elementansichten und Übergangsnamen zum FragmentTransaction
  3. Übergangsanimation für gemeinsam genutzte Elemente festlegen

Zunächst müssen Sie jeder Ansicht gemeinsam genutzter Elemente einen eindeutigen Übergangsnamen zuweisen. damit die Ansichten von einem Fragment zum nächsten zugeordnet werden können. Legen Sie einen Namen von gemeinsam genutzten Elementen in jedem Fragmentlayout mithilfe von ViewCompat.setTransitionName(), und bietet Kompatibilität mit API-Levels 14 und höher. Beispielsweise der Übergangsname für eine ImageView in den Fragmenten A und B. kann folgendermaßen zugewiesen werden:

Kotlin

class FragmentA : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        ...
        val itemImageView = view.findViewById<ImageView>(R.id.item_image)
        ViewCompat.setTransitionName(itemImageView, item_image)
    }
}

class FragmentB : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        ...
        val heroImageView = view.findViewById<ImageView>(R.id.hero_image)
        ViewCompat.setTransitionName(heroImageView, hero_image)
    }
}

Java

public class FragmentA extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        ...
        ImageView itemImageView = view.findViewById(R.id.item_image);
        ViewCompat.setTransitionName(itemImageView, item_image);
    }
}

public class FragmentB extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        ...
        ImageView heroImageView = view.findViewById(R.id.hero_image);
        ViewCompat.setTransitionName(heroImageView, hero_image);
    }
}

Um Ihre gemeinsam genutzten Elemente in den Fragmentübergang einzubeziehen, FragmentTransaction muss wissen, wie die Ansichten der geteilten Elemente von einem zum nächsten Fragment. Fügen Sie jedes Ihrer gemeinsamen Elemente FragmentTransaction über folgenden Anruf FragmentTransaction.addSharedElement(), übergeben die Ansicht und den Übergangsnamen der entsprechenden Ansicht im nächstes Fragment, wie im folgenden Beispiel gezeigt:

Kotlin

val fragment = FragmentB()
supportFragmentManager.commit {
    setCustomAnimations(...)
    addSharedElement(itemImageView, hero_image)
    replace(R.id.fragment_container, fragment)
    addToBackStack(null)
}

Java

Fragment fragment = new FragmentB();
getSupportFragmentManager().beginTransaction()
    .setCustomAnimations(...)
    .addSharedElement(itemImageView, hero_image)
    .replace(R.id.fragment_container, fragment)
    .addToBackStack(null)
    .commit();

Um festzulegen, wie Ihre gemeinsam genutzten Elemente von einem Fragment zum nächsten übergehen, müssen Sie auf dem zu verwendenden Fragment einen enter-Übergang festlegen. aufgerufen wurde. Anruf Fragment.setSharedElementEnterTransition() in der Methode onCreate() des Fragments, wie im folgenden Beispiel gezeigt:

Kotlin

class FragmentB : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        sharedElementEnterTransition = TransitionInflater.from(requireContext())
             .inflateTransition(R.transition.shared_image)
    }
}

Java

public class FragmentB extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Transition transition = TransitionInflater.from(requireContext())
            .inflateTransition(R.transition.shared_image);
        setSharedElementEnterTransition(transition);
    }
}

Der Übergang shared_image ist so definiert:

<!-- res/transition/shared_image.xml -->
<transitionSet>
    <changeImageTransform />
</transitionSet>

Alle abgeleiteten Klassen von Transition werden als Übergänge mit gemeinsam genutzten Elementen unterstützt. Wenn Sie ein benutzerdefiniertes Transition erstellen möchten, finden Sie unter Benutzerdefinierte Übergangsanimation erstellen changeImageTransform, das im vorherigen Beispiel verwendet wurde, ist eine der verfügbaren vordefinierte Übersetzungen, die Sie nutzen können. Hier finden Sie weitere Transition in der API-Referenz für die Klasse Transition.

Standardmäßig wird der Übergang vom gemeinsam genutzten Element auch als return-Übergang für gemeinsam genutzte Elemente. Der Rückübergang bestimmt, wie gemeinsam genutzte Elemente gehen zum vorherigen Fragment über, Transaktion aus dem Back-Stack entfernt. Falls Sie eine andere können Sie dies mithilfe der Fragment.setSharedElementReturnTransition() in der Methode onCreate() des Fragments.

Vorausschauende Rückenkompatibilität

Sie können die Funktion „Hintergrundeingabe“ mit vielen, aber nicht allen fragmentierten Animationen verwenden. Beachten Sie bei der Implementierung von „rückblickender Prognose“ Folgendes:

  • Importieren Sie Transitions 1.5.0 oder höher und Fragments 1.7.0 oder höher.
  • Die Animator-Klasse und die abgeleiteten Klassen sowie die AndroidX-Übergangsbibliothek sind unterstützt.
  • Die Animation-Klasse und die Framework-Transition-Bibliothek werden nicht unterstützt.
  • Prognostische Fragmentanimationen funktionieren nur auf Geräten mit Android 14 oder höher liegen.
  • setCustomAnimations, setEnterTransition, setExitTransition setReenterTransition, setReturnTransition setSharedElementEnterTransition und setSharedElementReturnTransition sind mit der Funktion „Rückwärtspfeil“.

Weitere Informationen finden Sie unter Unterstützung für vorausschauende Rückwärtsanimationen

Übergänge verschieben

In einigen Fällen müssen Sie den Fragmentübergang um einen in einem kurzen Zeitraum. Es kann z. B. sein, dass Sie warten müssen, bis alle Aufrufe im eingegebenen Fragment so vermessen und angeordnet wurden, dass Android ihre Start- und Endzustände für den Übergang genau erfassen.

Außerdem muss die Umstellung möglicherweise die erforderlichen Daten geladen wurden. Sie müssen z. B. warten, bis Bilder wurden für geteilte Elemente geladen. Andernfalls kann es passieren, wenn ein Bild während oder nach dem Übergang fertig geladen wird.

Um einen Übergang zu verschieben, müssen Sie zuerst sicherstellen, dass das Fragment -Transaktion ermöglicht die Neuanordnung von Fragmentstatusänderungen. Um Neuanordnung zu ermöglichen Änderungen des Fragmentstatus, FragmentTransaction.setReorderingAllowed(), Dies wird im folgenden Beispiel gezeigt:

Kotlin

val fragment = FragmentB()
supportFragmentManager.commit {
    setReorderingAllowed(true)
    setCustomAnimation(...)
    addSharedElement(view, view.transitionName)
    replace(R.id.fragment_container, fragment)
    addToBackStack(null)
}

Java

Fragment fragment = new FragmentB();
getSupportFragmentManager().beginTransaction()
    .setReorderingAllowed(true)
    .setCustomAnimations(...)
    .addSharedElement(view, view.getTransitionName())
    .replace(R.id.fragment_container, fragment)
    .addToBackStack(null)
    .commit();

Um den Wechsel zu verschieben, rufen Sie Folgendes auf: Fragment.postponeEnterTransition() in der Methode onViewCreated() des eingegebenen Fragments:

Kotlin

class FragmentB : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        ...
        postponeEnterTransition()
    }
}

Java

public class FragmentB extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        ...
        postponeEnterTransition();
    }
}

Sobald Sie die Daten geladen haben und mit der Umstellung beginnen können, rufen Sie Fragment.startPostponedEnterTransition() Im folgenden Beispiel wird die Methode Glide-Bibliothek, um ein Bild zu laden in eine gemeinsame ImageView, wobei der entsprechende Übergang bis zur Ladevorgang ist abgeschlossen.

Kotlin

class FragmentB : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        ...
        Glide.with(this)
            .load(url)
            .listener(object : RequestListener<Drawable> {
                override fun onLoadFailed(...): Boolean {
                    startPostponedEnterTransition()
                    return false
                }

                override fun onResourceReady(...): Boolean {
                    startPostponedEnterTransition()
                    return false
                }
            })
            .into(headerImage)
    }
}

Java

public class FragmentB extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        ...
        Glide.with(this)
            .load(url)
            .listener(new RequestListener<Drawable>() {
                @Override
                public boolean onLoadFailed(...) {
                    startPostponedEnterTransition();
                    return false;
                }

                @Override
                public boolean onResourceReady(...) {
                    startPostponedEnterTransition();
                    return false;
                }
            })
            .into(headerImage)
    }
}

Bei Problemen wie der langsamen Internetverbindung eines Nutzers dass der verschobene Übergang nach einer bestimmten Zeit beginnen soll, als warten, bis alle Daten geladen sind. In diesen Fällen können Sie stattdessen anrufen Fragment.postponeEnterTransition(long, TimeUnit) in der onViewCreated()-Methode des eingegebenen Fragments, wobei die Dauer übergeben wird und die Zeiteinheit. Die verschobene Anzeige beginnt dann automatisch, die angegebene Zeit verstrichen ist.

Übergänge mit gemeinsam genutzten Elementen mit einem RecyclerView verwenden

Verschobene Eingabeübergänge sollten erst beginnen, wenn alle Ansichten in der wurden vermessen und angeordnet. Bei Verwendung eines RecyclerView, Sie müssen warten bis alle Daten geladen sind und die RecyclerView-Elemente zum Zeichnen bereit sind bevor Sie mit der Umstellung beginnen. Beispiel:

Kotlin

class FragmentA : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        postponeEnterTransition()

        // Wait for the data to load
        viewModel.data.observe(viewLifecycleOwner) {
            // Set the data on the RecyclerView adapter
            adapter.setData(it)
            // Start the transition once all views have been
            // measured and laid out
            (view.parent as? ViewGroup)?.doOnPreDraw {
                startPostponedEnterTransition()
            }
        }
    }
}

Java

public class FragmentA extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        postponeEnterTransition();

        final ViewGroup parentView = (ViewGroup) view.getParent();
        // Wait for the data to load
        viewModel.getData()
            .observe(getViewLifecycleOwner(), new Observer<List<String>>() {
                @Override
                public void onChanged(List<String> list) {
                    // Set the data on the RecyclerView adapter
                    adapter.setData(it);
                    // Start the transition once all views have been
                    // measured and laid out
                    parentView.getViewTreeObserver()
                        .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                            @Override
                            public boolean onPreDraw(){
                                parentView.getViewTreeObserver()
                                        .removeOnPreDrawListener(this);
                                startPostponedEnterTransition();
                                return true;
                            }
                    });
                }
        });
    }
}

Beachten Sie, dass ein ViewTreeObserver.OnPreDrawListener wird für das übergeordnete Element der Fragmentansicht festgelegt. So stellen Sie sicher, dass alle die Ansichten des Fragments wurden gemessen und angeordnet und sind daher vor Beginn des verschobenen Übergangs gezeichnet werden.

Ein weiterer Punkt, der bei der Verwendung von Übergängen mit gemeinsam genutzten Elementen in Verbindung mit einem RecyclerView ist, dass Sie den Übergangsnamen nicht in der Das XML-Layout des RecyclerView-Elements, da sich eine beliebige Anzahl von Elementen das gleiche teilen kann für dieses Layout. Für den Übergang muss ein eindeutiger Name für den Übergang zugewiesen werden, die richtige Ansicht verwendet.

Sie können dem gemeinsam genutzten Element einen eindeutigen Übergangsnamen zuweisen, indem Sie Sie werden zugewiesen, wenn die ViewHolder gebunden ist. Wenn zum Beispiel die Daten für jeder Artikel eine eindeutige ID hat, kann dieser als Übergangsname verwendet werden, Beispiel:

Kotlin

class ExampleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val image = itemView.findViewById<ImageView>(R.id.item_image)

    fun bind(id: String) {
        ViewCompat.setTransitionName(image, id)
        ...
    }
}

Java

public class ExampleViewHolder extends RecyclerView.ViewHolder {
    private final ImageView image;

    ExampleViewHolder(View itemView) {
        super(itemView);
        image = itemView.findViewById(R.id.item_image);
    }

    public void bind(String id) {
        ViewCompat.setTransitionName(image, id);
        ...
    }
}

Weitere Informationen

Weitere Informationen zu Fragmentübergängen finden Sie in den folgenden zusätzlichen Ressourcen.

Produktproben

Blogposts