Android一个个性的自定义progressbar

废话不多说,直接上代码,对于这种规则的动画,希望能给一些朋友一些启发,这里的实现是和> 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;
}
欢迎指正
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值