一、前言
这是 Android5.0 推出的新的动画框架,可以给 View 做一个揭露效果。效果如下:
二、Circular Reveal 介绍
当您显示或隐藏一组 UI 元素时,揭露动画可为用户提供视觉连续性。
ViewAnimationUtils.createCircularReveal()
方法让您能够为裁剪区域添加动画以揭露或隐藏视图。
/* @param view The View will be clipped to the animating circle.
* @param centerX The x coordinate of the center of the animating circle, relative to
* <code view</code .
* @param centerY The y coordinate of the center of the animating circle, relative to
* <code view</code .
* @param startRadius The starting radius of the animating circle.
* @param endRadius The ending radius of the animating circle.
*/
public static Animator createCircularReveal(View view,
int centerX, int centerY, float startRadius, float endRadius) {
return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
}
参数说明:
- view :要执行动画效果的View
- centerX:圆心x坐标
- centerY:圆心y坐标
- startRadius:开始时的圆半径
- endRadius:结束时的圆半径
返回值是一个 Animator 。
ViewAnimationUtils.createCircularReveal()
方法所执行的效果,就是将一个 View 裁剪成圆,然后从圆心逐渐揭露展现视图。
三、实例
1. TextView 简单使用
-
效果图
-
布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--做动画的布局-->
<LinearLayout
android: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">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:textSize="20sp"
android:text="我是内容区域 我是内容区域
我是内容区域 我是内容区域
我是内容区域
我是内容区域
我是内容区域我是内容区域" />
</LinearLayout>
<Button
android: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>
- 实现代码
public class Main11Activity extends AppCompatActivity {
LinearLayout targetView ;
@Override
protected 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);
}
@Override
protected void onResume() {
super.onResume();
findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
@Override
public 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() {
@Override
public 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() {
@Override
public void onAnimationEnd(Animator animation) {
targetView.setVisibility(View.VISIBLE);
}
});
}
}
});
}
}
2. ImageView 简单使用
-
效果图
-
布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--做动画的布局-->
<LinearLayout
android: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">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:src="@drawable/image_home_game_nor"/>
</LinearLayout>
<Button
android: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. 结合属性动画,共享元素和揭露动画的简单实例
-
效果图
-
布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".AActivity">
<ImageView
android: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"/>
<FrameLayout
android: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>
---------------------------------分割线---------------------------------
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android: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" />
<!--做动画的布局-->
<LinearLayout
android: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">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:src="@drawable/image_home_game_nor"/>
</LinearLayout>
<Button
android: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>
- 实现代码
ActivityA 代码
public class ActivityA extends AppCompatActivity {
private ImageView fab;
private ConstraintLayout mCons;
private FrameLayout mFram;
@Override
protected 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() {
@Override
public 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() {
@Override
public 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());
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(objectAnimator,objectAnimator2);
animatorSet.start();
}
});
}
}
ActivityB 代码
public class ActivityB extends AppCompatActivity {
View targetView ;
@Override
protected void onCreate(Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main11);
targetView = findViewById(R.id.targetView);
}
@Override
protected void onResume() {
super.onResume();
findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
@Override
public 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() {
@Override
public 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() {
@Override
public void onAnimationEnd(Animator animation) {
targetView.setVisibility(View.VISIBLE);
}
});
}
}
});
new Handler().postDelayed(new Runnable() {
@Override
public 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() {
@Override
public void onAnimationEnd(Animator animation) {
targetView.setVisibility(View.GONE);
}
});
}
},1000);
}
}