Zeigen Sie DialogFragment mit Animationen, die von einem Punkt aus wachsen

92

Ich zeige a, DialogFragmentwenn der Benutzer auf eine Zeile in a tippt ListView. Ich möchte die Darstellung des Dialogfelds so animieren, dass es aus der Mitte der Zeile heraus wächst. Ein ähnlicher Effekt tritt beim Öffnen eines Ordners über den Launcher auf.

Eine Idee, die ich hatte, ist eine Kombination aus TranslateAnimationund ScaleAnimation. Gibt es eine andere Art und Weise?

Edward Dale
quelle
1
Unter dem Link finden Sie Animationen zu DialogFragment.
ASH

Antworten:

168

Als DialogFragmentWrapper für die DialogKlasse sollten Sie ein Thema für Ihre Basis festlegen Dialog, um die gewünschte Animation zu erhalten:

public class CustomDialogFragment extends DialogFragment implements OnEditorActionListener
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) 
    {
        // Set a theme on the dialog builder constructor!
        AlertDialog.Builder builder = 
            new AlertDialog.Builder( getActivity(), R.style.MyCustomTheme );

        builder  
        .setTitle( "Your title" )
        .setMessage( "Your message" )
        .setPositiveButton( "OK" , new DialogInterface.OnClickListener() 
            {      
              @Override
              public void onClick(DialogInterface dialog, int which) {
              dismiss();                  
            }
        });
        return builder.create();
    }
}

Dann müssen Sie nur noch das Thema definieren, das Ihre gewünschte Animation enthält. Fügen Sie in styles.xml Ihr benutzerdefiniertes Thema hinzu:

<style name="MyCustomTheme" parent="@android:style/Theme.Panel">
    <item name="android:windowAnimationStyle">@style/MyAnimation.Window</item>
</style>

<style name="MyAnimation.Window" parent="@android:style/Animation.Activity"> 
    <item name="android:windowEnterAnimation">@anim/anim_in</item>
    <item name="android:windowExitAnimation">@anim/anim_out</item>
</style>    

Fügen Sie nun die Animationsdateien im Ordner res / anim hinzu:

(das android:pivotYist der Schlüssel)

anim_in.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="0.0"
        android:toXScale="1.0"
        android:fromYScale="0.0"
        android:toYScale="1.0"
        android:fillAfter="false"
        android:startOffset="200"
        android:duration="200" 
        android:pivotX = "50%"
        android:pivotY = "-90%"
    />
    <translate
        android:fromYDelta="50%"
        android:toYDelta="0"
        android:startOffset="200"
        android:duration="200"
    />
</set>

anim_out.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="0.0"
        android:fromYScale="1.0"
        android:toYScale="0.0"
        android:fillAfter="false"
        android:duration="200" 
        android:pivotX = "50%"        
        android:pivotY = "-90%"        
    />
    <translate
        android:fromYDelta="0"
        android:toYDelta="50%"
        android:duration="200"
    />
</set>

Schließlich ist es hier schwierig, Ihre Animation aus der Mitte jeder Zeile heraus wachsen zu lassen. Ich nehme an, die Zeile füllt den Bildschirm horizontal aus, sodass der android:pivotXWert einerseits statisch ist. Andererseits können Sie den android:pivotYWert nicht programmgesteuert ändern .

Ich schlage vor, Sie definieren mehrere Animationen, von denen jede einen anderen Prozentwert für das android:pivotYAttribut hat (und mehrere Themen, die auf diese Animationen verweisen). Wenn der Benutzer auf die Zeile tippt, berechnen Sie die Y-Position in Prozent der Zeile auf dem Bildschirm. Wenn Sie die Position in Prozent kennen, weisen Sie Ihrem Dialogfeld ein Thema mit dem entsprechenden android:pivotYWert zu.

Es ist keine perfekte Lösung, könnte aber den Trick für Sie tun. Wenn Ihnen das Ergebnis nicht gefällt, würde ich vorschlagen, das DialogFragmenteinfache ViewWachsen von der exakten Mitte der Reihe aus zu vergessen und zu animieren .

Viel Glück!

Xavi Gil
quelle
Gute Idee mit den mehreren Animationen für verschiedene Orte auf dem Bildschirm. Es ist ein Hack, aber es scheint der einzige Weg zu sein.
Edward Dale
Dies wird nur mit> API 11 @Kiran Babu Antwort Wok ist eine Problemumgehung
Blundell
Wissen Sie, ob es eine Möglichkeit gibt, einen Rückruf zu erhalten, wenn diese Animationen abgeschlossen sind? Ich möchte eine zweiteilige Animation erstellen, in der der Dialog eingeblendet und dann die Ansichten ausgeblendet werden. Wie würde ich einen Listener an windowAnimations anhängen?
android_student
Hervorragend! Es ist genau das, wonach ich gesucht habe!
Aleksey Timoshchenko
2
Das Einstellen des Themas kann so einfach sein wie setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme)unter onCreate(bundle)Siehe: developer.android.com/reference/android/app/DialogFragment.html
tropicalfish
117

Schauen Sie sich diesen Code an, er funktioniert bei mir

// Animation nach oben schieben

<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromYDelta="100%"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toXDelta="0" />

</set>

// Dowm Animation schieben

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromYDelta="0%p"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toYDelta="100%p" />

</set>

// Stil

<style name="DialogAnimation">
    <item name="android:windowEnterAnimation">@anim/slide_up</item>
    <item name="android:windowExitAnimation">@anim/slide_down</item>
</style>

// Innerhalb des Dialogfragments

@Override
public void onActivityCreated(Bundle arg0) {
    super.onActivityCreated(arg0);
    getDialog().getWindow()
    .getAttributes().windowAnimations = R.style.DialogAnimation;
}
Kiran Babu
quelle
8
Entschuldigung, das beantwortet meine Frage überhaupt nicht.
Edward Dale
3
Dies ist vielleicht nicht genau das, was das OP verlangt, aber es ist ein guter Einstiegspunkt, denke ich.
Mdelolmo
2
Exzellentes Beispiel! Die einzige Probe, die für mich funktioniert hat. Trick ist, Animation / Thema in onActivityCreated (...) Methode
Tomurka
3
Dies mag nützlich sein, beantwortet aber die Frage überhaupt nicht.
Olayinka
Wissen Sie, ob es eine Möglichkeit gibt, einen Rückruf zu erhalten, wenn diese Animationen abgeschlossen sind? Ich möchte eine zweiteilige Animation erstellen, in der der Dialog eingeblendet und dann die Ansichten ausgeblendet werden. Wie würde ich einen Listener an windowAnimations anhängen?
android_student
22

DialogFragment verfügt über eine öffentliche getTheme () -Methode, die Sie aus genau diesem Grund überschreiben können. Diese Lösung verwendet weniger Codezeilen:

public class MyCustomDialogFragment extends DialogFragment{
    ...
    @Override
    public int getTheme() {
        return R.style.MyThemeWithCustomAnimation;
    }
}
Siavash
quelle
1
Keine Sorgen mehr ... Einfache und direkte Lösung.
Noundla Sandeep
Das ist die beste Antwort für mich!
Superuser
Obwohl dies nicht mit der ursprünglichen Frage zusammenhängt, wurde in MainAcitvity eine Galerie angezeigt, in der durch Klicken des Benutzers die Diashow in DialogFragment aktiviert wird. Es gibt jedoch einen Ruck in der MainActivity, wenn Sie von der Diashow zurückkehren. Dies liegt an der Verwendung von MainActivity, AppTheme.NoActionBarwährend das DialogFragment die Standardeinstellung verwendet AppTheme. Die obige Methode löste mein Problem, indem sie sowohl in Fragmenten als auch in Aktivitäten ein einheitliches Thema hatte.
Tingyik90
Bro, du bist ein Genie
Jacky Chong
Diese Lösung hat bei mir funktioniert. Eines verwirrte mich jedoch; Das Festlegen von windowEnterAnimation oder windowExitAnimation direkt im Design würde in meinen DialogFragments-Animationen keinen Unterschied machen. Das einzige, was für mich funktioniert hat, war, windowAnimationStyle auf eine separate XML-Datei festzulegen, die den Stil definiert und die
Eingangs-
9

Um einen Vollbilddialog mit Animation zu erhalten, schreiben Sie Folgendes ...

Stile:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="actionModeBackground">?attr/colorPrimary</item>
    <item name="windowActionModeOverlay">true</item>
</style>

<style name="AppTheme.NoActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
</style>

<style name="AppTheme.NoActionBar.FullScreenDialog">
    <item name="android:windowAnimationStyle">@style/Animation.WindowSlideUpDown</item>
</style>

<style name="Animation.WindowSlideUpDown" parent="@android:style/Animation.Activity">
    <item name="android:windowEnterAnimation">@anim/slide_up</item>
    <item name="android:windowExitAnimation">@anim/slide_down</item>
</style>

res / anim / slide_up.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:interpolator/accelerate_quad">

    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="100%"
        android:toYDelta="0%"/>
</set>

res / anim / slide_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:interpolator/accelerate_quad">

    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="0%"
        android:toYDelta="100%"/>
</set>

Java-Code:

public class MyDialog extends DialogFragment {

    @Override
    public int getTheme() {
        return R.style.AppTheme_NoActionBar_FullScreenDialog;
    }
}

private void showDialog() {
    FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
    Fragment previous = getSupportFragmentManager().findFragmentByTag(MyDialog.class.getName());
    if (previous != null) {
        fragmentTransaction.remove(previous);
    }
    fragmentTransaction.addToBackStack(null);

    MyDialog dialog = new MyDialog();
    dialog.show(fragmentTransaction, MyDialog.class.getName());
}
maXp
quelle
4

Verwenden Sie die Dekoransicht in onStart in Ihrem Dialogfragment

@Override
public void onStart() {
    super.onStart();


    final View decorView = getDialog()
            .getWindow()
            .getDecorView();

    decorView.animate().translationY(-100)
            .setStartDelay(300)
            .setDuration(300)
            .start();

}
Horatio
quelle
1
Die zugrunde liegende Ansicht scheint danach nicht anklickbar zu sein
HaydenKai
3

In DialogFragment heißt die benutzerdefinierte Animation onCreateDialog. 'DialogAnimation' ist ein benutzerdefinierter Animationsstil in der vorherigen Antwort.

public Dialog onCreateDialog(Bundle savedInstanceState) 
{
    final Dialog dialog = super.onCreateDialog(savedInstanceState);
    dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
    return dialog;
}
Brownsoo Han
quelle
1

Haben Sie sich das Android-Entwicklertraining zum Zoomen einer Ansicht angesehen ? Könnte ein guter Ausgangspunkt sein.

Sie möchten wahrscheinlich eine benutzerdefinierte Klasse erstellen, die erweitert wird DialogFragment, damit dies funktioniert.

Schauen Sie sich auch Jake Whartons NineOldAndroids für Honeycomb Animation API-Kompatibilität bis hin zu API Level 1 an.

Greve
quelle
0

Wenn Sie über APIs arbeiten möchten, müssen Sie dies in Ihrem DialogFragemnt-> onStart und nicht in onCreateDialog tun

@Override
    public void onStart() 
    {
        if (getDialog() == null) 
        {
            return;
        }

        getDialog().getWindow().setWindowAnimations(
                  R.style.DlgAnimation);

        super.onStart();
    }
Colateral
quelle
Beste Lösung meiner Meinung nach. Es funktioniert auch für AlertDialogs. Verwenden Sie es einfach im onShowListener. Vielen Dank!
Gabor Novak
0

Die Lösung von Colateral hat bei mir funktioniert. Ich habe jedoch ein nerviges Problem mit der Animation festgestellt: Sie wurde nicht nur abgespielt, als mein Dialog erstellt und zerstört wurde, sondern auch, wenn die App in den Hintergrund und aus dem Hintergrund geriet (dh alle onStart()und onStop()).

Achten Sie zunächst auf die Unterscheidung zwischen

window.attributes.windowAnimations = R.style.CustomDialogAnimation

und

window.setWindowAnimations(R.style.CustomAnimation)

Letzterer ändert nicht nur das Attribut, sondern löst auch die Änderung aus. Nur das Ändern des Attributs allein hat keine Auswirkungen, nachdem Ihr Dialog erstellt wurde.

Hier ist meine (nicht ganz elegante) Herangehensweise an das Problem mit redundanten Animationen:

override fun onStart() {
    super.onStart()

    enableWindowAnimations()
    view?.post {
        disableWindowAnimation()
    }
}

override fun dismiss() {
    enableWindowAnimations()
    view?.post {
        super.dismiss()
    }
}

private fun enableWindowAnimations() {
    dialog
        ?.window
        ?.setWindowAnimations(R.style.CustomAnimation)
}

private fun disableWindowAnimation() {
    dialog
        ?.window
        ?.setWindowAnimations(0)
}

Eine andere Lösung besteht darin, alles zu windowAnimationsentfernen und zu animieren window.decorView, wie hier beschrieben . Dadurch haben Sie mehr Kontrolle über Ihre Animationen.

SqueezyMo
quelle
0

Fügen Sie diesen Code in die Werteanimation ein

 <scale
    android:duration="@android:integer/config_longAnimTime"
    android:fromXScale="0.2"
    android:fromYScale="0.2"
    android:toXScale="1.0"
    android:toYScale="1.0"
    android:pivotX="50%"
    android:pivotY="50%"/>
<alpha
    android:fromAlpha="0.1"
    android:toAlpha="1.0"
    android:duration="@android:integer/config_longAnimTime"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"/>

Rufen Sie styles.xml auf

<style name="DialogScale">
    <item name="android:windowEnterAnimation">@anim/scale_in</item>
    <item name="android:windowExitAnimation">@anim/scale_out</item>
</style>

Bei Java-Code: Setzen Sie Onclick

public void onClick(View v) {
        fab_onclick(R.style.DialogScale, "Scale" ,(Activity) context,getWindow().getDecorView().getRootView());
      //  Dialogs.fab_onclick(R.style.DialogScale, "Scale");

    }

Setup auf Methode:

alertDialog.getWindow().getAttributes().windowAnimations = type;
Mue
quelle