【问题标题】:Animate the transition between fragments动画片段之间的过渡
【发布时间】:2011-06-23 09:06:04
【问题描述】:

我正在尝试为片段之间的过渡设置动画。我从以下得到了答案
Android Fragments and animation

FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);

DetailsFragment newFragment = DetailsFragment.newInstance();

ft.replace(R.id.details_fragment_container, newFragment, "detailFragment");

// Start the animated transition.
ft.commit();

还有我的 R.anim.slide_in_left

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate android:fromXDelta="50%p" android:toXDelta="0"
            android:duration="@android:integer/config_mediumAnimTime"/>
       <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
            android:duration="@android:integer/config_mediumAnimTime" />
</set>

但是当我尝试这个时它显示了

02-08 16:27:37.961: ERROR/AndroidRuntime(1717): FATAL EXCEPTION: main
02-08 16:27:37.961: ERROR/AndroidRuntime(1717): java.lang.RuntimeException: Unknown animator name: translate
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:129)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:126)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:93)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.loadAnimator(AnimatorInflater.java:72)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.loadAnimator(FragmentManager.java:621)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:733)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:919)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.BackStackRecord.run(BackStackRecord.java:578)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1217)

有什么想法吗?当我检查 Honeycomb API 参考 translate 时。我错过了什么?
有没有其他方法可以动画片段之间的过渡? 谢谢你

【问题讨论】:

  • 使用 ANIMATOR --- 不是动画!使用 android.R.ANIMATOR.fade_in 有效,不要使用 android.R.ANIM.fade_in - 它有行为错误

标签: android android-3.0-honeycomb


【解决方案1】:

您需要将新的android.animation 框架(对象动画师)与FragmentTransaction.setCustomAnimations 以及FragmentTransaction.setTransition 一起使用。

这是使用 ApiDemos 的 FragmentHideShow.java 中的setCustomAnimations 的示例:

ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);

这是来自 res/animator/fade_in.xml 的相关动画 XML:

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:interpolator/accelerate_quad"
    android:valueFrom="0"
    android:valueTo="1"
    android:propertyName="alpha"
    android:duration="@android:integer/config_mediumAnimTime" />

请注意,您可以使用 &lt;set&gt; 组合多个动画师,就像使用旧动画框架一样。


编辑:由于人们在询问滑入/滑出,我将在这里对此发表评论。

滑入和滑出

您当然可以为translationXtranslationYxy 属性设置动画,但通常幻灯片涉及在屏幕外设置动画内容。据我所知,没有任何使用相对值的转换属性。但是,这并不妨碍您自己编写它们。请记住,属性动画只需要您正在制作动画的对象(在本例中为视图)上的 getter 和 setter 方法,因此您可以在视图子类上创建自己的 getXFractionsetXFraction 方法,像这样:

public class MyFrameLayout extends FrameLayout {
    ...
    public float getXFraction() {
        return getX() / getWidth(); // TODO: guard divide-by-zero
    }

    public void setXFraction(float xFraction) {
        // TODO: cache width
        final int width = getWidth();
        setX((width > 0) ? (xFraction * width) : -9999);
    }
    ...
}

现在您可以为“xFraction”属性设置动画,如下所示:

res/animator/slide_in.xml

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator"
    android:valueFrom="-1.0"
    android:valueTo="0"
    android:propertyName="xFraction"
    android:duration="@android:integer/config_mediumAnimTime" />

请注意,如果您在其中制作动画的对象与其父对象的宽度不同,事情看起来就会不太正确,因此您可能需要调整属性实现以适合您的用例。

【讨论】:

  • 我让淡入和淡出工作,但 /res/animator 中的其他人给出错误。而且这些似乎都不是用于滑入和滑出的。我试图编写自己的 xml 来做到这一点,但我最终得到的只是片段之上的片段。请提供更多帮助?
  • 那翻译呢?请问如何用 XML 中定义的 objectAnimator 中的百分比值进行翻译?在使用 xml 中定义的垂直滑动动画翻转期间,我没有成功地为 AdapterViewFlipper 设置动画...
  • 我得到 11-19 10:27:50.912: W/PropertyValuesHolder(23107): 在目标类类 android.widget.FrameLayout 上找不到类型为 float 的方法 setXFraction()。但在我的 XML 中,我有我的自定义视图 MyFrameLayout。有什么想法吗?
  • 其实,Roman,建议也应该反过来:使用支持库时,需要使用旧动画框架(android.R.anim)和 FragmentTransaction.setCustomAnimations ao
  • @RomanNurik 这个答案在大多数设备上运行良好,但对于某些用户(特别是在某些三星 Galaxy S3/4 手机上)由于某种原因在动画期间没有报告宽度,导致片段永远不会出现。我能够使用 OnPredrawListener 为那些用户工作,如下所示:mavyasoni9891.blogspot.com/2014/06/…
【解决方案2】:

我是这样做的:

添加这个方法动画替换片段

public void replaceFragmentWithAnimation(android.support.v4.app.Fragment fragment, String tag){
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
    transaction.replace(R.id.fragment_container, fragment);
    transaction.addToBackStack(tag);
    transaction.commit();
}

您必须在 anim 文件夹中添加 四个动画,该文件夹关联resource强>:

enter_from_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="-100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

exit_to_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

enter_from_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

exit_to_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="-100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

输出:

完成

【讨论】:

  • 很好的解决方案。但是我不确定您为什么将方向交换到 RTL。我的方法:.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)
  • 很棒的解决方案。类似的方法和相同的动画文件适用于活动之间的转换。
  • @MikeZriel, res -> 动画 -> 把你的 xml 放在这里
  • 感谢 Hiren,我将速度 (700) 更改为 (300) 更好,更像 iOS
  • 大声笑,我带着解决方案回来了。我在每个 java 类上导入了 android.app.fragment 和 FragmentManager。检查了一些资料后,我发现使用 'setCustomAnimations()' 需要导入 android.support.v4 库。重要的是说应该是'support.v4.app'!我将所有方法 'getFragmentManager()' 替换为 'getSupportFragmentManager()',并将所有导入 'android.app.Fragment/FragmentManager...' 替换为 'android.support.v4.app....',然后这个动画开始运行良好而没有崩溃......如果你们陷入类似的情况,请阅读我的解决方案。谢谢 Hiren Patel xD
【解决方案3】:

如果您有能力将自己绑在 Lollipop 和以后,这似乎可以解决问题:

import android.transition.Slide;
import android.util.Log;
import android.view.Gravity;
.
.
.
f = new MyFragment();
f.setEnterTransition(new Slide(Gravity.END));
f.setExitTransition(new Slide(Gravity.START));
getFragmentManager()
    .beginTransaction()
    .replace(R.id.content, f, FRAG_TAG)  // FRAG_TAG is the tag for your fragment
    .commit();

Kotlin 版本:

f = MyFragment().apply {
    enterTransition = Slide(Gravity.END)
    exitTransition = Slide(Gravity.START)
}
fragmentManager
    .beginTransaction()
    .replace(R.id.content, f, FRAG_TAG)  // FRAG_TAG is the tag for your fragment
    .commit();

希望这会有所帮助。

【讨论】:

  • 虽然这将在 Lollipop 上实现,但几乎不实用,因为运行 Lollipop 的设备的百分比可以忽略不计(目前 1.6% 的 Android 设备运行 Lollipop)。
  • new Slide(...) : 调用需要 API 级别 21
  • @EranGoldin 没有什么是永恒的......你会嘲笑今天只有 Android 2.0+ 的解决方案吗?
  • 只需使用支持库就可以像魅力一样在 API 16 上工作。
  • 天啊!我不敢相信我以前没有使用过这个,看起来它适用于一些物理!非常感谢@Scorpiodawg!
【解决方案4】:

Nurik 的回答非常有帮助,但直到找到this 后我才能让它工作。简而言之,如果您使用的是兼容性库(例如 SupportFragmentManager 而不是 FragmentManager),则 XML 动画文件的语法会有所不同。

【讨论】:

    【解决方案5】:

    这是片段之间的滑入/滑出动画:

    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.setCustomAnimations(R.animator.enter_anim, R.animator.exit_anim);
    transaction.replace(R.id.listFragment, new YourFragment());
    transaction.commit();
    

    我们正在使用 objectAnimator。

    这是 animator 子文件夹中的两个 xml 文件。

    enter_anim.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set>
         <objectAnimator
             xmlns:android="http://schemas.android.com/apk/res/android"
             android:duration="1000"
             android:propertyName="x"
             android:valueFrom="2000"
             android:valueTo="0"
             android:valueType="floatType" />
    </set>
    

    exit_anim.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set>
        <objectAnimator
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:duration="1000"
            android:propertyName="x"
            android:valueFrom="0"
            android:valueTo="-2000"
            android:valueType="floatType" />
    </set>
    

    我希望这会对某人有所帮助。

    【讨论】:

    • 将视图移动 2000 像素,是一个非常丑陋的解决方案。
    • exit_anim 对我来说只是“弹出”屏幕,它不会在屏幕上重新设置动画。有任何想法吗?我正在使用.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)
    • @MrPablo,原因可能是您没有复制粘贴上面的代码。 setCustomAnimations 应该在 replace 方法之前调用。
    • 在这种情况下,如果我用动画替换其他片段并且我在动画超时或持续时间之前立即最小化应用程序并再次返回应用程序,它将显示前一个片段和当前片段并行。
    【解决方案6】:

    对于被抓到的任何其他人,请确保在构建事务时调用替换/添加之前调用 setCustomAnimations。

    【讨论】:

      【解决方案7】:

      尝试使用这个简单快速的解决方案。 Android 提供了一些默认的animations。

      fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
      

      FragmentManager fragmentManager = getSupportFragmentManager();
      FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
      fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
      fragmentManager.addOnBackStackChangedListener(this);
      fragmentTransaction.replace(R.id.frame, firstFragment, "h");
      fragmentTransaction.addToBackStack("h");
      fragmentTransaction.commit();
      

      输出:

      【讨论】:

      • 哇......这应该是公认的答案!一个简单而优雅的解决方案。与其他建议的答案相比,它非常流畅
      【解决方案8】:

      Android SDK 的 FragmentTransaction 实现需要一个 Animator,而支持库需要一个 Animation,不要问我为什么,但在奇怪的评论之后,我查看了 android 4.0.3 代码和支持库。 Android SDK使用loadAnimator(),支持库使用loadAnimation()

      【讨论】:

        【解决方案9】:

        为了给这个老问题添加一个更现代的答案,如果你已经转向 Material Design,这可以很容易地使用提供的动作库来完成——更多详细信息请访问https://material.io/develop/android/theming/motion

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-05-16
          • 2020-09-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多