附上github:https://github.com/covetcode/CircularRevealLayout
圓形揭示動畫在很多情況下都可以使用萎庭,比如說轉場、打開popupwidow和覆蓋一層新的view。
官方也提供了一個類專門提供這個動畫的封裝:
ViewAnimationUtils.createCircularReveal(View view,
int centerX, int centerY, float startRadius, float endRadius)
然而這個方法必須api 5.0以上才能使用雳刺,既然如此不如自己動手造輪子。
思路:
1.只負責顯示的范圍仲锄,所以繼承自FrameLayout,具體顯示的內容由Child負責湃鹊。
2.如何控制child顯示的區(qū)域儒喊?在dispatchDraw中調用canvas.clipPath(Path path)把需要顯示的區(qū)域裁剪出來。
3.如何顯示圓币呵?
mCirclePath.reset();
mCirclePath.addCircle(float x, float y, float radius, Direction dir)
4.動畫用ValueAnimator怀愧。
具體流程:
/**
* 開始揭示動畫
* @param x 動畫開始位置的x值
* @param y 動畫開始位置的y值
*/
public void revealLayout(int x, int y){
mCenterX = x;
mCenterY = y;
computeFarthest();
computeVisibleRegion();
if (mAnimator == null) {
mAnimator = ValueAnimator.ofFloat(0,1);
mAnimator.setDuration(DEFAULT_ANIMATION_DURATION);
mAnimator.setInterpolator(new DecelerateInterpolator());
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAnimationValue = (float) animation.getAnimatedValue();
postInvalidate((int) (mVisibleRectF.left*mAnimationValue),(int) (mVisibleRectF.top*mAnimationValue)
,(int) (mVisibleRectF.right*mAnimationValue),(int) (mVisibleRectF.bottom*mAnimationValue));
}
});
}
mAnimator.start();
}
開始動畫,傳入動畫開始的坐標值xy余赢。
computeFarthest()計算動畫開始點與Layout四個角的最遠距離芯义,即圓形為最大時的半徑。
computeVisibleRegion()計算圓形顯示區(qū)域的外界矩形妻柒,用于postInvalidate()時指定刷新的區(qū)域扛拨,減少繪制開銷。
@Override
protected void dispatchDraw(Canvas canvas) {
if (mAnimationValue == 0){
return;
}
canvas.save();
mCirclePath.reset();
mCirclePath.addCircle(mCenterX,mCenterY,mFarthest*mAnimationValue, Path.Direction.CW);
canvas.clipPath(mCirclePath);
super.dispatchDraw(canvas);
canvas.restore();
}
動畫開始前不繪制Layout里的內容举塔,動畫開始后根據mAnimationValue的值改變圓形的大小绑警。mFarthest為之前通過computeFarthest()計算出來的結果。