为什么要使用转场动画?在页面切换或者UI展示的时候,如果没有设计转场动画,那么状态场景的切换就是瞬间发生的,这样就非常突兀,没有视觉效果,所以在App开发的过程中,设计转场动画,是必不可少的。
1、揭露动画
揭露动画使用的场景,往往是在单个View中呈现的效果,实现是通过ViewAnimationUtils
工具实现的。
在设置揭露动画的时候,需要设置的4个参数值分别为:中心点的x,y值,以及揭露动画开始的半径和结束的半径。(这4个值是相对View视图的)
btn_show.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(view.isShown()){
//如果显示
}else{
startReval();
}
}
});
显示揭露动画:
private void startReval() {
int width = view.getWidth();
int height = view.getHeight();
//相对于View的坐标,这样就是右下角作为圆心
int x = width;
int y = height;
//半径为斜边
int endRadius = (int) Math.hypot(x,y);
Animator animator = ViewAnimationUtils.
createCircularReveal(view, x, y, 0, endRadius);
animator.setDuration(3000);
//显示View
view.setVisibility(View.VISIBLE);
animator.start();
}
这样展示的揭露动画,就是从右下角圆心开始,逐渐将View填充完毕。
结束揭露动画:
private void endReval() {
int width = view.getWidth();
int height = view.getHeight();
int x = width;
int y = height;
int endRadius = (int) Math.hypot(x,y);
Animator animator = ViewAnimationUtils.
createCircularReveal(view, x, y, endRadius, 0);
// animator.setDuration(3000);
// //显示View
// view.setVisibility(View.INVISIBLE);
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
//动画结束之后
view.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animator.start();
}
在结束揭露动画的时候,不能像显示揭露动画那样,将View设置为INVISIBLE,这样就不能看到动画效果,因此需要给动画设置监听,当动画结束的时候,将View设置为INVISIBLE。
2、转场动画
在使用转场动画之前,首先需要知道几个概念:
(1)Scene
场景。每个界面都可以有很多场景,不同场景之间的变换,就需要Scene来获取。
通过getSceneForLayout
获取场景,sceneRoot
为转场动画的舞台或者根节点,动画在这里播放,layoutId就是转场动画的视图资源,可以通过getSceneForLayout来创建多个Scene,包括转场前后的。
public static Scene getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) {
SparseArray<Scene> scenes = (SparseArray<Scene>) sceneRoot.getTag(
com.android.internal.R.id.scene_layoutid_cache);
if (scenes == null) {
scenes = new SparseArray<Scene>();
sceneRoot.setTagInternal(com.android.internal.R.id.scene_layoutid_cache, scenes);
}
Scene scene = scenes.get(layoutId);
if (scene != null) {
return scene;
} else {
scene = new Scene(sceneRoot, layoutId, context);
scenes.put(layoutId, scene);
return scene;
}
}
(2)Transition
转换。也存在很多变换的场景,像:
Fade
:清晰度的改变,入场时清晰度从0-1,出场时清晰度从1-0;
ChangeBounds
:形状大小的改变,视图的大小变换可以通过此类场景改变。
(3)TransitionManager
转场动画的执行者,通常使用一下API来进行设置
传入的两个参数分为为之前介绍的场景和转换动画。
3、转场动画的使用
首先需要创建一个空布局,作为sceneRoot,场景的根布局,创建2个场景分别为场景1和场景2;
scene_root = findViewById(R.id.scene_root);
mOverViewScene = Scene.getSceneForLayout
(scene_root, R.layout.layout_overview, getBaseContext());
mOverViewScene = Scene.getSceneForLayout
(scene_root, R.layout.layout_sceneview, getBaseContext());
//默认先去场景1
TransitionManager.go(mOverViewScene);
当点击按钮切换时,切换到不同的场景(不要去findViewById,会出现空指针,用XML布局中的OnClick属性即可)。
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_info:
//去场景2
TransitionManager.go(mSceneView);
break;
case R.id.btn_back:
//去场景1:
TransitionManager.go(mOverViewScene);
break;
}
}
这里是没有加转场动画的效果,在调用go方法的时候,默认是使用AutoAnimation动画的。
public static void go(@NonNull Scene scene) {
changeScene(scene, sDefaultTransition);
}
private static Transition sDefaultTransition = new AutoTransition();
public AutoTransition() {
init();
}
public AutoTransition(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setOrdering(ORDERING_SEQUENTIAL);
addTransition(new Fade(Fade.OUT))
.addTransition(new ChangeBounds())
.addTransition(new Fade(Fade.IN));
}
默认使用的AutoTransition动画,有清晰度的转换淡入淡出,还有ChangeBounds
变换大小等特效。
4、自定义转场动画
在res目录下,创建transition文件,可以编写动画集合AnimationSet
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeImageTransform android:duration="3000" >
//指定目标控件的id进行changeImageTransform 变换
<targets android:targetId="@id/iv_icon"/>
</changeImageTransform>
//startDelay 上一个动画结束后1s,fade动画开始
<fade android:duration="3000" android:startDelay="1000"/>
</transitionSet>
在自定义完转场动画之后,这是场景1的转场动画,可以去go中设置Transition
Transition transition = TransitionInflater.from(getBaseContext())
.inflateTransition(R.transition.transition);
TransitionManager.go(mSceneView,transition);
在加载转场动画的时候,使用TransitionInflater
加载动画文件,有点类似于动态加载布局文件的LayoutInflater。
5、Activity之间的转场动画
Activity之间切换也是转场动画使用的高频之处。
在Activity中也有定义好的转场动画,像:Fade(清晰度)、Slide(平移 上下左右)、Explode(爆炸效果),当然也可以自定义转场动画。
btn_trans.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//爆炸效果的转场动画
Transition transition = new Explode();
//不能让状态栏变动
transition.excludeTarget(android.R.id.statusBarBackground,true);
getWindow().setEnterTransition(transition);
getWindow().setExitTransition(transition);
//设置转场动画
final ActivityOptions options = ActivityOptions.
makeSceneTransitionAnimation(this, null);
Intent intent = new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
startActivity(intent,options.toBundle());
}
});
通过ActivityOptions
来设置转场动画,根据现有的或者自定义的转场动画,来设置Activity之间的转场动画。
如果想要更好的视觉效果,如果跳转的两个Activity之间有相同的属性控件,例如ImageView,那么可以设置共享元素,这样有更好的视觉连续性。
Pair<View, String> sharedElements = Pair.create(iv_trans, "img");
//设置转场动画
final ActivityOptions options = ActivityOptions.
makeSceneTransitionAnimation(MainActivity.this,sharedElements);
那么在跳转目标Activity的布局文件中,需要设置transitionName
,这样就能使得动画更具有视觉连续性。
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon"
android:layout_centerInParent="true"
android:transitionName="img"/>
6、ARouter设置转场动画
在之前使用ARouter路由框架的时候,主要也是用来Activity之间的跳转,那么ARouter框架也有转场动画API。
ARouter.getInstance()
.build(Arouter.SECOND_ACTIVITY)
// .with(options.toBundle())
.withTransition(R.anim.animition_enter,R.anim.animation_exit)
.navigation(MainActivity.this);
通过设置withTransition,设置入场动画和出场动画,注意在navigation
中一定要加上上下文对象,不然没有动画效果。
在退出动画的时候,如果不加设置,就没有转场动画,需要重新finish方法,具体方法视业务情况而定。