背景
最近在使用某一款天氣軟件的時候發現了它的一個日出日落的動畫,感覺還不錯,后面就自己動手擼了一個源碼地址。
分析
我們先對這個動畫元素進行分析:
- 需要一條曲線。
- 需要一個沿著曲線運動的小太陽。
- 需要一個跟著太陽一起運動的陰影面。
好了我們直接開始
首先我們定義一個自定義View,然后初始化一些我們上面分析到的元素
//曲線初始化
mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPathPaint.setStyle(Paint.Style.STROKE);
mPathPaint.setStrokeWidth(2);
mPathPaint.setColor(Color.parseColor("#ffffff"));
PathEffect effects = new DashPathEffect(new float[]{10, 10, 10, 10}, 0);
mPathPaint.setPathEffect(effects);
//日出動畫陰影部分初始化
mAnmationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mAnmationPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mAnmationPaint.setColor(Color.parseColor("#32ffffff"));
//開始坐標的XY
mStartPointX = dp2px(9);
mStartPointY = dp2px(80);
//結束坐標的XY
mEndPointX = dp2px(139);
mEndPointY = mStartPointY;
//太陽的移動坐標的XY
mMovePointX = mStartPointX;
mMovePointY = mStartPointY;
//圓的半徑
mRadius = dp2px(74);
//圓心坐標
mCirclePointX = dp2px(74);
mCirclePointY = dp2px(115);
//圓的初始化
mRectF = new RectF(mCirclePointX - mRadius, mCirclePointY - mRadius, mCirclePointX + mRadius, mCirclePointY + mRadius);
接下來就是我們繪制的代碼
if (isNeedSun) {
//畫曲線
canvas.save();
canvas.clipRect(mStartPointX, 0, mEndPointX, mStartPointY, Region.Op.INTERSECT);
canvas.clipRect(mMovePointX - mBitmapW / 2, mMovePointY - mBitmapH / 2, mMovePointX + mBitmapW / 2, mMovePointY + mBitmapH / 2, Region.Op.DIFFERENCE);
canvas.drawArc(mRectF, 200, 140, true, mPathPaint);
//畫透明背景用圓的角度來控制
canvas.clipRect(mStartPointX, 0, mMovePointX, mStartPointY, Region.Op.INTERSECT);
canvas.drawArc(mRectF, 200, 140, true, mAnmationPaint);
canvas.restore();
//畫小太陽
canvas.drawBitmap(mSunBitmap, mMovePointX - mBitmapW, mMovePointY - mBitmapH, null);
} else if (mNotUp || mHasDown) {
//畫曲線
canvas.save();
canvas.clipRect(mMovePointX - mBitmapW / 2, mMovePointY - mBitmapH / 2, mMovePointX + mBitmapW / 2, mMovePointY + mBitmapH / 2, Region.Op.DIFFERENCE);
canvas.clipRect(0, 0, getWidth(), mStartPointY, Region.Op.INTERSECT);
canvas.drawCircle(mCirclePointX, mCirclePointY, mRadius, mPathPaint);
canvas.restore();
if (mNotUp) {
//畫小太陽
canvas.drawBitmap(mSunBitmap, mStartPointX - mBitmapW, mStartPointY - mBitmapH, null);
} else {
canvas.drawBitmap(mSunBitmap, mEndPointX - mBitmapW, mEndPointY - mBitmapH, null);
}
} else {
//這里不繪制小太陽,只有曲線
canvas.save();
canvas.clipRect(0, 0, getWidth(), mStartPointY, Region.Op.INTERSECT);
canvas.drawCircle(mCirclePointX, mCirclePointY, mRadius, mPathPaint);
canvas.restore();
}
最后就是通過我們外部的控制來實現小太陽的動畫
mSunBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.daily_deatil_sun);
mBitmapW = mSunBitmap.getWidth() / 2;
mBitmapH = mSunBitmap.getHeight() / 2;
mNotUp = false;
isNeedSun = true;
mHasDown = false;
ValueAnimator progressAnimator = ValueAnimator.ofFloat(210, 330);
progressAnimator.setDuration(3000);
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
/**每次在初始值和結束值之間產生的一個平滑過渡的值,逐步去更新進度*/
float x = (float) animation.getAnimatedValue();
if ((x - 210) <= (120 * a)) {
mMovePointX = mCirclePointX + (int) (mRadius * (Math.cos(x * 3.14 / 180)));
mMovePointY = mCirclePointY + (int) (mRadius * (Math.sin(x * 3.14 / 180)));
invalidate();
} else {
return;
}
}
});
progressAnimator.setInterpolator(new LinearInterpolator());
progressAnimator.start();
最后附上源碼地址和簡單看一下效果圖:
曲線效果圖