Android自定義控件 - 彩虹錶盤

說實話寫代碼久了,本能的會避免一些不熟悉的領域,而去做一些擅長的領域,這樣使工作顯得得心應手,但殊不知這是一種逃避行爲,只有不斷的面臨問題甚至主動製造問題,好比說我偏偏不用setVisible這種老舊的顯影方式,而是使用去使用動畫,不用常用佈局堆疊構建UI,而是使用Canvas繪製佈局,雖然說到底還是API調用師,筆者不是要歌頌那些勇於嘗試的人,只是想多個方法對條路,這也是另一種節約時間成本的方式。

進入正題

國際慣例先上效果圖

設計圖 實現效果
設計 效果

看完效果會給我打多少分?···
基本樣式已出,剩下就是精雕細琢了

按照筆者學習借鑑的套路,一般找幾個參考案例,百度,GitHub,谷歌三連,是絕對不會少的

案例一

效果: 指針旋轉 + 間隔彩虹

package com.xiaomakj.utillib.widget;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.view.View;


public class GradualView extends View {
    public static final int[] SWEEP_GRADIENT_COLORS = new int[]{Color.GREEN, Color.GREEN, Color.BLUE, Color.RED, Color.RED};
    private int tableWidth = 50;
    private Paint mPaint;
    private Path mPath;
    private RectF mTableRectF;
    //把路徑分成虛線段的
    private DashPathEffect dashPathEffect;
    //給路徑上色
    private SweepGradient mColorShader;
    //指針的路徑
    private Path mPointerPath;
    private float mCurrentDegree = 60;

    public GradualView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.BLACK);
        mPath = new Path();
        mPointerPath = new Path();
        startAnimator();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        float size = Math.min(w, h) - tableWidth * 2;
        //油表的位置方框
        mTableRectF = new RectF(0, 0, size, size);
        mPath.reset();
        //在油表路徑中增加一個從起始弧度
        mPath.addArc(mTableRectF, 60, 240);
        //計算路徑的長度
        PathMeasure pathMeasure = new PathMeasure(mPath, false);
        float length = pathMeasure.getLength();
        float step = length / 60;
        dashPathEffect = new DashPathEffect(new float[]{step / 3, step * 2 / 3}, 0);

        float radius = size / 2;
        mColorShader = new SweepGradient(radius, radius,SWEEP_GRADIENT_COLORS,null);
        //設置指針的路徑位置
        mPointerPath.reset();
        mPointerPath.moveTo(radius, radius - 20);
        mPointerPath.lineTo(radius, radius + 20);
        mPointerPath.lineTo(radius * 2 - tableWidth, radius);
        mPointerPath.close();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float dx = (getWidth() - mTableRectF.width()) / 2;
        float dy = (getHeight() - mTableRectF.height()) / 2;
        //把油表的方框平移到正中間
        canvas.translate(dx, dy);
        canvas.save();
        //旋轉畫布
        canvas.rotate(90, mTableRectF.width() / 2, mTableRectF.height() / 2);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(tableWidth);
        mPaint.setPathEffect(dashPathEffect);
        mPaint.setShader(mColorShader);
        canvas.drawPath(mPath, mPaint);
        canvas.restore();
        //還原畫筆
        mPaint.setPathEffect(null);
        mPaint.setShader(null);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(tableWidth / 10);
        canvas.save();
        canvas.rotate(150 + mCurrentDegree, mTableRectF.width() / 2, mTableRectF.height() / 2);
        canvas.drawPath(mPointerPath, mPaint);
        canvas.restore();
    }

    public void startAnimator() {
        ValueAnimator animator = ValueAnimator.ofFloat(0, 240);
        animator.setDuration(40000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.RESTART);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurrentDegree = (int) (0 + (Float) animation.getAnimatedValue());
                invalidate();
            }
        });
        animator.start();
    }
}

案例二

效果:彩虹圓弧 + 圖形定位


package com.example.yan;

        import android.content.Context;
        import android.graphics.Canvas;
        import android.graphics.Paint;
        import android.graphics.Rect;
        import android.graphics.RectF;
        import android.graphics.Shader;
        import android.graphics.SweepGradient;
        import android.util.AttributeSet;
        import android.view.View;

/**
 * Created by xiaoyanzi on 2016/3/18.
 * 漸變圓弧
 */
public class GradualView extends View {

    private Context context;
    private Paint paint;//畫筆
    private Paint paintFull;//實心圓畫筆
    private Paint textPaint;//標識字畫筆
    private Paint valuePaint;//移動小球畫筆
    private int[] mColors;//漸變色數組

    private int centerX;//中心X
    private int centerY;//中心Y
    private int srcH;//控件高度
    private float startAngle = 110;//圓弧起始角度
    private float sweepAngle = 320;//圓弧所佔度數
    private float airValue = 66;

    /**
     * 直接在代碼中調用時,使用該函數
     *
     * @param context
     */
    public GradualView(Context context) {
        super(context);
        initData(context);
    }

    /**
     * 在xml中使用自定義view時,使用這個函數
     *
     * @param context
     * @param attrs
     */
    public GradualView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initData(context);
    }

    /**
     * 可以由上一個函數中手動調用
     *
     * @param context
     * @param atrrs
     * @param defStyle 自定義函數中的attrs表示view的屬性集,defStyle表示默認的屬性資源集的id
     */
    public GradualView(Context context, AttributeSet atrrs, int defStyle) {
        super(context, atrrs, defStyle);
    }

    /**
     * 初始化
     *
     * @param context
     */
    private void initData(Context context) {
        this.context = context;
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.STROKE);
        mColors = new int[]{
                0xFF660099,//紫色
                0xFF330033,//褐色
                0xFF99FF00,//草綠色
                0xFFFFFF00,//黃色
                0xFFFF6600,//橘色
                0xFFFF0000,//紅色
                0xFF660099,//紫色

        };
        Shader s = new SweepGradient(0, 0, mColors, null);
        paint.setAntiAlias(true);//設置畫筆爲無鋸齒
        paint.setStrokeWidth(dip2px(context, 14));//線寬
        paint.setShader(s);
        paintFull = new Paint(Paint.ANTI_ALIAS_FLAG);
        paintFull.setStyle(Paint.Style.FILL_AND_STROKE);
        paintFull.setAntiAlias(true);//設置畫筆爲無鋸齒
        paintFull.setShader(s);
        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextSize(dip2px(context, 22));//設置字體大小
        textPaint.setColor(0xFFFFFFFF);
        valuePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        valuePaint.setAntiAlias(true);//設置畫筆爲無鋸齒
    }

    public void setAirValue(float airValue) {
        this.airValue = airValue;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        srcH = h;
        centerX = w / 2;
        centerY = h / 2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float r = srcH / 2 - paint.getStrokeWidth() * 0.5f - dip2px(context, 200);
//移動中心
        canvas.translate(centerX, centerY);
        RectF oval = new RectF();
        oval.left = -r;//左邊
        oval.top = -r;//上邊
        oval.right = r;//右邊
        oval.bottom = r;//下邊
        canvas.drawArc(oval, startAngle, sweepAngle, false, paint); //繪製圓弧
//繪製圓弧兩頭的小圓
        float mr = dip2px(context, 7);
        float x1 = (float) (-r * Math.sin((360 - sweepAngle) / 2 * Math.PI / 180));
        float y1 = (float) (r * Math.cos((360 - sweepAngle) / 2 * Math.PI / 180));
        canvas.drawCircle(x1, y1, mr, paintFull);
        float x2 = (float) (r * Math.sin((360 - sweepAngle) / 2 * Math.PI / 180));
        float y2 = (float) (r * Math.cos((360 - sweepAngle) / 2 * Math.PI / 180));
        canvas.drawCircle(x2, y2, mr, paintFull);
//小圓離球的距離
        float range = r + dip2px(context, 30);
        float ar = 12f;
//畫周圍小球和數字
        float ax1 = (float) (-range * Math.sin(45 * Math.PI / 180));
        float ay1 = (float) (range * Math.cos(45 * Math.PI / 180));
        canvas.drawCircle(ax1, ay1, ar, paintFull);
        canvas.drawText("0", ax1 - getTextW() * 3, ay1 + getTextH() / 2, textPaint);
        float ax2 = -range;
        float ay2 = 0;
        canvas.drawCircle(ax2, ay2, ar, paintFull);
        canvas.drawText("50", ax2 - getTextW() * 5, ay2 + getTextH() / 2, textPaint);
        float ax3 = (float) (-range * Math.sin(45 * Math.PI / 180));
        float ay3 = (float) (-range * Math.cos(45 * Math.PI / 180));
        canvas.drawCircle(ax3, ay3, ar, paintFull);
        canvas.drawText("100", ax3 - getTextW() * 7, ay3 + getTextH() / 2, textPaint);
        float ax4 = 0;
        float ay4 = -range;
        canvas.drawCircle(ax4, ay4, ar, paintFull);
        canvas.drawText("150", ax4 - getTextW() * 3, ay4 - getTextH(), textPaint);
        float ax5 = (float) (range * Math.sin(45 * Math.PI / 180));
        float ay5 = (float) (-range * Math.cos(45 * Math.PI / 180));
        canvas.drawCircle(ax5, ay5, ar, paintFull);
        canvas.drawText("200", ax5 + getTextW(), ay5 + getTextH() / 2, textPaint);
        float ax6 = range;
        float ay6 = 0;
        canvas.drawCircle(ax6, ay6, ar, paintFull);
        canvas.drawText("300", ax6 + getTextW(), ay6 + getTextH() / 2, textPaint);
        float ax7 = (float) (range * Math.sin(45 * Math.PI / 180));
        float ay7 = (float) (range * Math.cos(45 * Math.PI / 180));
        canvas.drawCircle(ax7, ay7, ar, paintFull);
        canvas.drawText("500", ax7 + getTextW(), ay7 + getTextH() / 2, textPaint);
//畫標識小球
        valuePaint.setColor(0xFFFFFFFF);
        float cx;
        float cy;
        if (airValue >= 0 && airValue <= 50) {
            cx = (float) (-r * Math.cos((45 - airValue * 0.9) * Math.PI / 180));
            cy = (float) (r * Math.sin((45 - airValue * 0.9) * Math.PI / 180));
        } else if (airValue > 50 && airValue <= 150) {
            cx = (float) (-r * Math.cos((airValue * 0.9 - 45) * Math.PI / 180));
            cy = (float) (-r * Math.sin((airValue * 0.9 - 45) * Math.PI / 180));
        } else if (airValue > 150 && airValue <= 200) {
            cx = (float) (-r * Math.cos((airValue * 0.9 - 45) * Math.PI / 180));
            cy = (float) (-r * Math.sin((airValue * 0.9 - 45) * Math.PI / 180));
        } else if (airValue > 200 && airValue <= 300) {
            cx = (float) (-r * Math.cos((airValue * 0.45 + 45) * Math.PI / 180));
            cy = (float) (-r * Math.sin((airValue * 0.45 + 45) * Math.PI / 180));
        } else if (airValue > 300 && airValue <= 500) {//此處有問題
            cx = (float) (r * Math.cos(((airValue - 300) * 0.225) * Math.PI / 180));
            cy = (float) (r * Math.sin(((airValue - 300) * 0.225) * Math.PI / 180));
        } else {
            cx = (float) (-r * Math.cos(45 * Math.PI / 180));
            cy = (float) (r * Math.sin(45 * Math.PI / 180));
        }
        canvas.drawCircle(cx, cy, dip2px(context, 11), valuePaint);
        canvas.drawCircle(cx, cy, dip2px(context, 4), paintFull);
    }

    /**
     * dip轉px
     *
     * @param context
     * @param dpValue
     * @return
     */
    private int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 獲取"正"的高度
     *
     * @return
     */
    private float getTextH() {
        Paint pFont = new Paint();
        Rect rect = new Rect();
//返回包圍整個字符串的最小的一個Rect區域
        pFont.getTextBounds("正", 0, 1, rect);
        return rect.height();
    }

    /**
     * 獲取"正"的寬度
     *
     * @return
     */
    private float getTextW() {
        Paint pFont = new Paint();
        Rect rect = new Rect();
//返回包圍整個字符串的最小的一個Rect區域
        pFont.getTextBounds("正", 0, 1, rect);
        return rect.width();
    }
}

最終章:合併大法

效果:效果如上圖

package com.xiaomakj.utillib.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.view.View;

import com.vondear.rxtool.RxTool;
import com.xiaomakj.utillib.R;


/**
 * 弧形進度條
 *
 * @author Vondear
 * @date 2015/12/03
 */
public class RxRoundProgress extends View {
    private int count;
    public static final int STROKE = 0;
    /**
     * 畫筆對象的引用
     */
    private Paint paint;
    private Path mPath;
    private Paint textPaint;
    private Paint centerPaint;
    private Paint dotPaint;
    private Paint dotTexttPaint;
    /**
     * 圓環的顏色
     */
    private int roundColor;
    /**
     * 圓環進度的顏色
     */
    private int roundProgressColor;
    /**
     * 中間進度百分比的字符串的顏色
     */
    private int textColor;
    /**
     * 中間進度百分比的字符串的字體
     */
    private float textSize;
    /**
     * 圓環的寬度
     */
    private float roundWidth;
    /**
     * 最大進度
     */
    private double max;
    /**
     * 當前進度
     */
    private double progress;
    /**
     * 是否顯示中間的進度
     */
    private boolean textIsDisplayable;
    /**
     * 進度的風格,實心或者空心
     */
    private int style;

    private int centerX;//中心X
    private int centerY;//中心Y
    private int srcH;//控件高度

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

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

    public RxRoundProgress(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        //進度條畫筆
        paint = new Paint();
        mPath = new Path();
        //文字畫筆
        textPaint = new Paint();
        //文字畫筆
        centerPaint = new Paint();
        //文字畫筆
        dotPaint = new Paint();
        //文字畫筆
        dotTexttPaint = new Paint();
        TypedArray mTypedArray = context.obtainStyledAttributes(attrs,
                R.styleable.RxRoundProgress);

        //獲取自定義屬性和默認值
        roundColor = mTypedArray.getColor(R.styleable.RxRoundProgress_roundColor, Color.WHITE);
        roundProgressColor = mTypedArray.getColor(R.styleable.RxRoundProgress_roundProgressColor, Color.parseColor("#F6B141"));
        textColor = mTypedArray.getColor(R.styleable.RxRoundProgress_textColor, Color.GREEN);
        textSize = mTypedArray.getDimension(R.styleable.RxRoundProgress_textSize1, 15);
        roundWidth = mTypedArray.getDimension(R.styleable.RxRoundProgress_roundWidth, 20);
        max = mTypedArray.getInteger(R.styleable.RxRoundProgress_max, 100);
        textIsDisplayable = mTypedArray.getBoolean(R.styleable.RxRoundProgress_textIsDisplayable, true);
        style = mTypedArray.getInt(R.styleable.RxRoundProgress_style, 0);
        mTypedArray.recycle();

        textPaint.setColor(roundColor);
        textPaint.setAntiAlias(true);
        textPaint.setTextSize(dp2px(13));

        dotPaint.setStyle(Paint.Style.STROKE);
        dotPaint.setAntiAlias(true);

        dotTexttPaint.setStyle(Paint.Style.FILL);
        dotTexttPaint.setAntiAlias(true);
        dotTexttPaint.setTextSize(dp2px(12));

        //中間分數
        centerPaint.setColor(textColor);
        centerPaint.setAntiAlias(true);
    }

    int[] mColors = new int[]{
            Color.GREEN, 0xFF12B8CA,
            Color.RED, Color.RED,
            Color.YELLOW, Color.YELLOW,
            Color.BLUE, Color.GREEN,
    };

    /**
     * dp轉px
     *
     * @param dpValue dp值
     * @return px值
     */
    public int dp2px(float dpValue) {
        final float scale = RxTool.getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        srcH = h;
        centerX = w / 2;
        centerY = h / 2;

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**
         * 畫最外層的大圓環
         */
        //向右邊取啓點
        //間距
        int margin = dp2px(2);
        int tPadding = dp2px(40);
        //獲取圓心的x座標
        int center = getWidth() / 2 - tPadding;
        //圓環的半徑
        int radius = (int) (center - roundWidth / 2);
        //用於定義的圓弧的形狀和大小的界限
        RectF innerOval = new RectF(center - radius + tPadding, center - radius + tPadding, center + radius + tPadding, center + radius + tPadding);
        int outWidth = dp2px(20);
        RectF outOval = new RectF(center - radius + tPadding - outWidth, center - radius + tPadding - outWidth, center + radius + tPadding + outWidth, center + radius + tPadding + outWidth);
        //畫外圓
        mPath.reset();
        mPath.addArc(outOval, 135, 270);
        //計算路徑的長度
        PathMeasure pathMeasure = new PathMeasure(mPath, false);
        float length = pathMeasure.getLength();
        float step = length / 60;
        DashPathEffect dashPathEffect = new DashPathEffect(new float[]{step / 3, step * 2 / 3}, 0);
        SweepGradient mColorShader = new SweepGradient(centerX, centerX, mColors, null);
        paint.setPathEffect(dashPathEffect);
        //設置彩色
        paint.setShader(mColorShader);
        //設置空心
        paint.setStyle(Paint.Style.STROKE);
        //設置圓環的寬度
        paint.setStrokeWidth(roundWidth / 2);
        //消除鋸齒
        paint.setAntiAlias(true);
        paint.setStrokeCap(Paint.Cap.BUTT);
        canvas.drawPath(mPath, paint);
        //畫內圓
        mPath.reset();
        mPath.addArc(innerOval, 135, 270);
        //消除間隔
        paint.setPathEffect(null);
        paint.setStrokeWidth(roundWidth);
        //設置彩色
        canvas.drawPath(mPath, paint);

        //放棄灰底色圓
//        paint.setStrokeCap(Paint.Cap.ROUND);
//        paint.setStrokeWidth(roundWidth);
//        paint.setColor(roundColor);
//        paint.setPathEffect(null);
//        //設置彩色
//        paint.setShader(null);
        //根據進度畫圓弧
//        canvas.drawArc(innerOval, 135, 270, false, paint);


//		canvas.drawRect(0, 0, getWidth(), getWidth(), paint);// 正方形
        centerPaint.setTextSize(dp2px(18));
        float textH = getTextH(centerPaint, ((int) getProgress()) + "");
        canvas.drawText(
                ((int) getProgress()) + "",
                (center + tPadding) - centerPaint.measureText((int) getProgress() + "") / 2,
                center + tPadding + textH + radius / 2, centerPaint);
        centerPaint.setTextSize(dp2px(14));
        float textH2 = getTextH(centerPaint, "平均成績");
        canvas.drawText(
                "平均成績",
                (center + tPadding) - centerPaint.measureText("平均成績") / 2,
                center + tPadding + textH + textH2 + margin * 2 + radius / 2, centerPaint);
        centerPaint.setTextSize(dp2px(12));
        float textH3 = getTextH(centerPaint, "已完成考試" + count + "次");
        canvas.drawText(
                "已完成考試" + count + "次",
                (center + tPadding) - centerPaint.measureText("已完成考試" + count + "次") / 2,
                center + tPadding + textH + textH2 + textH3 + margin * 3 + radius / 2, centerPaint);

        //左邊最小值
//        canvas.drawText("0分", (float) (radius - Math.sqrt(2) * (radius / 2) + 10), (float) (2 * radius - Math.sqrt(2) * (radius / 4) + 130), textPaint);
        //右邊最大值
//        canvas.drawText(getMax() + "分", (float) (radius + Math.sqrt(2) * (radius / 2) + 138), (float) (2 * radius - Math.sqrt(2) * (radius / 4) + 130), textPaint);
		/*if(progress<50){
			double money = progress*1+(Math.floor(Math.random()*getMax()));
			canvas.drawText(money+"", (center+toright) - centerPaint.measureText(money+"")/2-15, center+165, centerPaint);//右邊最大值
		}else{*/
        //}
        //右邊最大值
//        canvas.drawText("分", (center + toright) + centerPaint.measureText(RxDataTool.format2Decimals(getProgress() + "")) / 2 - 10, center + 105, dotPaint);


        int[] mColors = new int[]{
                0xFFFF0000,//紅色
                0xFFFFFF00,//黃色
                0xFF0B74FE,//藍色
                0xFF99FF00//草綠色
        };
        String[] mStrings = new String[]{
                "差",//紅色
                "中",//黃色
                "良",//藍色
                "優"//草綠色
        };
        for (int i = 0; i < mColors.length; i++) {
            dotPaint.setColor(mColors[i]);
            dotTexttPaint.setColor(mColors[i]);
            canvas.drawCircle(tPadding * 2 / 3 + i / 5f * getWidth(), getHeight() - dp2px(7.5f),
                    dp2px(5), dotPaint);
            canvas.drawText(
                    mStrings[i],
                    tPadding * 2 / 3 + i / 5f * getWidth() + getTextW(dotTexttPaint, mStrings[i]) / 2 + margin,
                    getHeight() - dp2px(10) + getTextH(dotTexttPaint, mStrings[i]) / 2,
                    dotTexttPaint);

        }
//        /**
//         * 畫進度百分比
//         */
//        paint.setStrokeWidth(0);
//        paint.setColor(textColor);
//        paint.setTextSize(textSize);
//        //設置字體
//        paint.setTypeface(Typeface.DEFAULT_BOLD);
//        //中間的進度百分比,先轉換成float在進行除法運算,不然都爲0
//        int percent = (int) (((float) progress / (float) max) * 100);
//        //測量字體寬度,我們需要根據字體的寬度設置在圓環中間
//        float textWidth = paint.measureText(percent + "%");
//
//        if (textIsDisplayable && percent != 0 && style == STROKE) {
////            canvas.drawText(percent + "%", center + toright - textWidth / 2, center + toright + textSize / 2, paint); //畫出進度百分比
//        }


        //還原畫筆
        paint.setPathEffect(null);
        paint.setShader(null);
        paint.setStyle(Paint.Style.FILL);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pointer);
        Rect bitmapRec = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        RectF pointerOval = new RectF(
                center + tPadding - bitmap.getWidth() / 2,
                center + tPadding - bitmap.getWidth() / 2,
                center + tPadding + bitmap.getHeight() / 2,
                center + tPadding + bitmap.getHeight() / 2);
        Matrix matrix = new Matrix();
        matrix.postRotate(-90-45 + 270 * ((float) progress / (float) max), bitmapRec.width() / 2, bitmapRec.height());
        matrix.postTranslate(pointerOval.centerX()-bitmap.getWidth()/2, pointerOval.centerY()-bitmap.getHeight());
        canvas.drawBitmap(bitmap, matrix, paint);
        //canvas.drawBitmap(bitmap, bitmapRec, pointerOval, paint);


        /**
         * 畫圓弧 ,畫圓環的進度
         */
        //設置進度是實心還是空心
        paint.setStrokeWidth(roundWidth); //設置圓環的寬度
        paint.setColor(roundProgressColor);  //設置進度的顏色
        paint.setAntiAlias(true);
        switch (style) {
            case STROKE: {
                paint.setStyle(Paint.Style.STROKE);
                if (progress >= 0) {
                    canvas.drawArc(innerOval, 45, (270 * ((float) progress / (float) max - 1)), false, paint);  //根據進度畫圓弧
                }
                break;
            }
            default:
                break;
        }
    }

    public synchronized double getMax() {
        return max;
    }

    /**
     * 設置進度的最大值
     *
     * @param max
     */
    public synchronized void setMax(double max) {
        if (max < 0) {
            throw new IllegalArgumentException("max not less than 0");
        }
        this.max = max;
    }

    /**
     * 獲取進度.需要同步
     *
     * @return
     */
    public synchronized double getProgress() {
        return progress;
    }

    /**
     * 設置進度,此爲線程安全控件,由於考慮多線的問題,需要同步
     * 刷新界面調用postInvalidate()能在非UI線程刷新
     *
     * @param progress
     */
    public synchronized void setProgress(double progress) {
        if (progress < 0) {
            this.progress = progress;
            //throw new IllegalArgumentException("progress not less than 0");
        }
        if (progress > max) {
            progress = max;
        }
        if (progress <= max) {
            this.progress = progress;
            postInvalidate();
        }

    }


    /**
     * 獲取"正"的高度
     *
     * @return
     */
    private float getTextH(Paint pFont, String text) {
        Rect rect = new Rect();
//返回包圍整個字符串的最小的一個Rect區域
        pFont.getTextBounds(text, 0, 1, rect);
        return rect.height();
    }

    /**
     * 獲取"正"的寬度
     *
     * @return
     */
    private float getTextW(Paint pFont, String text) {
        Rect rect = new Rect();
//返回包圍整個字符串的最小的一個Rect區域
        pFont.getTextBounds(text, 0, 1, rect);
        return rect.width();
    }

    public int getCricleColor() {
        return roundColor;
    }

    public void setCricleColor(int cricleColor) {
        this.roundColor = cricleColor;
    }

    public int getCricleProgressColor() {
        return roundProgressColor;
    }

    public void setCricleProgressColor(int cricleProgressColor) {
        this.roundProgressColor = cricleProgressColor;
    }

    public int getTextColor() {
        return textColor;
    }

    public void setTextColor(int textColor) {
        this.textColor = textColor;
    }

    public float getTextSize() {
        return textSize;
    }

    public void setTextSize(float textSize) {
        this.textSize = textSize;
    }

    public float getRoundWidth() {
        return roundWidth;
    }

    public void setRoundWidth(float roundWidth) {
        this.roundWidth = roundWidth;
    }

    public int setCount(int count) {
        return this.count;
    }

}

style

    <declare-styleable name="RxRoundProgress">
        <attr format="color" name="roundColor"/>
        <attr format="color" name="roundProgressColor"/>
        <attr format="dimension" name="roundWidth"/>
        <attr format="color" name="textColor"/>
        <attr format="dimension" name="textSize1"/>
        <attr format="integer" name="max"/>
        <attr format="boolean" name="textIsDisplayable"/>
        <attr name="style">
            <enum name="STROKE" value="0"/>
            <enum name="FILL" value="1"/>
        </attr>
    </declare-styleable>

可以看出來筆者自己寫的也是二開版本,面向對象不就是隻要結果,不講過程嗎?嘿嘿

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