Android碎片和动画

277

如何实现类似蜂巢Gmail客户端所使用的滑动效果?

TransactionManager是否可以自动处理添加和删除碎片以实现此功能? 由于模拟器是幻灯片,因此测试这一点有些困难 :)

6个回答

395

要想在片段之间实现过渡动画,或者在显示或隐藏片段的过程中实现动画效果,您可以使用Fragment Manager创建Fragment Transaction

在每个Fragment Transaction中,您可以指定用于显示和隐藏的进入和退出动画(或在使用替换时同时使用两者)。

下面的代码演示了如何通过向外滑出一个片段并将另一个片段滑入其位置来替换一个片段:

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();
为了使用隐藏或显示片段实现相同的效果,只需调用ft.showft.hide,分别传入您希望显示或隐藏的Fragment即可。
参考资料,XML动画定义将使用objectAnimator标签。slide_in_left的示例可能如下所示:
<?xml version="1.0" encoding="utf-8"?>
<set>
  <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="x" 
    android:valueType="floatType"
    android:valueFrom="-1280"
    android:valueTo="0" 
    android:duration="500"/>
</set>

58
尝试过程中出现了RuntimeException: Unknown animator name: translate的提示。 - Labeeb Panampullan
3
确保在slide_in_left和slide_in_right中定义的动画是使用一组objectAnimator定义构建的,而不是旧动画定义方式。 - Reto Meier
7
非常有帮助。我原本就在正确的方向上,只是没有完全到位。对于其他读者,你还可以将android:interpolator作为属性,并指定你喜欢的插值器(比如“@android:interpolator/linear”)。默认值为“@android:interpolator/accelerate_decelerate”。 - Dave MacLean
6
我将使用兼容性API针对API Level 7。是否有一种方法可以为fragments添加动画效果? - Jarrod Smith
5
你可以尝试使用兼容库(例如NineOldAndroids)将Honeycomb API带到Eclair的级别。 - Mr. S
显示剩余13条评论

259

如果您不必使用支持库,请参考Roman的答案

但是,如果您想要使用支持库,则必须使用下面描述的旧动画框架。

在咨询了Reto的答案blindstuff的答案之后,我已经使以下代码工作正常。

片段会从右侧滑入并在按下“返回”时向左滑出

FragmentManager fragmentManager = getSupportFragmentManager();

FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit);

CustomFragment newCustomFragment = CustomFragment.newInstance();
transaction.replace(R.id.fragment_container, newCustomFragment );
transaction.addToBackStack(null);
transaction.commit();

顺序很重要。这意味着您必须在调用replace()之前调用setCustomAnimations(),否则动画将不会生效!

接下来,这些文件必须放置在res/anim文件夹中。

enter.xml:

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

exit.xml:

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="-100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_enter.xml:

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="-100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_exit.xml:

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>
动画的持续时间可以更改为任何默认值,例如@android:integer/config_shortAnimTime或其他数字。

请注意,在片段替换之间发生配置更改(例如旋转)时,返回操作不会有动画效果。这是一个已记录的错误,仍然存在于支持库的rev 20中。详见链接


50
这真的帮了我大忙。注意,顺序很重要,而我第一次自然而然地错过了。这意味着你必须在调用replace()之前先调用setCustomAnimations()。 - Stephen Kidson
3
我尝试在我的片段上实现。我按照您提到的一切编写了代码,但是logcat显示:未知的动画名称translate。我该如何解决这个问题?顺便说一句,我是在导航抽屉(滑动菜单)上调用我的片段的。 - Zafer Celaloglu
很棒的解决方案,当我按下返回按钮时它非常有效。我只有一个问题:如果我想创建一个自定义的返回按钮,我应该调用什么代码来复制返回按钮的行为? - Teilmann
1
如果你想要返回,你应该实现这个表单:.setCustomAnimations(R.anim.pop_enter, R.anim.pop_exit, R.anim.enter, R.anim.exit)。 - Alex Zaraos
很棒的答案..!! 运行正常 - Arunjith R S
显示剩余2条评论

28

我强烈建议您使用这个而不是创建动画文件,因为这是一个更好的解决方案。Android Studio已经提供了一些默认animation可以使用,而无需创建任何新的XML文件。这些动画的名称是android.R.anim.slide_in_leftandroid.R.anim.slide_out_right,您可以按照以下方式使用它们:

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

输出:

输入图像说明


1
"Android Studio提供默认动画",但这不仅适用于Android Studio,也可以在Eclipse中使用。android.R是专门针对Android的。顺便说一下,您没有分享此API具有哪些信息。因为android.R上的内容在不同的API上是不同的。 - Steve Moretz
@stevemoretz 谢谢兄弟,我同意你的观点。我会修正并更新我的答案。 - Gowthaman M

5
我的修改版支持库可以同时使用视图动画(即<translate>, <rotate>)和对象动画(即<objectAnimator>)来实现片段转换。它是使用NineOldAndroids实现的。请参阅我在 GitHub 上的文档以获取详细信息。

2

就我而言,我需要视图方向:

进入 -> 从右侧滑动

退出 -> 向左侧滑动

这里是适用于我的代码:

slide_in_right.xml

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

slide_out_left.xml

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

交易代码:

inline fun FragmentActivity.setContentFragment(
        containerViewId: Int,
        backStack: Boolean = false,
        isAnimate: Boolean = false,
        f: () -> Fragment

): Fragment? {
    val manager = supportFragmentManager
    return f().apply {
        manager.beginTransaction().let {
            if (isAnimate)
                it.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)

            if (backStack) {
                it.replace(containerViewId, this, "Fr").addToBackStack("Fr").commit()
            } else {
                it.replace(containerViewId, this, "Fr").commit()
            }
        }
    }
}

1
Android似乎在那些动画(特别是平移动画)中闪烁转换。 - Gabriel Rohden
@GabrielDeOliveiraRohden 对我来说,并非所有情况都是如此。 - Serg Burlaka

0

我以下面的方式解决了这个问题

Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide);
fg.startAnimation(anim);
this.fg.setVisibility(View.VISIBLE); //fg is a View object indicate fragment

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接