【发布时间】:2011-06-16 14:48:18
【问题描述】:
您应该如何实现例如 Honeycomb Gmail 客户端使用的那种滑动?
TransactionManager 可以通过添加和删除 Fragments 来自动处理这个问题,由于模拟器是幻灯片,所以测试起来有点困难 :)
【问题讨论】:
标签: android android-fragments android-3.0-honeycomb
您应该如何实现例如 Honeycomb Gmail 客户端使用的那种滑动?
TransactionManager 可以通过添加和删除 Fragments 来自动处理这个问题,由于模拟器是幻灯片,所以测试起来有点困难 :)
【问题讨论】:
标签: android android-fragments android-3.0-honeycomb
要动画片段之间的过渡,或动画显示或隐藏片段的过程,请使用Fragment Manager 创建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.show 或ft.hide,分别传入您希望显示或隐藏的片段。
作为参考,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>
【讨论】:
如果您不必使用支持库,请查看Roman's 答案。
但如果你想使用支持库,你必须使用如下所述的旧动画框架。
在咨询了Reto's 和blindstuff's 的答案后,我得到了以下代码。
当按下返回时,片段会出现从右侧滑入和向左滑出。
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 文件夹中。
进入.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 或任何其他数字。
请注意,如果在片段替换之间发生配置更改(例如旋转),则后退动作不会动画。这是一个documented bug,它仍然存在于支持库的第 20 版中。
【讨论】:
我强烈建议您使用它而不是创建动画文件,因为它是一个更好的解决方案。 Android Studio 已经提供了 default animation,您无需创建任何新的 XML 文件即可使用。动画的名称是 android.R.anim.slide_in_left 和 android.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();
输出:
【讨论】:
我修改后的support library 支持将视图动画(即<translate>, <rotate>)和对象动画器(即<objectAnimator>)用于片段过渡。它是用NineOldAndroids 实现的。详情参考我在github上的文档。
【讨论】:
至于我,我需要视图方向:
in -> 从右侧滑动
out -> 向左滑动
这里适用于我的代码:
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()
}
}
}
}
【讨论】:
我用下面的方法解决这个问题
Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide);
fg.startAnimation(anim);
this.fg.setVisibility(View.VISIBLE); //fg is a View object indicate fragment
【讨论】: