一、前言
这是 Android5.0 推出的新的动画框架,可以给 View 做一个揭露效果。效果如下:
当您显示或隐藏一组 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
*
- 实现代码
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 简单使用
-
效果图
-
布局文件
注意: 可以看到代码中在动画开始之前设置了targetView可见( targetView.setVisibility(View.VISIBLE); animator.start();)因为前面我们介绍了揭露动画特性 重要特性:
- 揭露动画是一个异步动画,它的回调方法都不能保证在准确的时间里调用,但误差不会很大。
- 揭露对象要先于动画开始前显示(View.VISIBLE),因为动画开始时如果被操作对象处于隐藏状态,那么动画就不会有效果,所以就算是不可见的对象,开始动画前也需要设置为可见。
所以可以在监听动画动画开始回调时调用targetView.setVisibility(View.VISIBLE),但因为揭露动画是异步的,会有极小的概率导致view不可见,所以再动画开始之前最保险。
3. 结合属性动画,共享元素和揭露动画的简单实例-
效果图
-
布局文件
---------------------------------分割线---------------------------------
- 实现代码 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);
}
}