今天看到了@Anderson大码渣写的文章,对5.0以上默认使用ViewAnimationUtils.createCircularReveal(view, centerX, centerY, startRadius, endRadius);
来实现渐变,
4.0以上兼容
要想在低版本中也能正常使用,我们可以直接自定义一个viewGroup,挂载在decorview上,然后使用canvas.clipPath
裁剪一个圆,这样达到覆盖的目的。
public class CircularRevealLayout extends FrameLayout {
private static final String TAG = "CircularRevealLayout";
private float revealRadius;
private int centerX;
private int centerY;
private float startRadius;
private float endRadius;
private View childRevealView;
private boolean isRunning = false;//动画是否正在执行
private Path path;//绘制路径
public CircularRevealLayout(Context context) {
this(context, null, 0);
}
public CircularRevealLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircularRevealLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
path = new Path();
setFocusable(false);
}
/**
* 设置要揭示的子view
* @param childRevealView
*/
public void setChildRevealView(View childRevealView) {
this.childRevealView = childRevealView;
}
/**
* 设置要揭示的子view的下标
* @param index
*/
public void setChildRevealViewIndex(int index) {
if(getChildCount()>index){
this.childRevealView=getChildAt(index);
}
}
/**
* 设置揭示半径
* @param revealRadius
*/
private void setRevealRadius(float revealRadius) {
this.revealRadius = revealRadius;
Log.e(TAG, "revealRadius=" + revealRadius);
invalidate();
}
/**
* 设置揭示的中心点x坐标
* @param centerX
*/
public void setCenterX(int centerX) {
this.centerX = centerX;
}
/**
* 设置揭示的中心点y坐标
* @param centerY
*/
public void setCenterY(int centerY) {
this.centerY = centerY;
}
/**
* 设置揭示的开始半径
* @param startRadius
*/
public void setStartRadius(float startRadius) {
this.startRadius = startRadius;
}
/**
* 设置揭示的结束半径
* @param endRadius
*/
public void setEndRadius(float endRadius) {
this.endRadius = endRadius;
}
public Animator getAnimator() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "revealRadius", startRadius, endRadius);
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
isRunning = true;
}
@Override
public void onAnimationEnd(Animator animator) {
isRunning = false;
}
@Override
public void onAnimationCancel(Animator animator) {
isRunning = false;
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
return objectAnimator;
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if (isRunning && child == childRevealView) {
final int state = canvas.save();
path.reset();
path.addCircle(centerX, centerY, revealRadius, Path.Direction.CW);//Pat.Direction.CW:顺时针
canvas.clipPath(path);//裁剪
boolean isInvalided = super.drawChild(canvas, child, drawingTime);
canvas.restoreToCount(state);
return isInvalided;
}
return super.drawChild(canvas, child, drawingTime);
}
}
再实现兼容的ViewAnimationCompatUtils
public class ViewAnimationCompatUtils {
private static final String TAG = "ViewAnimationCompatUtil";
public static Animator createCircularReveal(@NonNull View view, int centerX, int centerY, float startRadius, float endRadius) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return ViewAnimationUtils.createCircularReveal(view, centerX, centerY, startRadius, endRadius);
}
//如果父view已经是CircularRevealLayout,则设置参数后直接返回animator
if (view.getParent() != null && view.getParent() instanceof CircularRevealLayout) {
Log.e(TAG, "parent is CircularRevealLayout");
CircularRevealLayout circularRevealLayout = (CircularRevealLayout) view.getParent();
circularRevealLayout.setCenterX(centerX);
circularRevealLayout.setCenterY(centerY);
circularRevealLayout.setStartRadius(startRadius);
circularRevealLayout.setEndRadius(endRadius);
circularRevealLayout.setChildRevealView(view);
return circularRevealLayout.getAnimator();
}
Log.e(TAG, "parent is not CircularRevealLayout");
//如果父view不是CircularRevealLayout,则先为view添加父view CircularRevealLayout
//之后将CircularRevealLayout替换掉原来的view
CircularRevealLayout circularRevealLayout = new CircularRevealLayout(view.getContext());
//开启硬件加速
circularRevealLayout.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
circularRevealLayout.setCenterX(centerX);
circularRevealLayout.setCenterY(centerY);
circularRevealLayout.setStartRadius(startRadius);
circularRevealLayout.setEndRadius(endRadius);
circularRevealLayout.setChildRevealView(view);
ViewGroup.LayoutParams params = view.getLayoutParams();
ViewGroup parent = (ViewGroup) view.getParent();
int index = 0;
if (parent != null) {
index = parent.indexOfChild(view);//记录view在原先父view的下标
Log.e(TAG, "index=" + index);
parent.removeView(view);
circularRevealLayout.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
parent.addView(circularRevealLayout, index, params);
}
return circularRevealLayout.getAnimator();
}
}
写到这儿,已经能正常显示了,不过在@Anderson大码渣](http://www.jianshu.com/p/d4b421795154)的基础上我们最好再继续做一定的修改,上文在AnimationHelper的startActivityForResult中写了个延迟任务,
view.postDelayed(new Runnable() {
@Override
public void run() {
Animator anim = ViewAnimationCompatUtils.createCircularReveal(imageview, xCenter, yCenter, finalRadius, 0);
anim.setDuration(durationMills);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
try {
decorView.removeView(imageview);
imageview.setVisibility(View.GONE);
} catch (Exception e) {
e.printStackTrace();
}
}
});
anim.start();
}
}, 1000);
在4.0的系统上退回到前一个activity的时候动画有时候会显示不出来,所以最在在baseactivity的onresume中写一个回调,当回调时调用此动画执行。
BaseActivity...
@Override
protected void onResume() {
super.onResume();
if (resume != null) {
resume.setResume();
}
}
public void setResume(IonResume resume) {
this.resume = resume;
}
private IonResume resume;
public interface IonResume {
void setResume();
}
...
thisActivity.setResume(new BaseActivity.IonResume() {
@Override
public void setResume() {
if (imageview.getVisibility()==View.VISIBLE){
Animator anim = ViewAnimationCompatUtils.createCircularReveal(imageview, xCenter, yCenter, finalRadius, 0);
anim.setDuration(800);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
try {
decorView.removeView(imageview);
imageview.setVisibility(View.GONE);
} catch (Exception e) {
e.printStackTrace();
}
}
});
anim.start();
}
}
});
Github代码下载
也欢迎大家关注我的简书、CSDN
网友评论