FragmentTransaction-Animation, die nach oben verschoben werden soll

73

Ich versuche, den folgenden Effekt mit FragmentTransaction.setCustomAnimations zu erzielen.

  1. Fragment A wird angezeigt
  2. Ersetzen Sie Fragment A durch Fragment B. Fragment A sollte während des Austauschs sichtbar bleiben. Fragment B sollte von rechts hineingleiten. Fragment B sollte über die Oberseite von Fragment A gleiten.

Ich habe kein Problem damit, die Folie im Animations-Setup zu erhalten. Mein Problem ist, dass ich nicht herausfinden kann, wie Fragment A dort bleiben kann, wo es ist, und UNTER Fragment B sein kann, während die Folie in der Animation ausgeführt wird. Egal was ich mache, es scheint, dass Fragment A oben ist.

Wie kann ich das erreichen?

Hier ist der FragmentTransaction-Code:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_right, R.anim.nothing, R.anim.nothing,
    R.anim.slide_out_right);
ft.replace(R.id.fragment_content, fragment, name);
ft.addToBackStack(name);
ft.commit();

Wie Sie sehen können, habe ich eine Animation R.anim.nothing für die "out" -Animation definiert, da ich eigentlich nicht möchte, dass Fragment A etwas anderes tut, als nur dort zu bleiben, wo es während der Transaktion ist.

Hier sind die Animationsressourcen:

slide_in_right.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_mediumAnimTime"
    android:fromXDelta="100%p"
    android:toXDelta="0"
    android:zAdjustment="top" />

nothing.xml

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_mediumAnimTime"
    android:fromAlpha="1.0"
    android:toAlpha="1.0"
    android:zAdjustment="bottom" />
Matt Accola
quelle
1
Ich habe einen Fehlerbericht eingereicht, weil die aktuelle Z-Reihenfolge einfach falsch ist. code.google.com/p/android/issues/…
sbaar

Antworten:

24

Update (16. Juni 2020)

Ausgehend von der Fragmentbibliothek wird 1.2.0empfohlen, dieses Problem FragmentContainerViewmit zu beheben FragmentTransaction.setCustomAnimations().

Laut Dokumentation :

Fragmente, die Exit-Animationen verwenden, werden für FragmentContainerView vor allen anderen gezeichnet. Dadurch wird sichergestellt, dass das Verlassen von Fragmenten nicht über der Ansicht angezeigt wird.

Schritte zur Behebung dieses Problems sind:

  1. Aktualisieren Sie die Fragmentbibliothek auf 1.2.0 oder höher androidx.fragment:fragment:1.2.0.
  2. Ersetzen Sie Ihre XML - Fragment Behälter ( <fragment>, <FrameLayout>, oder) durch <androidx.fragment.app.FragmentContainerView>;
  3. Verwenden Sie FragmentTransaction.setCustomAnimations()diese Option, um Ihre Fragmentübergänge zu animieren.

Vorherige Antwort (19. November 2015)

Ausgehend von Lollipop können Sie die ÜbersetzungZ Ihres eingegebenen Fragments erhöhen. Es wird über dem Ausgang angezeigt.

Zum Beispiel:

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    ViewCompat.setTranslationZ(getView(), 100.f);
}

Wenn Sie den TranslationZ-Wert nur für die Dauer der Animation ändern möchten, sollten Sie Folgendes tun:

@Override
public Animation onCreateAnimation(int transit, final boolean enter, int nextAnim) {
    Animation nextAnimation = AnimationUtils.loadAnimation(getContext(), nextAnim);
    nextAnimation.setAnimationListener(new Animation.AnimationListener() {

        private float mOldTranslationZ;

        @Override
        public void onAnimationStart(Animation animation) {
            if (getView() != null && enter) {
                mOldTranslationZ = ViewCompat.getTranslationZ(getView());
                ViewCompat.setTranslationZ(getView(), 100.f);
            }
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            if (getView() != null && enter) {
                ViewCompat.setTranslationZ(getView(), mOldTranslationZ);
            }
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    });
    return nextAnimation;
}
JFrite
quelle
Gute Arbeit bei der Suche, habe vor langer Zeit nach dieser Lösung gesucht und jetzt ist sie gelöst.
Rod_Algonquin
Vielen Dank. Scheint zu funktionieren. Darf ich wissen, warum onCreateAnimationwir zum Überschreiben die Animation manuell über erstellen müssen AnimationUtils.loadAnimation? Mir ist klar, wenn ich versuche, Animationüber super.onCreateAnimation zu erhalten , ist es null.
Cheok Yan Cheng
@CheokYanCheng Weil die Fragment.onCreateAnimation()Methode standardmäßig nichts tut und nur null zurückgibt. Diese Methode ist nur dazu da, Ihnen die Möglichkeit zu geben, die Animation selbst zu erstellen. Wenn Sie sich die Methode ansehen, werden FragmentManager.loadAnimation()Sie feststellen, dass sie zuerst versucht, eine Animation abzurufen. fragment.onCreateAnimation()Wenn sie null zurückgibt, erstellt der FragmentManager die Animation selbst.
JFrite
2
Es ist erwähnenswert, dass das Verringern der Höhe am NED aufgrund von Zeitproblemen zu Flackern führen kann, was bedeutet, dass das ersetzte Fragment die Animation noch nicht abgeschlossen hat. Ich habe es gelöst, indem ich die Höhe mit einer kleinen Verzögerung zurückgegeben habe.
Efi G
1
Funktioniert nicht für mich. Es gibt android.content.res.Resources $ NotFoundException: Fehler Resource ID # 0x0
Rohit Singh
20

Ich weiß nicht, ob Sie noch eine Antwort benötigen, aber ich musste kürzlich das Gleiche tun und habe einen Weg gefunden, das zu tun, was Sie wollen.

Ich habe so etwas gemacht:

FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();

MyFragment next = getMyFragment();

ft.add(R.id.MyLayout,next);
ft.setCustomAnimations(R.anim.slide_in_right,0);
ft.show(next);
ft.commit();

Ich zeige mein Fragment in einem FrameLayout an.

Es funktioniert Geldstrafen, aber das ältere Fragment ist immer noch in meiner Ansicht. Ich lasse Android es verwalten, wie er es will, denn wenn ich sage:

ft.remove(myolderFrag);

Es wird während der Animation nicht angezeigt.

slide_in_right.xml

    <?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate android:duration="150" android:fromXDelta="100%p" 
android:interpolator="@android:anim/linear_interpolator"
android:toXDelta="0" />
 </set>
Meph
quelle
Vielen Dank und ich suche noch nach einer Lösung. Ihre Antwort ist korrekt, aber leider wird das Problem nicht vollständig behoben. Ich kann das alte Fragment nicht im Speicher belassen, da es sonst zu viel Speicher verbraucht. Ich habe den Ansatz gewählt, eine Bitmap aus der ausgehenden Ansicht zu erstellen und diese unter der Ansicht zu platzieren, zu der das neue Fragment hinzugefügt wird. Das erzielt den Effekt, aber ich habe wieder Speicherprobleme, weil die Bitmap zu groß ist. Ich untersuche einige andere Ansätze, einschließlich ViewPager mit FragmentStatePagerAdapter und einem FrameLayout pro Fragment. Werde später zurück posten.
Matt Accola
1
@ Domji84 <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="150" android:fromXDelta="100%p" android:interpolator="@android:anim/linear_interpolator" android:toXDelta="0" /> </set>
Meph
Vielen Dank. overridePendingTransition(R.anim.my_animation, 0)ist die Linie, nach der ich gesucht habe.
Adam Johns
Auf Support v22 scheint das alte Fragment nur zu verschwinden, wenn der Übergang beginnt.
sbaar
8

Ich habe eine Lösung gefunden, die für mich funktioniert. Am Ende habe ich einen ViewPager mit einem FragmentStatePagerAdapter verwendet. Der ViewPager stellt das Wischverhalten bereit und der FragmentStatePagerAdapter tauscht die Fragmente aus. Der letzte Trick, um den Effekt zu erzielen, dass eine Seite "unter" der eingehenden Seite sichtbar ist, ist die Verwendung eines PageTransformers. Der PageTransformer überschreibt den Standardübergang des ViewPager zwischen Seiten. Hier ist ein Beispiel für einen PageTransformer, der den Effekt mit Übersetzung und einer geringen Skalierung auf der linken Seite erzielt.

public class ScalePageTransformer implements PageTransformer {
    private static final float SCALE_FACTOR = 0.95f;

    private final ViewPager mViewPager;

    public ScalePageTransformer(ViewPager viewPager) {
            this.mViewPager = viewPager;
    }

    @SuppressLint("NewApi")
    @Override
    public void transformPage(View page, float position) {
        if (position <= 0) {
            // apply zoom effect and offset translation only for pages to
            // the left
            final float transformValue = Math.abs(Math.abs(position) - 1) * (1.0f - SCALE_FACTOR) + SCALE_FACTOR;
            int pageWidth = mViewPager.getWidth();
            final float translateValue = position * -pageWidth;
            page.setScaleX(transformValue);
            page.setScaleY(transformValue);
            if (translateValue > -pageWidth) {
                page.setTranslationX(translateValue);
            } else {
                page.setTranslationX(0);
            }
        }
    }

}
Matt Accola
quelle
Tolle Lösung, passt aber leider nicht, wenn Sie den Stapel ändern möchten, insbesondere in Richtung Verkleinerung - dies führt zu Blendung (Neuzeichnen des gesamten Elements).
Siruk Viktor
6

Nach weiteren Experimenten (daher ist dies meine zweite Antwort) scheint das Problem zu sein, dass R.anim.nothing "verschwinden" bedeutet, wenn wir eine andere Animation wollen, die explizit "bleiben" sagt. Die Lösung besteht darin, eine echte "Nichts tun" -Animation wie folgt zu definieren:

Datei erstellen no_animation.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/linear_interpolator"
        android:fromXScale="1.0"
        android:toXScale="1.0"
        android:fromYScale="1.0"
        android:toYScale="1.0"
        android:duration="200"
        />
    <alpha xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromAlpha="1.0"
        android:toAlpha="0.0"
        android:duration="200"
        android:startOffset="200"
        />
</set>

Tun Sie jetzt einfach so, wie Sie es sonst tun würden:

getActivity().getSupportFragmentManager().beginTransaction()
                .setCustomAnimations(R.anim.slide_in_right, R.anim.no_animation)
                .replace(R.id.container, inFrag, FRAGMENT_TAG)
                .addToBackStack("Some text")
                .commit();
Merk
quelle
Ich werde es versuchen, aber ich hatte überlegt, eine richtige "stay_put" -Animation zu machen, und alles, was es tat, war, die gleitende Animation des neuen Fragments abzudecken, wobei das alte Fragment im Vordergrund blieb. Aber ich sehe, dass Sie den Beginn der no_animation versetzt haben, also macht es vielleicht den Trick. Ich werde Sie wissen lassen, was ich von Ihrer Lösung halte.
JDenais
3
Netter Gedanke, aber das funktioniert nicht, da die Transaktion das Fragment sofort entfernt und ich den weißen Bildschirm unter dem zweiten Fragment während der Animation sehen kann.
Muhammad Babar
1
Verwirrt darüber, warum Sie dachten, dass dies erforderlich ist. Ich habe gerade 0 verwendet, wo ich keinen Übergang wollte und es hat super funktioniert. So sieht es aus, als hättest du es oben getan.
NineToeNerd
1
In meinem Fall war die Animation "Nichts tun" bei der Verwendung in Ordnung add, verursachte jedoch Probleme bei der Verwendung replace. Das Ersetzen durch 0hat den Trick getan. Danke, @NineToeNerd
Cesar Castro
2

Ich habe eine alternative Lösung gefunden (nicht stark getestet), die ich eleganter finde als die bisherigen Vorschläge:

final IncomingFragment newFrag = new IncomingFragment();
newFrag.setEnterAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    clearSelection();
                    inFrag.clearEnterAnimationListener();

                    getFragmentManager().beginTransaction().remove(OutgoingFragment.this).commit();
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });

 getActivity().getSupportFragmentManager().beginTransaction()
                    .setCustomAnimations(R.anim.slide_in_from_right, 0)
                    .add(R.id.container, inFrag)
                    .addToBackStack(null)
                    .commit();

Dies wird aus einer inneren Klasse der OutgoingFragment-Klasse heraus aufgerufen.

Ein neues Fragment wird eingefügt, die Animation wird abgeschlossen und das alte Fragment wird entfernt.

In einigen Anwendungen kann es zu Speicherproblemen kommen, aber es ist besser, beide Fragmente unbegrenzt beizubehalten.

Merk
quelle
Für mich ist dies die bisher beste Lösung. Früher habe ich das Gleiche getan, aber indem ich das System während der Animation mit einem Handler angehalten und dann das vorherige Fragment entfernt habe, aber das ist viel besser.
JDenais
1
Woher kamen die Klassen IncomingFragment und OutgoingFragment? Sind sie Brauch? Ich verstehe die Implementierung dahinter nicht ganz. Vielleicht gab es beim Schreiben eine Funktion wie Fragment.setEnterAnimationListener(...)... oder ist das eine benutzerdefinierte Funktion für dieses Fragment?
NineToeNerd
1

Dies ist meine aktuelle Problemumgehung für alle Interessierten.

In der Funktion zum Hinzufügen des neuen Fragment:

final Fragment toRemove = fragmentManager.findFragmentById(containerID);
if (toRemove != null) {
    new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                fragmentManager.beginTransaction().hide(toRemove).commit();
            }
        }, 
        getResources().getInteger(android.R.integer.config_mediumAnimTime) + 100);
        // Use whatever duration you chose for your animation for this handler
        // I added an extra 100 ms because the first transaction wasn't always 
        // fast enough
}
fragmentManager.beginTransaction()
    .setCustomAnimations(enter, 0, 0, popExit).add(containerID, fragmentToAdd)
    .addToBackStack(tag).commit();

und in onCreate:

final FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.addOnBackStackChangedListener(
        new FragmentManager.OnBackStackChangedListener() {
            @Override
            public void onBackStackChanged() {
                Fragment current = fragmentManager.findFragmentById(containerID);
                if (current != null && current.isHidden()) {
                    fragmentManager.beginTransaction().show(current).commit();
                }
            }
        });

Ich würde eine Art AnimationListener anstelle eines Handlers oben bevorzugen, aber ich habe keine Möglichkeit gesehen, mit einer das Ende der Transaktionsanimation zu erkennen, die nicht an das Fragment gebunden war onCreateAnimation(). Alle Vorschläge / Änderungen mit einem geeigneten Hörer wäre dankbar.

Ich werde darauf hinweisen, dass die Fragments, die ich auf diese Weise hinzufüge, leicht sind, sodass es für mich kein Problem ist, sie zusammen mit dem Fragment, auf dem sie sich befinden, im Fragmentcontainer zu haben.

Wenn Sie das Fragment entfernen möchten, können Sie es fragmentManager.beginTransaction().remove(toRemove).commitAllowingStateLoss();in das Handler's Runnableund in das OnBackStackChangedListener:

// Use back stack entry tag to get the fragment
Fragment current = getCurrentFragment(); 
if (current != null && !current.isAdded()) {
    fragmentManager.beginTransaction()
        .add(containerId, current, current.getTag())
        .commitNowAllowingStateLoss();
}

Beachten Sie, dass die obige Lösung für das erste Fragment im Container nicht funktioniert (da es sich nicht im Backstack befindet). Sie müssten also eine andere Möglichkeit haben, dieses wiederherzustellen, und möglicherweise einen Verweis auf das erste Fragment irgendwie speichern. Wenn Sie den Backstack jedoch nicht verwenden und Fragmente immer manuell ersetzen, ist dies kein Problem. ODER Sie können alle Fragmente zum hinteren Stapel hinzufügen (einschließlich des ersten) und überschreiben onBackPressed, um sicherzustellen, dass Ihre Aktivität beendet wird, anstatt einen leeren Bildschirm anzuzeigen, wenn nur noch ein Fragment im hinteren Stapel vorhanden ist.

EDIT: Ich habe die folgenden Funktionen entdeckt, die wahrscheinlich FragmentTransaction.remove()und FragmentTransaction.add()höher ersetzen könnten :

FragmentTransaction. trennen () :

Trennen Sie das angegebene Fragment von der Benutzeroberfläche. Dies ist derselbe Status wie beim Ablegen auf dem Backstack: Das Fragment wird aus der Benutzeroberfläche entfernt, sein Status wird jedoch weiterhin vom Fragmentmanager aktiv verwaltet. Wenn Sie in diesen Zustand wechseln, wird die Ansichtshierarchie zerstört.

FragmentTransaction. attach () :

Hängen Sie ein Fragment erneut an, nachdem es zuvor mit trennen (Fragment) von der Benutzeroberfläche getrennt wurde. Dadurch wird die Ansichtshierarchie neu erstellt, an die Benutzeroberfläche angehängt und angezeigt.

NineToeNerd
quelle
1

Basierend auf jfrite Antwort, die meine Implementierungen anhängt

import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.util.Log;

public final class AnimationHelper {
    private AnimationHelper() {

    }

    private static String TAG = AnimationHelper.class.getSimpleName();
    private static final float ELEVATION_WHILE_ENTER_ANIMATION_IS_RUNNING = 100f;
    private static final int RESTORE_ANIMATION_DELAY = 16;

    /**
     * When replacing fragments with animations, by default the new fragment is placed below the replaced fragment. This
     * method returns an animation object that sets high elevation at the beginning of the animation and resets the
     * elevation when the animation completes. The {@link Animation} object that is returned is not the actual object
     * that is used for the animating the fragment but the callbacks are called at the appropriate time. The method
     * {@link Fragment#onCreateAnimation(int, boolean, int)} by default returns null, therefor, this method can be used
     * as the return value for {@link Fragment#onCreateAnimation(int, boolean, int)} method although it can return
     * null.
     * @param enter True if fragment is 'entering'.
     * @param nextAnim Animation resource id that is about to play.
     * @param fragment The animated fragment.
     * @return If nextAnim is a valid resource id and 'enter' is true, returns an {@link Animation} object with the
     * described above behavior, otherwise returns null.
     */
    @Nullable
    public static Animation increaseElevationWhileAnimating(boolean enter, int nextAnim,
                                                            @NonNull Fragment fragment) {
        if (!enter || nextAnim == 0) {
            return null;
        }
        Animation nextAnimation;
        try {
            nextAnimation = AnimationUtils.loadAnimation(fragment.getContext(), nextAnim);
        } catch (Resources.NotFoundException e) {
            Log.e(TAG, "Can't find animation resource", e);
            return null;
        }
        nextAnimation.setAnimationListener(new Animation.AnimationListener() {
            private float oldTranslationZ;

            @Override
            public void onAnimationStart(Animation animation) {
                if (fragment.getView() != null && !fragment.isDetached()) {
                    oldTranslationZ = ViewCompat.getTranslationZ(fragment.getView());
                    ViewCompat.setTranslationZ(fragment.getView(), ELEVATION_WHILE_ENTER_ANIMATION_IS_RUNNING);
                }
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                if (fragment.getView() != null && !fragment.isDetached()) {
                    fragment.getView().postDelayed(() -> {
                        // Decreasing the elevation at the ned can cause some flickering because of timing issues,
                        // Meaning that the replaced fragment did not complete yet the animation. Resting the animation
                        // with a minor delay solves the problem.
                        if (!fragment.isDetached()) {
                            ViewCompat.setTranslationZ(fragment.getView(), oldTranslationZ);
                        }
                    }, RESTORE_ANIMATION_DELAY);
                }
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });
        return nextAnimation;
    }
}

Hier ist, wie ich den Helfer aus dem Fragment benutze.

@Override
    public Animation onCreateAnimation(int transit, final boolean enter, int nextAnim) {
        return AnimationHelper.increaseElevationWhileAnimating(enter, nextAnim, this);
    }

Hier ist, wie ich das Fragment mit Animation beginne

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.setCustomAnimations(R.anim.slide_in, R.anim.hold, R.anim.hold, R.anim.slide_out);
Efi G.
quelle
Dies behebt das Problem, wenn ein neues Fragment geladen wird, aber es gibt ein Problem beim Drücken der Zurück-Taste. Wie könnte ich die Animation "umkehren" und Übergangsprobleme vermeiden?
Moyo
@moyo nicht sicher, ob ich deine Frage verstanden habe. Trotzdem habe ich diese Zeile hinzugefügt: if (! enter || nextAnim == 0 || nextAnim == R.anim.hold) {return null; }
Efi G
0
FragmentTransaction ft = ((AppCompatActivity) context).getSupportFragmentManager().beginTransaction();
                ft.setCustomAnimations(0, R.anim.slide_out_to_right);
            if (!fragment.isAdded())
            {
                ft.add(R.id.fragmentContainerFrameMyOrders, fragment);
                ft.show(fragment);
            }
            else
                ft.replace(R.id.fragmentContainerFrameMyOrders, fragment);
            ft.commit();
Bishwajeet Biswas
quelle
0

Fügen Sie dem Layout eine Ansicht hinzu.

Ich habe dem Fragment, das von unten in 30sp hineingleitet, eine Ansicht hinzugefügt, und es hat funktioniert.

Ich habe viele hier vorgeschlagene Lösungen ausprobiert. Hier sind der vollständige Code und die Ausgabe, die die gesamte Idee + das Hinzufügen von Höhen kombinieren .

Ausgabe:

Ohne Erhebung:

Geben Sie hier die Bildbeschreibung ein

Mit Höhe:

Geben Sie hier die Bildbeschreibung ein

Vollständiger Code:

Fügen Sie der Wurzel eine Höhe hinzu

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:elevation="30sp">
     ----

     ----
 </RelativeLayout>

Wie schiebe ich das Fragment von unten hinein?

getSupportFragmentManager()
            .beginTransaction()
            .setCustomAnimations(R.anim.slide_in_bottom, R.anim.do_nothing, R.anim.do_nothing, R.anim.slide_out_bottom)
            .replace(R.id.fragmentContainer, currentFragment, "TAG")
            .addToBackStack("TAG")
            .commit();

Wie mache ich den Rückwärtsgang, wenn die Zurück-Taste gedrückt wird?

getSupportFragmentManager()
            .popBackStack();

Da wir bereits die Eingabe- und Beendigungsanimation für die setCustomAnimations()Methode definiert haben. Der Anruf popBackStack();kümmert sich um die umgekehrte Animation.

R.anim.slide_in_bottom

<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
       android:duration="500"
       android:fromYDelta="100%"
       android:toYDelta="0%">
    </translate>
</set>

R.anim.slide_out_bottom

<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="500"
        android:fromYDelta="0%"
        android:toYDelta="100%">
    </translate>
</set>

R.anim.do_nothing

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/linear_interpolator"
        android:fromXScale="1.0"
        android:toXScale="1.0"
        android:fromYScale="1.0"
        android:toYScale="1.0"
        android:duration="500"/>
     <alpha xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromAlpha="1.0"
        android:toAlpha="1.0"
        android:duration="500"
        android:startOffset="500" />
</set>
Rohit Singh
quelle