背景
最近在使用某一款天气软件的时候发现了它的一个日出日落的动画,感觉还不错,后面就自己动手撸了一个源码地址。
分析
我们先对这个动画元素进行分析:
- 需要一条曲线。
- 需要一个沿着曲线运动的小太阳。
- 需要一个跟着太阳一起运动的阴影面。
好了我们直接开始
首先我们定义一个自定义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();
最后附上源码地址和简单看一下效果图: