【问题标题】:Show DialogFragment with animation growing from a point显示 DialogFragment 动画从一个点开始
【发布时间】:2012-11-04 08:43:16
【问题描述】:

当用户点击ListView 中的一行时,我会显示DialogFragment。我想为对话框的显示设置动画,使其从行的中心开始增长。从启动器打开文件夹时可以看到类似的效果。

我的一个想法是TranslateAnimationScaleAnimation 的组合。还有其他方法吗?

【问题讨论】:

  • 有关 DialogFragment 上的动画,请参阅 link

标签: android android-fragments android-animation


【解决方案1】:

作为DialogFragmentDialog 类的包装器,您应该为基础Dialog 设置一个主题以获得您想要的动画:

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

然后您只需要定义包含所需动画的主题即可。在 styles.xml 中添加您的自定义主题:

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

现在在 res/anim 文件夹中添加动画文件:

android:pivotY 是关键)

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>

最后,棘手的事情是让您的动画从每行的中心开始增长。我想该行水平填充屏幕,所以一方面android:pivotX 值将是静态的。另一方面,您不能以编程方式修改android:pivotY 值。

我的建议是,您定义几个动画,每个动画在 android:pivotY 属性上具有不同的百分比值(以及引用这些动画的几个主题)。然后,当用户点击该行时,以屏幕上该行的百分比计算 Y 位置。知道百分比位置后,为您的对话框分配一个主题,该主题具有适当的android:pivotY 值。

这不是一个完美的解决方案,但可以为您解决问题。如果您不喜欢结果,那么我建议您忘记 DialogFragment 并为从行的确切中心生长的简单 View 设置动画。

祝你好运!

【讨论】:

  • 屏幕上不同位置的多个动画的好主意。这是一个 hack,但它似乎是唯一的方法。
  • 这只适用于 > API 11 @Kiran Babu 答案是一种解决方法
  • 你知道这些动画完成后是否有可能获得回调的方法吗?我想做一个两部分的动画,一个对话框滑入,然后淡入视图。如何将侦听器附加到 windowAnimations?
  • 非常棒!正是我一直在寻找的!
  • 设置主题可以像在onCreate(bundle)上做setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme)一样简单参见:developer.android.com/reference/android/app/DialogFragment.html
【解决方案2】:

看看这段代码,它对我有用

//上滑动画

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

// 幻灯片动画

<?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 name="DialogAnimation">
    <item name="android:windowEnterAnimation">@anim/slide_up</item>
    <item name="android:windowExitAnimation">@anim/slide_down</item>
</style>

// 对话片段内部

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

【讨论】:

  • 对不起,这根本不能回答我的问题。
  • 这可能不是 OP 所要求的,但我认为这是一个很好的切入点。
  • 很好的例子!唯一对我有用的样本。技巧是在 onActivityCreated(...) 方法中设置动画/主题
  • 这可能有用,但根本无法回答问题。
  • 你知道这些动画完成后是否有可能获得回调的方法吗?我想做一个两部分的动画,一个对话框滑入,然后淡入视图。如何将侦听器附加到 windowAnimations?
【解决方案3】:

DialogFragment 有一个公共的 getTheme() 方法,您可以出于这个确切原因覆盖该方法。此解决方案使用的代码行数更少:

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

【讨论】:

  • 不用担心...简单直接的解决方案。
  • 这对我来说是最好的答案!
  • 虽然与原始问题无关,但我在 MainAcitvity 中显示了一个画廊,用户单击该画廊将激活 DialogFragment 中的幻灯片。然而,每当从幻灯片返回时,MainActivity 中都会出现一个混蛋。这是由于 MainActivity 使用 AppTheme.NoActionBar 而 DialogFragment 使用默认的 AppTheme。上面的方法通过在片段和活动中保持一致的主题解决了我的问题。
  • 兄弟,你是天才
  • 这个解决方案对我有用。然而,有一件事让我感到困惑;直接在主题中设置 windowEnterAnimation 或 windowExitAnimation 不会对我的 DialogFragments 动画产生影响。唯一对我有用的是将 windowAnimationStyle 设置为一个单独的 XML 文件,该文件定义了样式并在那里设置进入和退出动画
【解决方案4】:

要获得带有动画的全屏对话框,请编写以下内容...

样式:

<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 代码:

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

【讨论】:

    【解决方案5】:

    在DialogFragment中,自定义动画被称为onCreateDialog。 'DialogAnimation' 是上一个答案中的自定义动画样式。

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

    【讨论】:

      【解决方案6】:

      在对话框片段的 onStart 中使用装饰视图

      @Override
      public void onStart() {
          super.onStart();
      
      
          final View decorView = getDialog()
                  .getWindow()
                  .getDecorView();
      
          decorView.animate().translationY(-100)
                  .setStartDelay(300)
                  .setDuration(300)
                  .start();
      
      }
      

      【讨论】:

      • 之后底层视图似乎不可点击
      【解决方案7】:

      如果你想处理 API,你必须在 DialogFragemnt->onStart 内部而不是在 onCreateDialog 内部进行

      @Override
          public void onStart() 
          {
              if (getDialog() == null) 
              {
                  return;
              }
      
              getDialog().getWindow().setWindowAnimations(
                        R.style.DlgAnimation);
      
              super.onStart();
          }
      

      【讨论】:

      • 我认为最好的解决方案。它也适用于 AlertDialogs,只需在 onShowListener 中使用它。谢谢!
      【解决方案8】:

      注意:这只是对其他答案的补充。

      无论您选择哪种解决方案,您都可能遇到与我相同的问题。

      我需要在安装新版本之前从我的开发设备卸载游戏,以使动画更改生效。

      我不知道为什么,但我想这与 Android Studio 上的优化部署没有识别更改有关。

      【讨论】:

      • 谢谢你。我快疯了,因为它不起作用。需要卸载应用程序并重新安装才能正常工作。
      • 我讨厌更新 Android Studio 的另一个原因。总是一个坏掉的版本。在更新之前我从来没有遇到过这个问题。
      【解决方案9】:

      您看过Zooming a View 上的 Android 开发人员培训吗?可能是一个很好的起点。

      您可能希望创建一个扩展 DialogFragment 的自定义类以使其正常工作。

      此外,请查看 Jake Whartons NineOldAndroids,了解 Honeycomb Animation API 与 API 级别 1 的兼容性。

      【讨论】:

        【解决方案10】:

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

        调用styles.xml

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

        在 java 代码上:设置 Onclick

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

        设置方法:

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

        【讨论】:

          最近更新 更多