100

I'm showing a DialogFragment when the user taps on a row in a ListView. I'd like to animate the showing of the dialog so that it grows from the center of the row. A similar effect can be seen when opening a folder from the launcher.

One idea that I've had is a combination of TranslateAnimation and ScaleAnimation. Is there another way?

Edward Dale
  • 28,070
  • 11
  • 84
  • 128
  • 1
    Refer to the [link](https://groups.google.com/forum/?fromgroups=#!topic/android-developers/0oCWqQC4Pww) for animations on DialogFragment. – ASH Nov 23 '12 at 11:58

10 Answers10

184

Being DialogFragment a wrapper for the Dialog class, you should set a theme to your base Dialog to get the animation you want:

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

Then you just need to define the theme that will include your desired animation. In styles.xml add your custom theme:

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

Now add the animation files in the res/anim folder:

( the android:pivotY is the key )

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>

Finally, the tricky thing here is to get your animation grow from the center of each row. I suppose the row is filling the screen horizontally so, on one hand the android:pivotX value will be static. On the other hand, you can't modify the android:pivotY value programmatically.

What I suggest is, you define several animations each of which having a different percentage value on the android:pivotY attribute (and several themes referencing those animations). Then, when the user taps the row, calculate the Y position in percentage of the row on the screen. Knowing the position in percentage, assign a theme to your dialog that has the appropriate android:pivotY value.

It is not a perfect solution but could do the trick for you. If you don't like the result, then I would suggest forgetting the DialogFragment and animating a simple View growing from the exact center of the row.

Good luck!

Xavi Gil
  • 10,764
  • 3
  • 51
  • 67
132

Check it out this code, it works for me

// Slide up animation

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

// Slide dowm animation

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

// Inside Dialog Fragment

@Override
public void onActivityCreated(Bundle arg0) {
    super.onActivityCreated(arg0);
    getDialog().getWindow()
    .getAttributes().windowAnimations = R.style.DialogAnimation;
}
Blundell
  • 69,653
  • 29
  • 191
  • 215
Kiran Babu
  • 1,755
  • 2
  • 12
  • 7
  • 8
    Sorry, this doesn't answer my question at all. – Edward Dale Apr 05 '13 at 09:16
  • 3
    This might not be exactly what the OP is asking for, but it's a good entry point, I think. – mdelolmo Sep 23 '13 at 14:17
  • 3
    Excellent example! The only sample that worked for me. Trick is to set animation/theme in onActivityCreated(...) method – tomurka Sep 01 '14 at 13:51
  • 3
    This may be useful but it doesn't answer the question at all. – Olayinka Dec 15 '14 at 15:15
  • Do you know if there's a possible way to get a callback when these animations are completed? I'd like to do a 2-part animation, one where the dialog slides in, and then fading the views in. How would I attaach a listener to the windowAnimations? – android_student Apr 08 '15 at 22:12
  • I have tried this and it works, but when I change the animation duration I have to do an actual uninstall and reinstall of my app to see my changes take effect. Anyone else had this problem? – lejonl Sep 04 '16 at 11:32
  • @tomurka Why does it not work in `onStart()`? Why it has to be placed in `onActivityCreated()`? – Slazer Nov 28 '20 at 13:31
  • Minor adjustment: android:toXDelta="0" should be android:toYDelta="0" in slide up anim. – Erik Melkersson May 24 '21 at 18:10
27

DialogFragment has a public getTheme() method that you can over ride for this exact reason. This solution uses less lines of code:

public class MyCustomDialogFragment extends DialogFragment{
    ...
    @Override
    public int getTheme() {
        return R.style.MyThemeWithCustomAnimation;
    }
}
Siavash
  • 7,009
  • 10
  • 43
  • 60
  • 1
    No More worries... Simple and straight solution. – Noundla Sandeep Feb 11 '16 at 10:51
  • This's the best answer for me! – superuser Oct 13 '16 at 06:54
  • While not related to the original question, I had a gallery shown in MainAcitvity where user click will activate the slideshow in DialogFragment. There is however a jerk in the MainActivity whenever returning from the slideshow. This is due to MainActivity using `AppTheme.NoActionBar` while the DialogFragment is using the default `AppTheme`. The method above solved my problem by having consistent theme in both fragment and activity. – tingyik90 Jan 12 '18 at 15:05
  • Bro, you are genius – Jacky Chong Feb 05 '18 at 14:51
  • This solution worked for me. However one thing confused me; setting windowEnterAnimation or windowExitAnimation directly in the Theme would make not difference in my DialogFragments animations. The only thing that worked for me was setting windowAnimationStyle to a separate XML file that defined the style and setting the enter and exit animations there – szaske Jun 12 '20 at 22:05
  • Would you please show the xml code of MyThemeWithCustomAnimation? – Oleg Yablokov Jan 17 '21 at 16:11
12

To get a full-screen dialog with animation, write the following ...

Styles:

<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
  • 1,115
  • 12
  • 21
4

In DialogFragment, custom animation is called onCreateDialog. 'DialogAnimation' is custom animation style in previous answer.

public Dialog onCreateDialog(Bundle savedInstanceState) 
{
    final Dialog dialog = super.onCreateDialog(savedInstanceState);
    dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
    return dialog;
}
Brownsoo Han
  • 3,937
  • 3
  • 16
  • 19
3

If you want to work over APIs you have to do inside your DialogFragemnt->onStart and not inside onCreateDialog

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

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

        super.onStart();
    }
Colateral
  • 1,517
  • 13
  • 21
3

Use decor view inside onStart in your dialog fragment

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


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

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

}
Horatio
  • 1,405
  • 1
  • 16
  • 26
1

Have you looked at Android Developers Training on Zooming a View? Might be a good starting point.

You probably want to create a custom class extending DialogFragment to get this working.

Also, take a look at Jake Whartons NineOldAndroids for Honeycomb Animation API compatibility all the way back to API Level 1.

greve
  • 2,471
  • 5
  • 20
  • 31
0

Note: This is just a complement to other answers.

No matter which the solutions you pick you might have the same problem as me.

I need to UNINSTALL the game from my development device before installing the new version for the animation changes to take effect.

I am not sure why but I guess it has to do with the optimized deployment on Android studio not recognizing the changes.

Erik Melkersson
  • 660
  • 5
  • 16
-1

Add this code on values 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"/>

call on styles.xml

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

On java code: set 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 on method:

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