项目背景:mvvm+组件化,然后由于领导要求,使用MainActivity为主界面,各种业务使用Fragment处理。所以~ 由于单独Activity+N Fragment 的方式,经过十多天的试错,我确认一件事情。再确认过架构方式后一定要了解下业务场景和使用技术栈。不然会导致身心俱疲——下一篇记录 组件化方式中使用 MainActivity + N Fragment方式怎么适配 组件化。
目录
1、界面转跳 转场动画;
方案一:使用 ARouter 自带 withTransition 设置转场动画。
方案二:使用ViewAnimationUtils 实现动画,配合addOnLayoutListener 监听 控制rootView显隐,达到视觉效果的转场。
方案三:使用Android官方推荐的共享元素方式
使用 FragmentTransaction
使用 TransitionSet
使用 MaterialContainerTransform
2、Fragment add Fragment 动画不生效问题记录。
1、界面转跳 转场动画;
方案一:使用 ARouter 自带 withTransition 设置转场动画。
// 普通跳转
ARouter.getInstance().build("/test/activity").withTransition(R.anim.slide_in_right, R.anim.slide_out_left) // 设置转场动画.navigation(this);
slide_in_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:duration="300"android:fromXDelta="100%"android:toXDelta="0%" />
</set>
slide_out_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:duration="300"android:fromXDelta="0%"android:toXDelta="-100%" />
</set>
优点:实现简单,不用二次封装
缺点:无法实现复杂的动画。
方案二:使用ViewAnimationUtils 实现动画,配合addOnLayoutListener 监听 控制rootView显隐,达到视觉效果的转场。
转跳前可以获取按钮位置xy值
binding.tvRouter.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {int centerX = (v.getLeft() + v.getRight()) / 2;int centerY = (v.getTop() + v.getBottom()) / 2;LogUtils.e("centerX: " + centerX );LogUtils.e("centerY: " + centerX );ARouter.getInstance().build(RouterActivityPath.Login.PAGER_LOGIN).withInt("centerX", centerX).withInt("centerY", centerY).navigation(getActivity());}});
转跳界面:获取前页面传递过来xy值,设置一些想要的动画效果。
centerX =getIntent().getIntExtra("centerX",0);centerX =getIntent().getIntExtra("centerY",0);binding.parent.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {@Overridepublic void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {binding.parent.removeOnLayoutChangeListener(this);float finalRadius = (float) Math.hypot(v.getWidth(), v.getHeight());CircularRevealUtil.startCircularReveal(v, centerX, centerY, 0, finalRadius);}});
CircularRevealUtil : 作了一个示例,圆形揭示
/*** 开始圆形揭示动画** @param view 要显示的视图* @param centerX 动画的中心X坐标* @param centerY 动画的中心Y坐标* @param startRadius 动画起始半径* @param endRadius 动画结束半径*/public static void startCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius) {Animator anim = ViewAnimationUtils.createCircularReveal(view, centerX, centerY, startRadius, endRadius);view.setVisibility(View.VISIBLE);anim.start();}
优点:可以定制复杂的转场动画
缺点:不易封装,实现难度,性能消耗等
方案三:使用Android官方推荐的共享元素方式
// 在第一个Activity中启动第二个Activity
Intent intent = new Intent(this, SecondActivity.class);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,Pair.create(sharedView, "shared_element_transition")
);
startActivity(intent, options.toBundle());
在布局文件中,为共享元素设置 android:transitionName
:
<!-- activity_first.xml -->
<ImageViewandroid:id="@+id/sharedView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/sample_image"android:transitionName="shared_element_transition" />
<!-- activity_second.xml -->
<ImageViewandroid:id="@+id/sharedView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/sample_image"android:transitionName="shared_element_transition" />
使用 FragmentTransaction
对于 Fragment
之间的共享元素动画,可以使用 FragmentTransaction
类来设置共享元素。
在第一个 Fragment
中启动第二个 Fragment
:
Fragment secondFragment = new SecondFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, secondFragment);
transaction.addToBackStack(null);
transaction.addSharedElement(sharedView, "shared_element_transition");
transaction.commit();
在布局文件中,为共享元素设置 android:transitionName
<!-- fragment_first.xml -->
<ImageViewandroid:id="@+id/sharedView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/sample_image"android:transitionName="shared_element_transition" />
<!-- fragment_second.xml -->
<ImageViewandroid:id="@+id/sharedView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/sample_image"android:transitionName="shared_element_transition" />
使用 TransitionSet
如果需要同时使用多种动画效果,可以使用 TransitionSet
来组合多个动画效果。
TransitionSet transitionSet = new TransitionSet();
transitionSet.addTransition(new ChangeBounds());
transitionSet.addTransition(new ChangeTransform());
transitionSet.addTransition(new ChangeImageTransform());getWindow().setSharedElementEnterTransition(transitionSet);
getWindow().setSharedElementReturnTransition(transitionSet);
使用 MaterialContainerTransform
MaterialContainerTransform
是 Android Material Design 提供的一个组件,可以用于容器转换动画,适用于 Activity
和 Fragment
之间的共享元素过渡。
FragmentTransaction transaction = getFragmentManager().beginTransaction();
MaterialContainerTransform transform = new MaterialContainerTransform();
transform.setDuration(300);
secondFragment.setSharedElementEnterTransition(transform);
transaction.addSharedElement(sharedView, "shared_element_transition");
transaction.replace(R.id.fragment_container, new SecondFragment());
transaction.addToBackStack(null);
transaction.commit();
在布局文件中,为共享元素设置 android:transitionName
<!-- fragment_first.xml -->
<Viewandroid:id="@+id/sharedView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:transitionName="shared_element_transition" />
<!-- fragment_second.xml -->
<Viewandroid:id="@+id/sharedView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:transitionName="shared_element_transition" />
2、Fragment add Fragment 动画不生效问题记录。
其实写这篇文章最重要的是想记录这个问题,我卡了一天。怀疑了FragmentTransaction封装,怀疑组件化结构。任何动画设置均不成功。最后看到自己布局里使用的Fragment容器。
<androidx.fragment.app.FragmentContainerViewandroid:id="@+id/main_container"android:layout_width="match_parent"android:layout_height="match_parent" />
FragmentContainerView 会导致 Fragment转场动画不生效。
FragmentContainerView 会导致 Fragment转场动画不生效。
FragmentContainerView 会导致 Fragment转场动画不生效。
重要的话说三遍