Afficher le DialogFragment avec une animation croissante à partir d'un point


93

J'affiche un DialogFragmentlorsque l'utilisateur appuie sur une ligne dans un ListView. Je voudrais animer l'affichage du dialogue pour qu'il se développe à partir du centre de la ligne. Un effet similaire peut être observé lors de l'ouverture d'un dossier à partir du lanceur.

Une idée que j'ai eue est une combinaison de TranslateAnimationet ScaleAnimation. Y a-t-il un autre moyen?


1
Reportez-vous au lien pour les animations sur DialogFragment.
ASH

Réponses:


168

En tant DialogFragmentque wrapper pour la Dialogclasse, vous devez définir un thème sur votre base Dialogpour obtenir l'animation souhaitée:

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();
    }
}

Ensuite, il vous suffit de définir le thème qui inclura l'animation souhaitée. Dans styles.xml, ajoutez votre thème personnalisé:

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

Ajoutez maintenant les fichiers d'animation dans le dossier res / anim :

( android:pivotYc'est la clé)

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>

Enfin, le plus délicat ici est de faire croître votre animation à partir du centre de chaque ligne. Je suppose que la ligne remplit l'écran horizontalement, donc, d'une part, la android:pivotXvaleur sera statique. En revanche, vous ne pouvez pas modifier la android:pivotYvaleur par programme.

Ce que je suggère, c'est que vous définissiez plusieurs animations ayant chacune une valeur de pourcentage différente sur l' android:pivotYattribut (et plusieurs thèmes référençant ces animations). Ensuite, lorsque l'utilisateur appuie sur la ligne, calculez la position Y en pourcentage de la ligne à l'écran. Connaissant la position en pourcentage, attribuez à votre boîte de dialogue un thème ayant la android:pivotYvaleur appropriée .

Ce n'est pas une solution parfaite mais pourrait faire l'affaire pour vous. Si vous n'aimez pas le résultat, alors je vous suggère d'oublier DialogFragmentet d'animer une simple Viewcroissance à partir du centre exact de la ligne.

Bonne chance!


Bonne idée avec les multiples animations pour différents endroits sur l'écran. C'est un hack, mais cela semble être le seul moyen.
Edward Dale

Cela ne fonctionnera qu'avec> API 11 @Kiran Babu La réponse est une solution
Blundell

Savez-vous s'il existe un moyen possible d'obtenir un rappel lorsque ces animations sont terminées? Je voudrais faire une animation en deux parties, une dans laquelle la boîte de dialogue glisse, puis fondre les vues. Comment attacher un auditeur à windowAnimations?
android_student

Excellent! C'est exactement ce que j'ai recherché!
Aleksey Timoshchenko

2
Le réglage du thème peut être aussi simple que de le faire setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme)sur onCreate(bundle)Voir: developer.android.com/reference/android/app/DialogFragment.html
tropicalfish

117

Vérifiez ce code, cela fonctionne pour moi

// Faire glisser l'animation vers le haut

<?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>

// Animation de diapositives dowm

<?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>

// Style

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

// Fragment de dialogue intérieur

@Override
public void onActivityCreated(Bundle arg0) {
    super.onActivityCreated(arg0);
    getDialog().getWindow()
    .getAttributes().windowAnimations = R.style.DialogAnimation;
}

8
Désolé, cela ne répond pas du tout à ma question.
Edward Dale

3
Ce n'est peut-être pas exactement ce que demande le PO, mais c'est un bon point d'entrée, je pense.
mdelolmo

2
Excellent exemple! Le seul échantillon qui a fonctionné pour moi. L'astuce consiste à définir une animation / un thème dans la méthode onActivityCreated (...)
tomurka

3
Cela peut être utile mais cela ne répond pas du tout à la question.
Olayinka

Savez-vous s'il existe un moyen possible d'obtenir un rappel lorsque ces animations sont terminées? Je voudrais faire une animation en deux parties, une dans laquelle la boîte de dialogue glisse, puis fondre les vues. Comment attacher un auditeur à windowAnimations?
android_student

22

DialogFragment a une méthode publique getTheme () que vous pouvez surcharger pour cette raison exacte. Cette solution utilise moins de lignes de code:

public class MyCustomDialogFragment extends DialogFragment{
    ...
    @Override
    public int getTheme() {
        return R.style.MyThemeWithCustomAnimation;
    }
}

1
Plus de soucis ... Solution simple et directe.
Noundla Sandeep le

C'est la meilleure réponse pour moi!
superutilisateur

Bien que cela ne soit pas lié à la question d'origine, j'avais une galerie affichée dans MainAcitvity où le clic de l'utilisateur activera le diaporama dans DialogFragment. Il y a cependant une secousse dans MainActivity à chaque retour du diaporama. Cela est dû à l'utilisation de MainActivity AppTheme.NoActionBaralors que DialogFragment utilise la valeur par défaut AppTheme. La méthode ci-dessus a résolu mon problème en ayant un thème cohérent à la fois dans le fragment et dans l'activité.
tingyik90

Bro, you are genius
Jacky Chong

Cette solution a fonctionné pour moi. Cependant, une chose m'a confondu; définir windowEnterAnimation ou windowExitAnimation directement dans le thème ne ferait aucune différence dans mes animations DialogFragments. La seule chose qui a fonctionné pour moi a été de définir windowAnimationStyle sur un fichier XML séparé qui définissait le style et y définissait les animations d'entrée et de sortie
szaske

9

Pour obtenir une boîte de dialogue plein écran avec animation, écrivez ce qui suit ...

Modes:

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

Code Java:

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());
}

4

Utilisez la vue décor dans onStart dans votre fragment de dialogue

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


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

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

}

1
La vue sous-jacente ne semble pas être cliquable par la suite
HaydenKai

3

Dans DialogFragment, l'animation personnalisée est appelée onCreateDialog. «DialogAnimation» est un style d'animation personnalisé dans la réponse précédente.

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

1

Avez-vous regardé la formation des développeurs Android sur le zoom d'une vue ? Cela pourrait être un bon point de départ.

Vous souhaitez probablement créer une classe personnalisée étendant DialogFragment pour que cela fonctionne.

Jetez également un œil à la compatibilité de l'API Jake Whartons NineOldAndroids pour Honeycomb Animation jusqu'au niveau 1 de l'API.


1

Si vous voulez travailler sur des API, vous devez le faire dans votre DialogFragemnt-> onStart et non dans onCreateDialog

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

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

        super.onStart();
    }

Meilleure solution à mon avis. Cela fonctionne également pour AlertDialogs, utilisez-le simplement dans onShowListener. Merci!
Gabor Novak

0

Ajouter ce code sur les valeurs anim

 <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"/>

appelez styles.xml

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

Sur le code java: définir Onclick

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

    }

configuration sur la méthode:

alertDialog.getWindow().getAttributes().windowAnimations = type;
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.