Show DialogFragment with animation growing from a point
Asked Answered
T

10

104

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?

Thirdrate answered 15/11, 2012 at 17:17 Comment(1)
Refer to the link for animations on DialogFragment.Pard
A
196

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.

Arleen answered 24/11, 2012 at 0:33 Comment(8)
Good idea with the multiple animations for different locations on the screen. It's a hack, but it seems to be the only way.Thirdrate
This will only wok with > API 11 @Kiran Babu answer is a work aroundWhoso
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?Anamorphic
Exelent! It is exectly that i have looked for!Plasticize
Setting theme can be as simple as doing setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme) on onCreate(bundle) See: developer.android.com/reference/android/app/DialogFragment.htmlSeng
not work for me, need remove parent="@android:style/Animation.Activity" and style for dialog.Binary
Is there a solution with transition API for 21+?Psyche
your animations are awesome, Is it possible to find more of these xml files (some kind of a library of animations)Entopic
M
140

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;
}
Maite answered 4/4, 2013 at 16:4 Comment(10)
Sorry, this doesn't answer my question at all.Thirdrate
This might not be exactly what the OP is asking for, but it's a good entry point, I think.Barnwell
Excellent example! The only sample that worked for me. Trick is to set animation/theme in onActivityCreated(...) methodPurlieu
This may be useful but it doesn't answer the question at all.Brinton
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?Anamorphic
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?Problem
@Purlieu Why does it not work in onStart()? Why it has to be placed in onActivityCreated()?Charie
Minor adjustment: android:toXDelta="0" should be android:toYDelta="0" in slide up anim.Thingumabob
any one have kotlin equivalent code (for calling)Femi
For anyone wondering in Kotlin you have to set the animation res like this dialog.window.setWindowAnimations(R.style.DialogPop) since dialog.window.attributes.windowAnimations is immutableErr
B
31

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;
    }
}
Burkle answered 10/4, 2015 at 8:51 Comment(3)
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.Keeling
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 thereLiddle
Would you please show the xml code of MyThemeWithCustomAnimation?Alicea
D
14

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());
}
Dahl answered 3/8, 2017 at 23:15 Comment(0)
M
6

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;
}
Mcclees answered 16/12, 2013 at 7:32 Comment(0)
S
4

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();
    }
Stalnaker answered 22/7, 2016 at 22:7 Comment(1)
Best solution in my opinion. It works for AlertDialogs as well, just use it in the onShowListener. Thanks!Corunna
R
4

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

}
Rascally answered 25/8, 2016 at 17:18 Comment(1)
The underlying view does not seem to be clickable afterwardsMukerji
T
4

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.

Thingumabob answered 25/5, 2021 at 16:28 Comment(2)
THANK YOU FOR THIS. I was going insane because it wasn't working. Needed to uninstall the app and reinstall for it to work.Atlantis
Another reason why I hate updating Android Studio. Always a version that's broken. Before update I've never had this issue.Atlantis
Y
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.

Yardage answered 21/11, 2012 at 20:29 Comment(0)
Y
-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;
Yucca answered 10/7, 2020 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.