我查看了一些有关在片段之间进行动画转换的教程。我已经使用了这种方法来进行动画处理,它有效:
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left,
android.R.anim.slide_out_right);
但我想反转这个动画:旧碎片向左滑出,新碎片向右滑入,但是在我的范围内似乎没有任何 R.anim
文件的值是有用的。
我该怎么做?
我查看了一些有关在片段之间进行动画转换的教程。我已经使用了这种方法来进行动画处理,它有效:
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left,
android.R.anim.slide_out_right);
但我想反转这个动画:旧碎片向左滑出,新碎片向右滑入,但是在我的范围内似乎没有任何 R.anim
文件的值是有用的。
我该怎么做?
更新 针对 Android v19+,请参阅此链接 通过 @Sandra
您可以创建自己的动画。将动画 XML 文件放置在 res > anim
中
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%p" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
从右侧进入.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%p" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="@android:integer/config_mediumAnimTime" />
</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%p"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="@android:integer/config_mediumAnimTime"/>
</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%p"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
您可以将动画的持续时间更改为短时间
android:duration="@android:integer/config_shortAnimTime"
或漫长的动画时间
android:duration="@android:integer/config_longAnimTime"
使用方法(注意在事务中调用方法的顺序很重要。在调用.replace 和 .commit 之前添加动画):
FragmentTransaction transaction = supportFragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
transaction.replace(R.id.content_frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
700
的动画持续时间有点长。Android框架为动画提供了3个预设的时间参数:android:duration="@android:integer/config_longAnimTime"
、android:duration="@android:integer/config_mediumAnimTime"
和android:duration="@android:integer/config_shortAnimTime"
,分别对应500、400和200。我猜测单位是毫秒,但不确定。 - Krøllebølle在片段中,有三种方式来处理事务动画。
如果需要使用内置的转场效果之一,请使用setTranstion()方法:
getSupportFragmentManager()
.beginTransaction()
.setTransition( FragmentTransaction.TRANSIT_FRAGMENT_OPEN )
.show( m_topFragment )
.commit()
您还可以使用setCustomAnimations()方法自定义动画:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations( R.anim.slide_up, 0, 0, R.anim.slide_down)
.show( m_topFragment )
.commit()
slide_up.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="translationY"
android:valueType="floatType"
android:valueFrom="1280"
android:valueTo="0"
android:duration="@android:integer/config_mediumAnimTime"/>
slide_down.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="translationY"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="1280"
android:duration="@android:integer/config_mediumAnimTime"/>
最后,我们也可以在一个事务中同时启动多个片段动画。这可以产生一个非常酷的效果,其中一个片段向上滑动,另一个片段向下滑动:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations( R.anim.abc_slide_in_top, R.anim.abc_slide_out_top ) // Top Fragment Animation
.show( m_topFragment )
.setCustomAnimations( R.anim.abc_slide_in_bottom, R.anim.abc_slide_out_bottom ) // Bottom Fragment Animation
.show( m_bottomFragment )
.commit()
注意:您可以根据自己的需求检查动画,因为上述可能存在问题。
向下滑入.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_longAnimTime"
android:fromYDelta="0%p"
android:toYDelta="100%p" />
</set>
slide_in_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_longAnimTime"
android:fromYDelta="100%p"
android:toYDelta="0%p" />
</set>
滑出下方.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_longAnimTime"
android:fromYDelta="-100%"
android:toYDelta="0"
/>
</set>
滑出向上.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_longAnimTime"
android:fromYDelta="0%p"
android:toYDelta="-100%p"
/>
</set>
方向 = 向下
activity.getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.slide_out_down, R.anim.slide_in_down)
.replace(R.id.container, new CardFrontFragment())
.commit();
方向 = 向上
activity.getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_out_up)
.replace(R.id.container, new CardFrontFragment())
.commit();
<?xml version="1.0" encoding="utf-8"?>
<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>
<?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>
fragmentTransaction.setCustomAnimations(R.anim.sliding_in_left, R.anim.sliding_out_right, android.R.anim.slide_in_left, android.R.anim.slide_out_right );
public class CustomAnimator {
private static final String TAG = "com.example.CustomAnimator";
private static Stack<AnimationEntry> animation_stack = new Stack<>();
public static final int DIRECTION_LEFT = 1;
public static final int DIRECTION_RIGHT = -1;
public static final int DIRECTION_UP = 2;
public static final int DIRECTION_DOWN = -2;
static class AnimationEntry {
View in;
View out;
int direction;
long duration;
}
public static boolean hasHistory() {
return !animation_stack.empty();
}
public static void reversePrevious() {
if (!animation_stack.empty()) {
AnimationEntry entry = animation_stack.pop();
slide(entry.out, entry.in, -entry.direction, entry.duration, false);
}
}
public static void clearHistory() {
animation_stack.clear();
}
public static void slide(final View in, View out, final int direction, long duration) {
slide(in, out, direction, duration, true);
}
private static void slide(final View in, final View out, final int direction, final long duration, final boolean save) {
ViewGroup in_parent = (ViewGroup) in.getParent();
ViewGroup out_parent = (ViewGroup) out.getParent();
if (!in_parent.equals(out_parent)) {
return;
}
int parent_width = in_parent.getWidth();
int parent_height = in_parent.getHeight();
ObjectAnimator slide_out;
ObjectAnimator slide_in;
switch (direction) {
case DIRECTION_LEFT:
default:
slide_in = ObjectAnimator.ofFloat(in, "translationX", parent_width, 0);
slide_out = ObjectAnimator.ofFloat(out, "translationX", 0, -out.getWidth());
break;
case DIRECTION_RIGHT:
slide_in = ObjectAnimator.ofFloat(in, "translationX", -out.getWidth(), 0);
slide_out = ObjectAnimator.ofFloat(out, "translationX", 0, parent_width);
break;
case DIRECTION_UP:
slide_in = ObjectAnimator.ofFloat(in, "translationY", parent_height, 0);
slide_out = ObjectAnimator.ofFloat(out, "translationY", 0, -out.getHeight());
break;
case DIRECTION_DOWN:
slide_in = ObjectAnimator.ofFloat(in, "translationY", -out.getHeight(), 0);
slide_out = ObjectAnimator.ofFloat(out, "translationY", 0, parent_height);
break;
}
AnimatorSet animations = new AnimatorSet();
animations.setDuration(duration);
animations.playTogether(slide_in, slide_out);
animations.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationCancel(Animator arg0) {
}
@Override
public void onAnimationEnd(Animator arg0) {
out.setVisibility(View.INVISIBLE);
if (save) {
AnimationEntry ae = new AnimationEntry();
ae.in = in;
ae.out = out;
ae.direction = direction;
ae.duration = duration;
animation_stack.push(ae);
}
}
@Override
public void onAnimationRepeat(Animator arg0) {
}
@Override
public void onAnimationStart(Animator arg0) {
in.setVisibility(View.VISIBLE);
}
});
animations.start();
}
}
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ui_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="@+id/list_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="@+id/details_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</FrameLayout>
使用方法
View details_container = findViewById(R.id.details_container);
View list_container = findViewById(R.id.list_container);
// You can select the direction left/right/up/down and the duration
CustomAnimator.slide(list_container, details_container,CustomAnimator.DIRECTION_LEFT, 400);
CustomAnimator.reversePrevious();
在用户按下返回按钮时获取先前的视图。在从一个片段转换到另一个片段的过程中,遇到了白屏问题。在navigation.xml中设置了导航和动画。
所有片段的背景都相同,但是显示为白色空白屏幕。因此,在执行转换期间,我在片段中设置了navOptions。
//Transition options
val options = navOptions {
anim {
enter = R.anim.slide_in_right
exit = R.anim.slide_out_left
popEnter = R.anim.slide_in_left
popExit = R.anim.slide_out_right
}
}
.......................
this.findNavController().navigate(SampleFragmentDirections.actionSampleFragmentToChartFragment(it),
options)
这对我有用。在转换之间没有白屏。太神奇了)
对我来说,唯一能够消除动画白色背景的方法是将Fragment更改为DialogFragment,并添加以下代码:
创建了以下样式:
<style name="WindowSlideInAndOutAnimation">
<item name="android:windowEnterAnimation">@anim/slide_in_bottom</item>
<item name="android:windowExitAnimation">@anim/slide_out_top</item>
</style>
<style name="AppFullScreenDialogTransparentTitleBar" parent="Theme.MaterialComponents.Light.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
<item name="colorPrimaryDark">@android:color/transparent</item>
</style>
然后在对话框片段中引用这些样式:
override fun getTheme() = R.style.AppFullScreenDialogTransparentTitleBar
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dialog?.window?.setWindowAnimations(R.style.WindowSlideInAndOutAnimation)
//rest of code on view created here
}
然后我只需通过导航组件正常导航到片段(还要注意更改导航 XML 文件中片段的类型为对话框)
override
key_code==back_key_press
。 - Nitin Misra