Android自定義View-記錄一個簡單卻又常見的效果實現

上週遇到一個需求,用一個圓形進度條的形式來展示某項操作所佔的比例,雖然類似的輪子已經有很多了,但是這種簡單的自定義View個人覺得有時間的話,還是自己寫寫比較好。

首先來看一下效果圖:

實現效果

分析: 從效果圖可以看到,這個效果整體分爲以下幾部分:

  • 背景圓環
  • 進度圓弧
  • 終點小圓圈(進度爲0和進度爲100%的時候應當沒有)
  • 內部三行文字

怎麼實現: 分析出整體框架之後,思路其實已經很簡單了,我是這樣實現的:

  1. 畫背景圓
  2. 按照當前進度計算出掃過的弧度來畫一個圓弧
  3. 以第二步的圓弧結束位置爲座標,畫兩個大小不同的實心圓,達到設計效果
  4. 分別畫三行文字

第三步中,在確定圓弧終點位置的時候用到了三角函數,這裏簡單畫了一個圖,很好理解:

三角函數計算圓弧終點位置座標

以頂點爲起點,圓半徑爲r,圓弧掃過的角度爲α。

代碼 簡單列下主要代碼,完整代碼地址放在了文字末尾。 1.爲了更加靈活,我這裏提供了很多屬性用於用戶自己來設置:

    private String title;
    private String num;
    private String unit;

    private float titleTextsize;
    private float numTextsize;
    private float unitTextsize;

    private int titleTextColor;
    private int numTextColor;
    private int unitTextColor;

    private float backCircleWidth;
    private float outerCircleWidth;

    private int backCircleColor;
    private int outerCircleColor;

    private float endCircleWidth;
    private int endCircleColor;

2.爲了代碼更加清晰,設置瞭如下Paint

private Paint backCirclePaint,//畫背景圓
            outerCirclePaint,//畫進度圓弧
            endCirclePaint,//畫終點實心大圓
            endCirclePaint2,//畫終點實心小圓
            titlePaint,//畫第一行文字
            numPaint,//畫第二行文字
            unitPaint;//畫第三行文字

3.在onDraw方法中實現繪製操作

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

        int centerX = width / 2;
        int centerY = height / 2;

        //計算半徑
        float radius = (width / 2) - outerCircleWidth + (outerCircleWidth - backCircleWidth) / 2;


        //畫背景圓
        canvas.drawCircle(centerX, centerY, radius, backCirclePaint);

        //根據進度話掃過一定角度的圓弧
        RectF rectF = new RectF(outerCircleWidth / 2 + backCircleWidth / 2, outerCircleWidth / 2 + backCircleWidth / 2, width - outerCircleWidth / 2 - backCircleWidth / 2, height - outerCircleWidth / 2 - backCircleWidth / 2);
        canvas.drawArc(rectF, -90, 360 * currentPercent, false, outerCirclePaint);

        //畫三行文字
        Rect textRect = new Rect();

        titlePaint.getTextBounds(title, 0, title.length(), textRect);
        canvas.drawText(title, width / 2 - textRect.width() / 2, height / 4 + textRect.height() / 2, titlePaint);

        numPaint.getTextBounds(num, 0, num.length(), textRect);
        canvas.drawText(num, width / 2 - textRect.width() / 2, height / 2 + textRect.height() / 2, numPaint);

        unitPaint.getTextBounds(unit, 0, unit.length(), textRect);
        canvas.drawText(unit, width / 2 - textRect.width() / 2, height * 2 / 3 + textRect.height() / 2, unitPaint);


        //我這裏規定進度在0~100%的時候纔會畫終點小圓,可以自由改動
        if (currentPercent < 1 && currentPercent > 0) {
            canvas.drawCircle(centerX + rectF.width() / 2 * (float) Math.sin(360 * currentPercent * Math.PI / 180),
                    centerY - rectF.width() / 2 * (float) Math.cos(360 * currentPercent * Math.PI / 180), endCircleWidth / 2, endCirclePaint);


            canvas.drawCircle(centerX + rectF.width() / 2 * (float) Math.sin(360 * currentPercent * Math.PI / 180),
                    centerY - rectF.width() / 2 * (float) Math.cos(360 * currentPercent * Math.PI / 180), endCircleWidth / 4, endCirclePaint2);

        }
    }

完整代碼地址

代碼

切換到progressviewwithcircle這個moudle運行即可看到效果,有興趣的小夥伴可以看下,希望大佬們有其他更好的實現方式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章