动画入门和进阶文章列表:
Animation动画概述和执行原理
Android动画之补间动画TweenAnimation
Android动画之逐帧动画FrameAnimation
Android动画之插值器简介和系统默认插值器
Android动画之插值器Interpolator自定义
Android动画之视图动画的缺点和属性动画的引入
Android动画之ValueAnimator用法和自定义估值器
Android动画之ObjectAnimator实现补间动画和ObjectAnimator自定义属性
Android动画之ObjectAnimator中ofXX函数全解析-自定义Property,TypeConverter,TypeEvaluator
Android动画之AnimatorSet联合动画用法
Android动画之LayoutTransition布局动画
Android动画之共享元素动画
Android动画之ViewPropertyAnimator(专用于view的属性动画)
Android动画之Activity切换动画overridePendingTransition实现和Theme Xml方式实现
Android动画之ActivityOptionsCompat概述
Android动画之场景变换Transition动画的使用
Android动画之Transition和TransitionManager使用
Android动画之圆形揭露动画Circular Reveal
Android 动画之 LayoutAnimation 动画
1 Circular Reveal 圆形揭露动画概述
Android5.0是一个里程碑式的版本,不但提升了流畅度,更是增加了很多炫酷的效果:
Touch feedback(触摸反馈)
Reveal effect(揭露效果)
Activity transitions(Activity转换效果)
Curved motion(曲线运动)
View state changes (视图状态改变)
Animate Vector Drawables(可绘矢量动画)
今天主要讲解揭露动画。
RevealAnimator 揭露动画,这时Android5.0添加的新动画,动画效果为利用圆形缩放实现一个view的显示或者隐藏,最低支持的版本为api21,低版本使用会报异常,如果想要兼容api19以上的版本,可以自己实现这种缩放动画。
因为懒文章后面用到揭露动画的地方没有加版本限制,真实开发不能这么做。
RevealAnimator 是个隐藏的类所以在AndroidDeveloper上没有RevealAnimator 相关信息,所以只需要关注生成揭露动画的函数。
Circular Reveal 圆形揭露动画由ViewAnimationUtils.createCircularReveal生成。
public static Animator createCircularReveal(View view,
int centerX, int centerY, float startRadius, float endRadius)
参数说明:
view :要执行动画效果的View
centerX:圆心x坐标
centerY:圆心y坐标
startRadius:开始时的圆半径
endRadius:结束时的圆半径
返回值是一个Animator。
一般要显示把开始半径设置为0,结束设置响应值,如果要隐藏view,需要把开始半径设置为最大值,结束半径设置为0
重要特性:
揭露动画是一个异步动画,它的回调方法都不能保证在准确的时间里调用,但误差不会很大。揭露对象要先于动画开始前显示(View.VISIBLE),因为动画开始时如果被操作对象处于隐藏状态,那么动画就不会有效果,所以就算是不可见的对象,开始动画前也需要设置为可见。
2 createCircularReveal的简单使用
首先要说明一点,看到api那么简单我直接应用到Activity中,但是换了很多个模拟器都无法出现揭露动画效果,最终利用 ActivityOptionsCompat.makeSceneTransitionAnimation和startActivity(intent,activityOptionsCompat.toBundle());启动的Activity才支持揭露动画。
2.1 简单使用,代码示例
XML文件:
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><!--做动画的布局--><LinearLayoutandroid:id="@+id/targetView"android:layout_width="match_parent"android:layout_height="400dp"android:background="#ff00ff"android:orientation="vertical"android:gravity="center"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="center"android:textSize="20sp"android:text="我是内容区域 我是内容区域我是内容区域 我是内容区域我是内容区域我是内容区域我是内容区域我是内容区域" /></LinearLayout><Buttonandroid:id="@+id/start"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom"android:text="开始动画"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent" /></android.support.constraint.ConstraintLayout>
Activity文件
public class Main11Activity extends AppCompatActivity {LinearLayout targetView ;@Overrideprotected void onCreate(Bundle savedInstanceState) {getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);Fade fade = new Fade();getWindow().setEnterTransition(fade);getWindow().setExitTransition(fade);getWindow().setReenterTransition(fade);getWindow().setReturnTransition(fade);ChangeBounds changeBounds = new ChangeBounds();changeBounds.setDuration(1000);ChangeClipBounds changeClipBounds = new ChangeClipBounds();changeClipBounds.setDuration(1000);ChangeImageTransform changeImageTransform = new ChangeImageTransform();changeImageTransform.setDuration(1000);ChangeTransform changeTransform = new ChangeTransform();changeTransform.setDuration(1000);getWindow().setSharedElementEnterTransition(changeBounds);getWindow().setSharedElementExitTransition(changeClipBounds);getWindow().setSharedElementReenterTransition(changeImageTransform);getWindow().setSharedElementReturnTransition(changeTransform);getWindow().setSharedElementsUseOverlay(true);super.onCreate(savedInstanceState);setContentView(R.layout.activity_main11);targetView = findViewById(R.id.targetView);}@Overrideprotected void onResume() {super.onResume();findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {final int width = targetView.getMeasuredWidth();final int height = targetView.getMeasuredHeight();final float radius = (float)Math.sqrt(width*width + height*height) / 2;//半径Animator animator;if (targetView.getVisibility() == View.VISIBLE){animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, radius, 0);animator.setDuration(1000);animator.setInterpolator(new AccelerateDecelerateInterpolator());animator.start();animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {targetView.setVisibility(View.GONE);}});}else{animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, 0, radius);animator.setDuration(1000);animator.setInterpolator(new AccelerateDecelerateInterpolator());targetView.setVisibility(View.VISIBLE);animator.start();animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {targetView.setVisibility(View.VISIBLE);}});}}});}}
Activity代码中关于转场动画的代码不用管
效果图:
2.2 对ImageView操作
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><!--做动画的布局--><LinearLayoutandroid:id="@+id/targetView"android:layout_width="match_parent"android:layout_height="400dp"android:orientation="vertical"android:gravity="center"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"><ImageViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="fitCenter"android:src="@drawable/image_home_game_nor"/></LinearLayout><Buttonandroid:id="@+id/start"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom"android:text="开始动画"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent" /></android.support.constraint.ConstraintLayout>
效果图:
注意:
可以看到代码中在动画开始之前设置了targetView可见( targetView.setVisibility(View.VISIBLE); animator.start();)因为前面我们介绍了揭露动画特性
重要特性:
揭露动画是一个异步动画,它的回调方法都不能保证在准确的时间里调用,但误差不会很大。揭露对象要先于动画开始前显示(View.VISIBLE),因为动画开始时如果被操作对象处于隐藏状态,那么动画就不会有效果,所以就算是不可见的对象,开始动画前也需要设置为可见。
所以可以在监听动画动画开始回调时调用targetView.setVisibility(View.VISIBLE),但因为揭露动画是异步的,会有极小的概率导致view不可见,所以再动画开始之前最保险。
3 结合属性动画,共享元素和揭露动画的简单实例
从ActivityA启动ActivityB
ActivityA 布局文件
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"android:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".Main10Activity"><ImageViewandroid:id="@+id/floatactionbtn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/image_home_game_nor2"android:scaleType="centerCrop"app:layout_constraintRight_toRightOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:transitionName="shareelement"/><FrameLayoutandroid:id="@+id/framelayout"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="gone"android:background="@color/colorPrimary"></FrameLayout></android.support.constraint.ConstraintLayout>
ActivityA 代码
public class ActivityA extends AppCompatActivity {private ImageView fab;private ConstraintLayout mCons;private FrameLayout mFram;@Overrideprotected void onCreate(Bundle savedInstanceState) {getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);super.onCreate(savedInstanceState);setContentView(R.layout.activity_main10);fab = findViewById(R.id.floatactionbtn);mCons = findViewById(R.id.container);mFram = findViewById(R.id.framelayout);mFram.setVisibility(View.GONE);fab.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Path path = new Path();path.moveTo(mCons.getMeasuredWidth()-fab.getWidth(),mCons.getMeasuredHeight() - fab.getHeight());path.quadTo(mCons.getMeasuredWidth()-300,mCons.getMeasuredHeight() -200,mCons.getMeasuredWidth()/2- fab.getWidth(),mCons.getMeasuredHeight()/2 - fab.getHeight()/2);ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(fab, "X", "Y", path);objectAnimator.setDuration(3000);objectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());Path path2 = new Path();path2.moveTo(1.0f,1.0f);path2.lineTo(2.0f,2.0f);path2.lineTo(1.0f,1.0f);path2.lineTo(2.0f,2.0f);path2.lineTo(1.0f,1.0f);ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(fab, View.SCALE_X,View.SCALE_Y, path2);objectAnimator2.setDuration(4000);objectAnimator2.setInterpolator(new AccelerateDecelerateInterpolator());objectAnimator2.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);Intent intent = new Intent(ActivityA.this, ActivityB.class);ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(ActivityA.this,fab,"shareelement");startActivity(intent,activityOptionsCompat.toBundle());}@Overridepublic void onAnimationStart(Animator animation) {super.onAnimationStart(animation);}});AnimatorSet animatorSet = new AnimatorSet();animatorSet.playSequentially(objectAnimator,objectAnimator2);animatorSet.start();}});}}
ActivityB 布局文件:
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/targetView"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="fitCenter"android:src="@drawable/image_home_game_nor"android:transitionName="shareelement" /><!--做动画的布局--><LinearLayoutandroid:layout_width="match_parent"android:layout_height="400dp"android:orientation="vertical"android:gravity="center"android:visibility="gone"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"><ImageViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="fitCenter"android:src="@drawable/image_home_game_nor"/></LinearLayout><Buttonandroid:id="@+id/start"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom"android:text="开始动画"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent" /></android.support.constraint.ConstraintLayout>
ActivityB 代码
public class ActivityB extends AppCompatActivity {View targetView ;@Overrideprotected void onCreate(Bundle savedInstanceState) {getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);super.onCreate(savedInstanceState);setContentView(R.layout.activity_main11);targetView = findViewById(R.id.targetView);}@Overrideprotected void onResume() {super.onResume();findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Animator animator;final int width = targetView.getMeasuredWidth();final int height = targetView.getMeasuredHeight();final float radius = (float)Math.sqrt(width*width + height*height) / 2;//半径if (targetView.getVisibility() == View.VISIBLE){animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, radius, 0);animator.setDuration(1000);animator.setInterpolator(new AccelerateDecelerateInterpolator());animator.start();animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {targetView.setVisibility(View.GONE);}});}else{animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, 0, radius);animator.setDuration(1000);animator.setInterpolator(new AccelerateDecelerateInterpolator());targetView.setVisibility(View.VISIBLE);animator.start();animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {targetView.setVisibility(View.VISIBLE);}});}}});new Handler().postDelayed(new Runnable() {@Overridepublic void run() {final int width = targetView.getMeasuredWidth();final int height = targetView.getMeasuredHeight();final float radius = (float)Math.sqrt(width*width + height*height) / 2;//半径Animator animator;animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, radius, 20);animator.setDuration(3000);animator.setInterpolator(new AccelerateDecelerateInterpolator());targetView.setVisibility(View.VISIBLE);animator.start();animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {targetView.setVisibility(View.GONE);}});}},1000);}}
效果图:
有没有兼容低版本的库,大家给推荐个?
如果觉得《Android动画之圆形揭露动画Circular Reveal》对你有帮助,请点赞、收藏,并留下你的观点哦!