android动画(转)

  • content
    {:toc}

    要求

实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void init(Context context, int width, int height) {
mContext = context;
mWidth = width;
mHeight = height;

//初始化画背景的paint
mBgPaint = new Paint();
mRect = new Rect();

initCirclePaint(); //初始化画旋转的外圆paint
initBallPaint(); //初始化变成点的piant
initForkPaint(); //初始化叉叉的paint
initLinePaint(); //初始化画勾勾的paint

}

画外圆paint

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* 画外围转的圆
*/
private void initCirclePaint() {
mCirclePaint = new Paint();
mCirclePaint.setStyle(Paint.Style.STROKE);
mCirclePaint.setStrokeWidth(10);
mCirclePaint.setAntiAlias(true);
mCirclePaint.setStrokeCap(Paint.Cap.ROUND);

int[] colors = {Color.WHITE, Color.TRANSPARENT};
mPositions = new float[2];
mPositions[0] = 0.7f;
mPositions[1] = .9f;

//渐变
SweepGradient sweepGradient = new SweepGradient(200, 200, colors, mPositions);
Matrix matrix = new Matrix();
matrix.setRotate(130, 200, 200);
sweepGradient.setLocalMatrix(matrix);
mCirclePaint.setShader(sweepGradient);

int padding = 20;
mRectF = new RectF();
mRectF.set(0 + padding, 0 + padding, mWidth - padding, mHeight - padding);

}

画叉 paint

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 画叉叉
*/
private void initForkPaint() {
mPath = new Path();

mForkPaint = new Paint();
mForkPaint.setStrokeCap(Paint.Cap.ROUND);
mForkPaint.setAntiAlias(true);
mForkPaint.setStrokeWidth(10);
mForkPaint.setStyle(Paint.Style.STROKE);
mForkPaint.setColor(Color.WHITE);
}

画小球

1
2
3
4
5
6
7
8
9
10
/**
* 画小球
*/
private void initBallPaint() {
mBallPaint = new Paint();
mBallPaint.setAntiAlias(true);
mBallPaint.setStyle(Paint.Style.FILL);
mBallPaint.setColor(Color.WHITE);

}

画勾勾

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 画勾勾
*/
private void initLinePaint() {
int centerX = mWidth / 2;
int centerY = mHeight / 2;

mLinePaint = new Paint();
mLinePaint.setAntiAlias(true);
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setStrokeWidth(10);
mLinePaint.setColor(Color.WHITE);
mLinePaint.setStrokeCap(Paint.Cap.ROUND);

//勾勾的线
mGPath = new Path();
float leftPathHeight = mHeight * 0.4f / 2f;
mGPath.moveTo(centerX, centerY + leftPathHeight);
mGPath.lineTo((float) (centerX - leftPathHeight / Math.tan(40 * Math.PI / 180)), centerY);
mPathMeasure = new PathMeasure();
mPathMeasure.setPath(mGPath, false);

mLineRightPaint = new Paint();
mLineRightPaint.setAntiAlias(true);
mLineRightPaint.setStyle(Paint.Style.STROKE);
mLineRightPaint.setStrokeWidth(10);
mLineRightPaint.setColor(Color.WHITE);
mLineRightPaint.setStrokeCap(Paint.Cap.ROUND);

mGRightPath = new Path();
float rightPathHeight = mHeight * 0.4f / 2f;
mGRightPath.moveTo(centerX, centerY + rightPathHeight);
mGRightPath.lineTo((float) (centerX + rightPathHeight / Math.tan(40 * Math.PI / 180)), centerY - rightPathHeight);
mPathRightMeasure = new PathMeasure();
mPathRightMeasure.setPath(mGRightPath, false);
}

最终onDraw

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
 @Override
public void draw(@NonNull Canvas canvas) {

//防止还有个 半径为10的小球还在,所以清理的画布
if (mDashPathEffect != null) {
canvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR);
canvas.drawColor(Color.WHITE);
}

int centerX = mWidth / 2;
int centerY = mHeight / 2;

mBgPaint.setColor(Color.GREEN);
mBgPaint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(0, 0, mWidth, mHeight, 30, 30, mBgPaint);


//旋转外面的圆圈
canvas.save();
canvas.rotate(90 + mRotate, mWidth / 2f, mHeight / 2f);
//画运动圆弧
canvas.drawArc(mRectF, -180, 240, false, mCirclePaint);

canvas.restore();


prepareForkPath(centerX, centerY);
//画叉
canvas.drawPath(mPath, mForkPaint);


if (mDashPathEffect != null) {
//把小球变小
canvas.drawCircle(centerX, centerY - mMoveHeight, 5, mBallPaint);
canvas.drawPath(mGPath, mLinePaint);
canvas.drawPath(mGRightPath, mLineRightPaint);
} else {
//画移动后的小球
canvas.drawCircle(centerX, centerY - mMoveHeight, 10, mBallPaint);
}

}

private void prepareForkPath(int centerX, int centerY) {
double cos45Value = Math.cos(45 * Math.PI / 180);
double sin5Value = Math.sin(45 * Math.PI / 180);
float len = mForkLenScale * centerX;

Log.e(TAG, "draw: " + len);

//左上角
float x1 = (float) (centerX - len * cos45Value);
float y1 = (float) (centerY - len * sin5Value);

//右上角
float x2 = (float) (centerX + len * cos45Value);
float y2 = (float) (centerY - len * sin5Value);

//右下角
float x3 = (float) (centerX + len * cos45Value);
float y3 = (float) (centerY + len * sin5Value);

//左下角
float x4 = (float) (centerX - len * cos45Value);
float y4 = (float) (centerY + len * sin5Value);

//要进行reset,不然一直运行就会卡顿,并且一直是把叉在那里看不到变化
mPath.reset();

mPath.moveTo(x1, y1);
mPath.lineTo(x3, y3);
mPath.moveTo(x2, y2);
mPath.lineTo(x4, y4);
}

启动动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
 /**
* 启动动画
*/
public void startAnimator() {

AnimatorSet animatorSet = new AnimatorSet();

ValueAnimator rotateAnimator = ValueAnimator.ofFloat(0, 1);
rotateAnimator.setDuration(1000);
//有了这个加速器 中间就不会产生停顿了
rotateAnimator.setInterpolator(new LinearInterpolator());
rotateAnimator.setRepeatCount(2);
rotateAnimator.setRepeatMode(ValueAnimator.RESTART);
rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
mRotate = -360 * animatedValue;
// if (mForkLenScale != 0) {
// mForkLenScale = 1 - 0.6f * animatedValue;
// }
invalidateSelf();
}
});
// rotateAnimator.start();


ValueAnimator forkAnimator = ValueAnimator.ofFloat(0.6f, 0);
forkAnimator.setDuration(1000);
//有了这个加速器 中间就不会产生停顿了
forkAnimator.setInterpolator(new LinearInterpolator());
// forkAnimator.setRepeatCount(ValueAnimator.INFINITE);
// forkAnimator.setRepeatMode(ValueAnimator.RESTART);
forkAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
mForkLenScale = animatedValue;
if (mForkLenScale == 0) {
mForkPaint.setAlpha(0);
}
invalidateSelf();
}
});
// forkAnimator.start();

ValueAnimator ballAnimator = ValueAnimator.ofFloat(0, mHeight * 0.6f / 2f, -mHeight * 0.6f / 2f, -mHeight * 0.4f / 2f);
ballAnimator.setDuration(1500);
ballAnimator.setStartDelay(1000);
//有了这个加速器 中间就不会产生停顿了
ballAnimator.setInterpolator(new LinearInterpolator());
// forkAnimator.setRepeatCount(ValueAnimator.INFINITE);
// forkAnimator.setRepeatMode(ValueAnimator.RESTART);
ballAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
mMoveHeight = animatedValue;
invalidateSelf();
}
});
// ballAnimator.start();

ValueAnimator gAnimator = ValueAnimator.ofFloat(1, 0);
gAnimator.setDuration(500);
gAnimator.setStartDelay(2500);
//有了这个加速器 中间就不会产生停顿了
gAnimator.setInterpolator(new LinearInterpolator());
gAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
mDashPathEffect = new DashPathEffect(new float[]{mPathMeasure.getLength(), mPathMeasure.getLength()}, mPathMeasure.getLength() * animatedValue);
mDashPathRightEffect = new DashPathEffect(new float[]{mPathRightMeasure.getLength(), mPathRightMeasure.getLength()}, mPathRightMeasure.getLength() * animatedValue);
mLinePaint.setPathEffect(mDashPathEffect);
mLineRightPaint.setPathEffect(mDashPathRightEffect);
invalidateSelf();
}
});
// gAnimator.start();

animatorSet.playTogether(rotateAnimator, forkAnimator, ballAnimator, gAnimator);

animatorSet.start();
}

适当的的地方可以用用Interpolator,有更加吸引人的地方。

总结:

  1. path绘制的时候要进行reset,否则就会一直画,然后执行的动画去绘制的时候就会进行卡顿
  2. 可以用canvas的旋转来进行旋转动画绘制
  3. SweepGradient 或者 LinearGradient等 position是传递 0-1的值就好了
  4. setInterpolator(new LinearInterpolator()) 这样,repeatCount多次以后就不会停顿一下,再继续下一个动画
  5. repeatCount是指重复的次数,所以2表示重复2次,一开始的那一次不包含在内,也就是说肉眼看到是有3次的动画
  6. 清空某个点什么的可以用 canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);来进行全部清除,只要保证后面不再执行绘制这个清除的内容就可以了