显示动画从一个点生长的对话框片段

当用户点击 ListView中的一行时,我将显示一个 DialogFragment。我想动画显示的对话框,以便它从行的中心增长。从启动程序打开文件夹时,也可以看到类似的效果。

我有一个想法就是将 TranslateAnimationScaleAnimation结合起来。还有别的办法吗?

117198 次浏览

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.

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!

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

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

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

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

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


}

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

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;

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.