自定义view(四) 方形进度条

       效果图如下:

        

      一。view的组成

      看到上图效果,大概可以确定这个view由三部分组成

       1.绕一圈的正方形

       2.中间的图形

       3.移动的正方形


       1.绘制最外层的正方形

        最外层是由12个正方形组成,并且从1到12缓慢增长,缓慢增长的过程,我是用ValueAnimator控制,同时可以看出这个动画,是由两部分组成,一部是正方形的垂直下落动画,另一部分则是最外圈正方形增长动画,具体代码如下:

        

         

   mValueAnimator = ValueAnimator.ofInt(0,13);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator)
            {
//                if (++progress >= max) {
//                    progress = max;
//                    bar_null.setProgress(progress);
//                    stopProgress();
//                    return;
//                }

                  setProgress((Integer) valueAnimator.getAnimatedValue());
                Log.e(" valueAnimator ","" +   valueAnimator.getAnimatedValue());

            }
        });



        mValueAnimator.setDuration(2500);
        mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.start();

        mValueAnimator.addListener(new Animator.AnimatorListener()
        {
            @Override
            public void onAnimationStart(Animator animator)
            {

            }

            @Override
            public void onAnimationEnd(Animator animator)
            {

            }

            @Override
            public void onAnimationCancel(Animator animator)
            {

            }

            @Override
            public void onAnimationRepeat(Animator animator)
            {

                switch (currentStatus){

                    case SQUARE:

                        currentStatus = CIRCLE;
                        break;

                    case CIRCLE:

                        currentStatus = SQUARE;
                        break;
                }


            }
        });
                

 绘制最外层的正方形是用  mCanvas.rotate(30f, mCenterX, mCenterY); 方法进行旋转,总共一圈12个正方形,360/12=30,每一圈12个正方形每一次旋转30度

绘制正方形代码如下:

int count = 0;

                Log.e("mpercent",percent + "");

                // 1.1 当前进度
                while (count++ < percent) {
                    //mCanvas.drawCircle(mCenterX, mCenterY - outerRadius + dotRadius, dotRadius, mPaint);

                    mCanvas.drawRect(mCenterX-size/2,getHeight()-size,mCenterX+size/2,getHeight(),mPaint);
                    //    mCanvas.drawRect(mCenterX-50/2,0,mCenterX+50/2,50,mPaint);
                    mCanvas.rotate(30f, mCenterX, mCenterY); //3.6f

                    Log.e(" count ",count+"");
                    Log.e(" percent ",percent+"");
                }
                // 1.2 未完成进度
                mPaint.setColor(dotBgColor);
                count--;
                while (count++ < 12) {
                    mCanvas.drawCircle(mCenterX, mCenterY - outerRadius + dotRadius, dotRadius, mPaint);

                    // mCanvas.drawRect(mCenterX-50/2,0,mCenterX+50/2,50,mPaint);
                    mCanvas.rotate(30f, mCenterX, mCenterY);
                }

这里每一次重绘需要旋转12次,按进度的变化,不断绘制红色矩形,剩余的用白色替代,不然会出现角度错乱的现象.算出每一次旋转的百分比:

percent = progress * 12 / progressMax;

2.绘制中间图形,这个比较容易了,直接调用 mCanvas.drawBitmap方法,先算出中心点的坐标,获取bitmap具体代码如下:

 mCenterX = getWidth() / 2f;
        mCenterY = getHeight() / 2f;

        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),R.mipmap.ic_launcher);

        int bitmapWidth = bitmap.getWidth();
        int bitmapHeight = bitmap.getHeight();

        mCanvas.drawBitmap(bitmap,mCenterX - bitmapWidth/2,mCenterY-bitmapHeight/2,mPaint);


3.绘制移动的矩形,这个不断的去改变矩形的左上和右下的坐标,每一次重绘时记得清空画布,不然原来图形会存在,按照百分比去不断增加剩余的高度,具体代码如下

 int movePercent = (int) ((getHeight()-size-mCenterY-bitmapHeight/2) * progress / 12);

                mCanvas.drawRect(mCenterX-size/2,mCenterY+bitmapHeight/2 + movePercent,mCenterX+size/2,mCenterY+bitmapHeight/2+size + movePercent,squarePaint);


下面贴上完整代码

public class CircleProgressBar extends View
{

    /**
     * 当前进度
     */
    private int progress;

    /**
     * 当前百分比
     */
    private int percent;

    /**
     * 最大进度
     */
    private int progressMax;
    private int dotColor;
    private int dotBgColor;
    private int showMode;
    public static final int SHOW_MODE_NULL      = 0;
    public static final int SHOW_MODE_PERCENT   = 1;
    public static final int SHOW_MODE_ALL       = 2;

    private float percentTextSize;
    private int percentTextColor;
    private boolean isPercentFontSystem;
    private int percentThinPadding;

    private String unitText;
    private float unitTextSize;
    private int unitTextColor;
    private int unitTextAlignMode;
    public static final int UNIT_TEXT_ALIGN_MODE_DEFAULT = 0;
    public static final int UNIT_TEXT_ALIGN_MODE_CN = 1;
    public static final int UNIT_TEXT_ALIGN_MODE_EN      = 2;

    private String buttonText;
    private float buttonTextSize;
    private int buttonTextColor;
    private int buttonBgColor;
    private int buttonClickColor;
    private int buttonClickBgColor;
    private float buttonTopOffset;


    private Paint mPaint;

    private float mSin_1; // sin(1°)

    private float mCenterX;
    private float mCenterY;

    private Canvas mCanvas;
    private Bitmap mBitmap;
    private Xfermode mClearCanvasXfermode;
    private Xfermode mPercentThinXfermode;

    private Context mContext;

    private Paint squarePaint;

    private ValueAnimator mValueAnimator;

    private final int SQUARE = 1005;
    private final int CIRCLE = 1006;
    private int currentStatus = 0;

    public CircleProgressBar(Context context)
    {
        this(context,null);
    }

    public CircleProgressBar(Context context, AttributeSet attrs)
    {
        this(context, attrs,0);
    }

    public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);

        this.mContext = context;
        currentStatus = SQUARE;

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleDotProgressBar);

        // 获取自定义属性值或默认值
        progressMax = ta.getInteger(R.styleable.CircleDotProgressBar_progressMax, 12);
        dotColor = ta.getColor(R.styleable.CircleDotProgressBar_dotColor, Color.RED);
        dotBgColor = ta.getColor(R.styleable.CircleDotProgressBar_dotBgColor, Color.WHITE);
        showMode = ta.getInt(R.styleable.CircleDotProgressBar_showMode, SHOW_MODE_PERCENT);

        if (showMode != SHOW_MODE_NULL) {
            percentTextSize = ta.getDimension(R.styleable.CircleDotProgressBar_percentTextSize, dp2px(30));
            percentTextColor = ta.getInt(R.styleable.CircleDotProgressBar_percentTextColor, Color.WHITE);
            isPercentFontSystem = ta.getBoolean(R.styleable.CircleDotProgressBar_isPercentFontSystem, false);
            percentThinPadding = ta.getInt(R.styleable.CircleDotProgressBar_percentThinPadding, 0);

            unitText = ta.getString(R.styleable.CircleDotProgressBar_unitText);
            unitTextSize = ta.getDimension(R.styleable.CircleDotProgressBar_unitTextSize, percentTextSize);
            unitTextColor = ta.getInt(R.styleable.CircleDotProgressBar_unitTextColor, Color.WHITE);
            unitTextAlignMode = ta.getInt(R.styleable.CircleDotProgressBar_unitTextAlignMode, UNIT_TEXT_ALIGN_MODE_DEFAULT);

            if (unitText == null) {
                unitText = "%";
            }
        }

        if (showMode == SHOW_MODE_ALL) {
            buttonText = ta.getString(R.styleable.CircleDotProgressBar_buttonText);
            buttonTextSize = ta.getDimension(R.styleable.CircleDotProgressBar_buttonTextSize, dp2px(15));
            buttonTextColor = ta.getInt(R.styleable.CircleDotProgressBar_buttonTextColor, Color.GRAY);
            buttonBgColor = ta.getInt(R.styleable.CircleDotProgressBar_buttonBgColor, Color.WHITE);
            buttonClickColor = ta.getInt(R.styleable.CircleDotProgressBar_buttonClickColor, buttonBgColor);
            buttonClickBgColor = ta.getInt(R.styleable.CircleDotProgressBar_buttonClickBgColor, buttonTextColor);
            buttonTopOffset = ta.getDimension(R.styleable.CircleDotProgressBar_buttonTopOffset, dp2px(15));
            if (buttonText == null) {
                buttonText = context.getString(R.string.CircleDotProgressBar_speed_up_one_key);
            }
        }
        ta.recycle();

        // 其他准备工作
        mSin_1 = (float) Math.sin(Math.toRadians(1)); // 求sin(1°)。角度需转换成弧度
        mPaint = new Paint();
        mPaint.setAntiAlias(true); // 消除锯齿

        
        squarePaint = new Paint();
        squarePaint.setAntiAlias(true); // 消除锯齿
        squarePaint.setColor(Color.RED);



//        mPercentTypeface = isPercentFontSystem ? Typeface.DEFAULT
//                : Typeface.createFromAsset(context.getAssets(), "fonts/HelveticaNeueLTPro.ttf");

        mClearCanvasXfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
        if (percentThinPadding != 0) {
            mPercentThinXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
        }


        mValueAnimator = ValueAnimator.ofInt(0,13);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator)
            {
//                if (++progress >= max) {
//                    progress = max;
//                    bar_null.setProgress(progress);
//                    stopProgress();
//                    return;
//                }

                  setProgress((Integer) valueAnimator.getAnimatedValue());
                Log.e(" valueAnimator ","" +   valueAnimator.getAnimatedValue());

            }
        });



        mValueAnimator.setDuration(2500);
        mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.start();

        mValueAnimator.addListener(new Animator.AnimatorListener()
        {
            @Override
            public void onAnimationStart(Animator animator)
            {

            }

            @Override
            public void onAnimationEnd(Animator animator)
            {

            }

            @Override
            public void onAnimationCancel(Animator animator)
            {

            }

            @Override
            public void onAnimationRepeat(Animator animator)
            {

                switch (currentStatus){

                    case SQUARE:

                        currentStatus = CIRCLE;
                        break;

                    case CIRCLE:

                        currentStatus = SQUARE;
                        break;
                }


            }
        });
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    private int size = 30;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制外围圆点进度
//        drawCircleDot(mCanvas);

        // 先清除上次绘制的
        mPaint.setXfermode(mClearCanvasXfermode);
        mCanvas.drawPaint(mPaint);
        mPaint.setXfermode(null);


        mCenterX = getWidth() / 2f;
        mCenterY = getHeight() / 2f;

        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),R.mipmap.ic_launcher);

        int bitmapWidth = bitmap.getWidth();
        int bitmapHeight = bitmap.getHeight();

        mCanvas.drawBitmap(bitmap,mCenterX - bitmapWidth/2,mCenterY-bitmapHeight/2,mPaint);

        Log.e(" currentStatus ", currentStatus + "");


       // mCanvas.drawRect(mCenterX-size/2,getHeight()-size,mCenterX+size/2,getHeight(),mPaint);
     //   mCanvas.drawRect(mCenterX-size/2,mCenterY+bitmapHeight/2,mCenterX+size/2,mCenterY+bitmapHeight/2+size,mPaint);
        if (percent == 12){

            mCanvas.drawRect(mCenterX-size/2,getHeight()-size,mCenterX+size/2,getHeight(),mPaint);
        }


        switch (currentStatus){

            case SQUARE:

                int movePercent = (int) ((getHeight()-size-mCenterY-bitmapHeight/2) * progress / 12);

                mCanvas.drawRect(mCenterX-size/2,mCenterY+bitmapHeight/2 + movePercent,mCenterX+size/2,mCenterY+bitmapHeight/2+size + movePercent,squarePaint);
               // mCanvas.drawRect(mCenterX-size/2,mCenterY+bitmapHeight + movePercent ,mCenterX+size/2,mCenterY+bitmapHeight+size + movePercent,squarePaint);
                break;

            case CIRCLE:


                // 计算圆点半径
                float outerRadius = (getWidth() < getHeight() ? getWidth() : getHeight()) / 2f;
                mCenterX = getWidth() / 2f;
                mCenterY = getHeight() / 2f;

                // outerRadius = innerRadius + dotRadius
                // sin((360°/200)/2) = sin(0.9°) = dotRadius / innerRadius;
                // 为了让圆点饱满一些,把角度0.9°增加0.1°到1°
                float dotRadius = mSin_1 * outerRadius / (1 + mSin_1);


                // 画进度
                mPaint.setColor(dotColor);
                mPaint.setStyle(Paint.Style.FILL);
                int count = 0;

                Log.e("mpercent",percent + "");

                // 1.1 当前进度
                while (count++ < percent) {
                    //mCanvas.drawCircle(mCenterX, mCenterY - outerRadius + dotRadius, dotRadius, mPaint);

                    mCanvas.drawRect(mCenterX-size/2,getHeight()-size,mCenterX+size/2,getHeight(),mPaint);
                    //    mCanvas.drawRect(mCenterX-50/2,0,mCenterX+50/2,50,mPaint);
                    mCanvas.rotate(30f, mCenterX, mCenterY); //3.6f

                    Log.e(" count ",count+"");
                    Log.e(" percent ",percent+"");
                }
                // 1.2 未完成进度
                mPaint.setColor(dotBgColor);
                count--;
                while (count++ < 12) {
                    mCanvas.drawCircle(mCenterX, mCenterY - outerRadius + dotRadius, dotRadius, mPaint);

                    // mCanvas.drawRect(mCenterX-50/2,0,mCenterX+50/2,50,mPaint);
                    mCanvas.rotate(30f, mCenterX, mCenterY);
                }
                break;
        }





        canvas.drawBitmap(mBitmap, 0, 0, null);
    }



    /**
     * 绘制圆点进度
     * @param canvas 画布
     */
    private void drawCircleDot(Canvas canvas) {
        // 先清除上次绘制的
        mPaint.setXfermode(mClearCanvasXfermode);
        mCanvas.drawPaint(mPaint);
        mPaint.setXfermode(null);

        // 计算圆点半径
        float outerRadius = (getWidth() < getHeight() ? getWidth() : getHeight()) / 2f;
        mCenterX = getWidth() / 2f;
        mCenterY = getHeight() / 2f;

        // outerRadius = innerRadius + dotRadius
        // sin((360°/200)/2) = sin(0.9°) = dotRadius / innerRadius;
        // 为了让圆点饱满一些,把角度0.9°增加0.1°到1°
        float dotRadius = mSin_1 * outerRadius / (1 + mSin_1);


        // 画进度
        mPaint.setColor(dotColor);
        mPaint.setStyle(Paint.Style.FILL);
        int count = 0;



        // 1.1 当前进度
        while (count++ < percent) {
            //mCanvas.drawCircle(mCenterX, mCenterY - outerRadius + dotRadius, dotRadius, mPaint);

            mCanvas.drawRect(mCenterX-size/2,getHeight()-size,mCenterX+size/2,getHeight(),mPaint);
        //    mCanvas.drawRect(mCenterX-50/2,0,mCenterX+50/2,50,mPaint);
            mCanvas.rotate(30f, mCenterX, mCenterY); //3.6f

            Log.e(" count ",count+"");
            Log.e(" percent ",percent+"");
        }
        // 1.2 未完成进度
        mPaint.setColor(dotBgColor);
        count--;
        while (count++ < 12) {
            mCanvas.drawCircle(mCenterX, mCenterY - outerRadius + dotRadius, dotRadius, mPaint);

           // mCanvas.drawRect(mCenterX-50/2,0,mCenterX+50/2,50,mPaint);
            mCanvas.rotate(30f, mCenterX, mCenterY);
        }

    }


    private int dp2px(int dp) {
        float density = getContext().getResources().getDisplayMetrics().density;
        return (int) (dp * density + .5f);
    }


    /**
     * Setter and Getter
     */

    public synchronized int getProgressMax() {
        return progressMax;
    }

    public synchronized void setProgressMax(int progressMax) {
        if (progressMax < 0) {
            throw new IllegalArgumentException("progressMax mustn't smaller than 0");
        }
        this.progressMax = progressMax;
    }

    public synchronized int getProgress() {
        return progress;
    }

    /**
     * 设置进度
     * 同步,允许多线程访问
     * @param progress 进度
     */
    public synchronized void setProgress(int progress) {
        if (progress < 0 || progress > progressMax) {
            throw new IllegalArgumentException(String.format(getResources().getString(R.string.CircleDotProgressBar_progress_out_of_range), progressMax));
        }
        this.progress = progress;
        percent = progress * 12 / progressMax;
        postInvalidate(); // 可以直接在子线程中调用,而invalidate()必须在主线程(UI线程)中调用
    }



          

       

       

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值