废话不多说,直接上代码,对于这种规则的动画,希望能给一些朋友一些启发,这里的实现是和> http://www.see-source.com/androidwidget/detail.html?wid=108一样的效果,逻辑相对简单。
public class CustomProgressBar extends View {
private static final int SHAPE_RECT = 0, SHAPE_CIRCLE = 1, SHAPE_TRIANGLE = 2;
private Paint mRect, mCircle, mTriangle, mOval;// 画笔
private int mShape;//画图的标记
private int mHeight;
private float x, y;//原点位置
private int angle;//角度
private float r;//半径
private int mAngleRise = 5;//角度增量
private boolean isDown = false;//是否是下降
private long times = 0;
private int totalTimes = 50;
public CustomProgressBar(Context context) {
super(context);
init();
}
public CustomProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mHeight = getHeight();
}
@Override
protected void onDraw(Canvas canvas) {
//不同的形状
if (mShape == SHAPE_TRIANGLE) {
drawPoints(canvas, trianglePoints(x, -y, r, angle), mTriangle);
} else if (mShape == SHAPE_RECT) {
drawPoints(canvas, rectPoints(x, -y, r, angle), mRect);
} else if (mShape == SHAPE_CIRCLE) {
drawCircle(canvas, x, y, r);
}
//影子
drawShadow(canvas, y, mOval);
postInvalidate();
//更改形状和远点位置
changeYandShape();
}
/**
* 初始化方法
*/
private void init() {
mRect = new Paint();
mRect.setColor(0xffff0000);
mRect.setAntiAlias(true);
mRect.setStyle(Paint.Style.FILL);
mCircle = new Paint();
mCircle.setAntiAlias(true);
mCircle.setColor(0xff0000ff);
mCircle.setStyle(Paint.Style.FILL);
mTriangle = new Paint();
mTriangle.setColor(0xff00ff00);
mTriangle.setAntiAlias(true);
mTriangle.setStyle(Paint.Style.FILL);
mOval = new Paint();
mOval.setColor(0xff000000);
mOval.setAntiAlias(true);
mOval.setStyle(Paint.Style.FILL);
mShape = SHAPE_TRIANGLE;
x = 30;
y = 30;
angle = 0;
r = 30;
}
/**
* 模拟现实的下降和上升
* 通过加速度,最高点速度为0,长度l为mHeight - 2 * r,times为draw所用的时间和,
* 假设用totalTimes的时间就可以走完从高到低的位置,
* 则a*t*t/2 = l;求出加速度
* 以此可以根据时间求出每次draw的时候y的位置
* <p/>
* 设置一个加速度,就可以求出每次draw的时候所在的位置了
*/
private void changeYandShape() {
if (y <= r) {
isDown = true;
}
if (y >= mHeight - r) {
isDown = false;
if (mShape == SHAPE_TRIANGLE) {
mShape = SHAPE_RECT;
} else if (mShape == SHAPE_RECT) {
mShape = SHAPE_CIRCLE;
} else if (mShape == SHAPE_CIRCLE) {
mShape = SHAPE_TRIANGLE;
}
}
if (isDown) {
times++;
//根据总长度和总的需要的次数来求出time增加的时候的位置
y = (mHeight - 2 * r) / (totalTimes * totalTimes) * times * times + r;
} else {
times--;
y = (mHeight - 2 * r) / (totalTimes * totalTimes) * times * times + r;
}
angle += mAngleRise;
}
/**
* 三角形的三个点
* 通过三角函数获得,角度每次增加120
*
* @param x
* @param y
* @param r
* @param ang
* @return
*/
private List<Point> trianglePoints(float x, float y, float r, int ang) {
List<Point> points = new ArrayList<>();
Point point1 = new Point();
point1.x = (float) (Math.cos(Math.PI * (ang) / 180) * r) + x;
point1.y = (float) (Math.sin(Math.PI * (ang) / 180) * r) + y;
points.add(point1);
Point point2 = new Point();
point2.x = (float) (Math.cos(Math.PI * (ang + 120) / 180) * r) + x;
point2.y = (float) (Math.sin(Math.PI * (ang + 120) / 180) * r) + y;
points.add(point2);
Point point3 = new Point();
point3.x = (float) (Math.cos(Math.PI * (ang + 240) / 180) * r) + x;
point3.y = (float) (Math.sin(Math.PI * (ang + 240) / 180) * r) + y;
points.add(point3);
return points;
}
/**
* 根据y位置去计算影子的大小
*/
private void drawShadow(Canvas canvas, float y, Paint paint) {
RectF oval = new RectF();//RectF对象
float left = r - y * r / mHeight;//左边
oval.top = mHeight - 5;//上边
float right = r + y * r / mHeight;//右边
oval.bottom = mHeight;//下边
oval.left = left;
oval.right = right;
canvas.drawOval(oval, paint);//绘制椭圆
}
/**
* 正方形的四个点
* 通过三角函数获得,角度增加90
*
* @param x
* @param y
* @param r
* @param ang
* @return
*/
private List<Point> rectPoints(float x, float y, float r, int ang) {
List<Point> points = new ArrayList<>();
Point point1 = new Point();
point1.x = (float) (Math.cos(Math.PI * (ang + 45) / 180) * r) + x;
point1.y = (float) (Math.sin(Math.PI * (ang + 45) / 180) * r) + y;
points.add(point1);
Point point2 = new Point();
point2.x = (float) (Math.cos(Math.PI * (ang + 135) / 180) * r) + x;
point2.y = (float) (Math.sin(Math.PI * (ang + 135) / 180) * r) + y;
points.add(point2);
Point point3 = new Point();
point3.x = (float) (Math.cos(Math.PI * (ang + 225) / 180) * r) + x;
point3.y = (float) (Math.sin(Math.PI * (ang + 225) / 180) * r) + y;
points.add(point3);
Point point4 = new Point();
point4.x = (float) (Math.cos(Math.PI * (ang + 315) / 180) * r) + x;
point4.y = (float) (Math.sin(Math.PI * (ang + 315) / 180) * r) + y;
points.add(point4);
return points;
}
/**
* 根据点画图形
*
* @param canvas
* @param points
* @param paint
*/
private void drawPoints(Canvas canvas, List<Point> points, Paint paint) {
Path path = new Path();
for (int i = 0; i < points.size(); i++) {
Point point = points.get(i);
if (i == 0) {
//canvas坐标和数学坐标相反,所以传入相反的y
path.moveTo(point.x, -point.y);
} else {
path.lineTo(point.x, -point.y);
}
}
path.close();
canvas.drawPath(path, paint);
}
private void drawCircle(Canvas canvas, float x, float y, float r) {
canvas.drawCircle(x, y, r - 3, mCircle);
}
/**
* 自定义的点
*/
class Point {
float x;
float y;
}
欢迎指正