Fragment transaction animation: slide in and slide out

I've check some tutorials for animate transaction between fragments. I've used this method for animation and it works:

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

But I want to invert this animation: old fragment slide out to the left, and new fragment slide in to the right, but no value of R.anim file seems to be useful for my scope.

How can I do it?

168411 次浏览

通过@Sandra 更新

您可以创建自己的动画

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>

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

USAGE (请注意,调用事务方法的顺序很重要。在调用之前添加动画。更换。提交) :

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

这是我使用的另一种解决方案:

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();获取上一个视图。

在片段中进行事务动画有三种方法。

过渡期

因此,需要使用内置的转换之一,使用 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()

更多细节,你可以访问网址

注意:- 您可以根据您的需求检查动画,因为上面可能有问题。

我也有同样的问题,我用了简单的解决方案

1)在 anim 文件夹中创建 sliat _ out _ right xml

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

2)在 anim 文件夹中创建 sliin _ left. xml

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

3)简单地使用片段事务 setCustomeAnimations ()和两个自定义 xml 和两个默认 xml 作为动画,如下所示:-

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

Slide _ in _ down. 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>

Slide _ down. 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>

Slide _ out _ 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="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();

在从一个片段过渡到另一个片段时,白屏也有同样的问题。在 Navigation.xml 中设置导航和动画。

enter image description here

所有片段的背景都是相同的,但是白色的空白屏幕。所以我在执行转换过程中在片段中设置了导航选项

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

对我来说很有效,过渡期间没有白屏,太神奇了)