web-dev-qa-db-fra.com

Montrer DialogFragment avec l'animation grandissant d'un point

Je montre une DialogFragment lorsque l'utilisateur appuie sur une ligne dans une ListView. J'aimerais animer l'affichage du dialogue afin qu'il croisse à 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 eu est une combinaison de TranslateAnimation et ScaleAnimation. Y a-t-il un autre moyen?

80
scompt.com

Étant DialogFragment un wrapper pour la classe Dialog, vous devez définir un thème pour votre Dialogde base pour 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>    

Maintenant, ajoutez les fichiers d'animation dans le res/anim dossier:

(le Android:pivotY 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 difficile est de faire en sorte que votre animation grandisse à partir du centre de chaque rangée. Je suppose que la ligne remplit l'écran horizontalement, donc, d'une part, la valeur Android:pivotX sera statique. D'autre part, vous ne pouvez pas modifier la valeur Android:pivotY par programme. 

Je suggère que vous définissiez plusieurs animations ayant chacune une valeur de pourcentage différente sur l'attribut Android:pivotY (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 qui possède la valeur Android:pivotY appropriée.

Ce n'est pas une solution parfaite mais pourrait faire l'affaire pour vous. Si vous n'aimez pas le résultat, je suggérerais alors d'oublier la DialogFragment et d'animer une simple View croissant du centre exact de la ligne.

Bonne chance!

145
Xavi Gil

Regardez ce code, ça marche pour moi

// animation de diapositives

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

// Diapositive d'animation 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 à l'intérieur

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

DialogFragment a une méthode publique getTheme () que vous pouvez utiliser 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;
    }
}
19
Siavash

Pour obtenir un 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());
}
7
maXp

Utilisez la vue de décor dans onStart dans votre fragment de boîte de dialogue. 

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


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

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

}
2
Horatio

Dans DialogFragment, une 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;
}
2
Brownsoo Han

Avez-vous examiné Formation des développeurs Android sur Zoomer sur une vue ? Peut-être un bon point de départ.

Vous voulez probablement créer une classe personnalisée qui étend DialogFragment pour que cela fonctionne.

Consultez également Jake Whartons NineOldAndroids pour la compatibilité de l'API Honeycomb Animation jusqu'au niveau 1 de l'API.

1
greve

Si vous souhaitez utiliser 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();
    }
0
Colateral