Created
June 4, 2015 03:57
-
-
Save ishitcno1/875933317d91eca68f0f to your computer and use it in GitHub Desktop.
android dial view
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.content.res.Resources; | |
import android.graphics.Canvas; | |
import android.graphics.Color; | |
import android.graphics.Paint; | |
import android.graphics.Path; | |
import android.graphics.Point; | |
import android.graphics.Rect; | |
import android.graphics.RectF; | |
import android.graphics.SweepGradient; | |
import android.os.Handler; | |
import android.util.AttributeSet; | |
import android.view.Display; | |
import android.view.View; | |
import android.view.WindowManager; | |
/** | |
* Created by albert on 15-6-1. | |
*/ | |
public class DialView extends View { | |
/** | |
* 基本度数 | |
*/ | |
private static final int BASE_DEGREE = 180; | |
private Context mContext; | |
private Paint mPaint = new Paint(); | |
private RectF mRectF = new RectF(); | |
private Rect mRect = new Rect(); | |
private Path mPath = new Path(); | |
private SweepGradient mDialSweepGradient; | |
/** | |
* 屏幕宽度 | |
*/ | |
private int mDisplayWidth; | |
/** | |
* 屏幕高度 | |
*/ | |
private int mDisplayHeight; | |
/** | |
* 刻度盘超越180的度数 | |
*/ | |
private int mOverDegree = 20; | |
/** | |
* 边距比例 | |
*/ | |
private float mMarginPercent = 0.1f; | |
/** | |
* 边距,由mMarginPercent与mDisplayWidth计算而来 | |
*/ | |
private int mLeft; | |
/** | |
* 上边距 | |
*/ | |
private int mTop = dpToPx(50); | |
/** | |
* 超越半径的偏移高度 | |
*/ | |
private int mOverHeight; | |
/** | |
* 图表高度 | |
*/ | |
private int mHeight; | |
/** | |
* 原始颜色值 | |
*/ | |
private int[] mRawColors = {Color.RED, Color.YELLOW, Color.GREEN}; | |
/** | |
* 用于绘制刻度盘的颜色 | |
*/ | |
private int[] mColors = {Color.GREEN, Color.RED, Color.YELLOW, Color.GREEN}; | |
/** | |
* 刻度盘直径 | |
*/ | |
private int mDiameter; | |
/** | |
* 刻度盘宽度 | |
*/ | |
private int mDialWidth = dpToPx(30); | |
/** | |
* 刻度盘分隔线宽度 | |
*/ | |
private int mDialDividerWidth = mDialWidth + dpToPx(2); | |
/** | |
* 刻度盘单位刻度的宽度,以度数为单位 | |
*/ | |
private int mDialUnitDegree = 10; | |
/** | |
* 刻度盘分隔线的宽度,以度数为单位 | |
*/ | |
private int mDialDividerDegree = 1; | |
/** | |
* 刻度盘字符Path直径 | |
*/ | |
private int mDialTextDiameter; | |
/** | |
* 刻度盘字体大小,单位sp | |
*/ | |
private int mDialTextSize = spToPx(12); | |
/** | |
* 进度条宽度 | |
*/ | |
private int mProcessWidth = dpToPx(6); | |
/** | |
* 进度条与刻度盘的距离 | |
*/ | |
private int mProgressMargin = dpToPx(10); | |
/** | |
* 进度条直径 | |
*/ | |
private int mProgressDiameter; | |
/** | |
* 绘制进度条的速度,每1ms多少度 | |
*/ | |
private int mDrawProgressSpeed = 4; | |
/** | |
* 百分比字的size | |
*/ | |
private int mTextSize = spToPx(70); | |
/** | |
* 百分比字的top | |
*/ | |
private int mTextTop; | |
/** | |
* 目标百分比,0-100 | |
*/ | |
private int mTargetRate = 0; | |
/** | |
* 百分比 | |
*/ | |
private int mRate = 0; | |
/** | |
* 当前颜色值 | |
*/ | |
private int mCurrentColor = mRawColors[0]; | |
/** | |
* 目标度数 | |
*/ | |
private int mTargetDegree = 0; | |
/** | |
* 当前度数 | |
*/ | |
private int mDegree = 0; | |
private Handler mHandler = new Handler(); | |
private Runnable drawR = new Runnable() { | |
@Override | |
public void run() { | |
if (mDegree < mTargetDegree) { | |
invalidate(); | |
mDegree += mDrawProgressSpeed; | |
mRate += mDrawProgressSpeed * 100 / (BASE_DEGREE + mOverDegree * 2); | |
mHandler.postDelayed(this, 2); | |
} else { | |
mDegree = mTargetDegree; | |
mRate = mTargetRate; | |
invalidate(); | |
} | |
} | |
}; | |
public DialView(Context context) { | |
this(context, null); | |
} | |
public DialView(Context context, AttributeSet attrs) { | |
this(context, attrs, 0); | |
} | |
public DialView(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
mContext = context; | |
WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); | |
Display display = manager.getDefaultDisplay(); | |
Point point = new Point(); | |
display.getSize(point); | |
mDisplayWidth = point.x; | |
mDisplayHeight = point.y; | |
calValues(); | |
} | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
setMeasuredDimension(widthMeasureSpec, mHeight | MeasureSpec.EXACTLY); | |
} | |
@Override | |
protected void onDraw(Canvas canvas) { | |
super.onDraw(canvas); | |
mPaint.setColor(mCurrentColor); | |
mPaint.setAntiAlias(true); | |
mPaint.setStyle(Paint.Style.STROKE); | |
// draw dial background | |
mPaint.setStrokeWidth(mDialWidth); | |
mRectF.set(mLeft, mTop, mLeft + mDiameter, mTop + mDiameter); | |
float dialColorStartPosition = 1 - (BASE_DEGREE + mOverDegree * 2) / 360.0f; | |
float[] dialColorPositions = {0, dialColorStartPosition, 0.75f, 1}; | |
if (mDialSweepGradient == null) { | |
mDialSweepGradient = new SweepGradient(mDisplayWidth / 2, mTop + mDiameter / 2, mColors, dialColorPositions); | |
} | |
mPaint.setShader(mDialSweepGradient); | |
canvas.drawArc(mRectF, -(BASE_DEGREE + mOverDegree), BASE_DEGREE + mOverDegree * 2, false, mPaint); | |
// draw dial dividers | |
mPaint.setStrokeWidth(mDialWidth + mDialDividerWidth); | |
mPaint.setColor(Color.WHITE); | |
mPaint.setShader(null); | |
for (int i = mDialUnitDegree - (BASE_DEGREE + mOverDegree); i < mOverDegree; i += mDialUnitDegree) { | |
canvas.drawArc(mRectF, i, mDialDividerDegree, false, mPaint); | |
} | |
// draw process background | |
mRectF.set(mLeft + mDialWidth + mProgressMargin, mTop + mDialWidth + mProgressMargin, mLeft + mDialWidth + mProgressMargin + mProgressDiameter, | |
mTop + mDialWidth + mProgressMargin + mProgressDiameter); | |
mPaint.setColor(Color.LTGRAY); | |
mPaint.setStrokeWidth(mProcessWidth); | |
canvas.drawArc(mRectF, -(BASE_DEGREE + mOverDegree), BASE_DEGREE + mOverDegree * 2, false, mPaint); | |
// draw process | |
mPaint.setColor(mCurrentColor); | |
canvas.drawArc(mRectF, -(BASE_DEGREE + mOverDegree), mDegree, false, mPaint); | |
// draw indicator | |
// draw dial text | |
mPaint.setColor(Color.GRAY); | |
mPaint.setStrokeWidth(1); | |
mPaint.setStyle(Paint.Style.FILL); | |
mPaint.setTextSize(mDialTextSize); | |
mPath.addCircle(mDisplayWidth / 2, mTop + mDiameter / 2, mDialTextDiameter / 2, Path.Direction.CW); | |
double circumference = mDialTextDiameter * Math.PI; | |
double overLength = mDialTextDiameter * mOverDegree * Math.PI / 360; | |
mPaint.getTextBounds("100", 0, 3, mRect); | |
canvas.drawTextOnPath("100", mPath, (int) ((overLength - mRect.width()) % circumference), 0, mPaint); | |
canvas.drawTextOnPath("75", mPath, (int) (circumference * 7 / 8 + overLength / 2), 0, mPaint); | |
canvas.drawTextOnPath("50", mPath, (int) (circumference * 3 / 4), 0, mPaint); | |
canvas.drawTextOnPath("25", mPath, (int) (circumference * 5 / 8 - overLength / 2), 0, mPaint); | |
canvas.drawTextOnPath("0", mPath, (int) (circumference / 2 - overLength), 0, mPaint); | |
// draw rate | |
mPaint.setColor(mCurrentColor); | |
mPaint.setStrokeWidth(1); | |
mPaint.setStyle(Paint.Style.FILL); | |
mPaint.setTextSize(mTextSize); | |
String text = mRate + ""; | |
mPaint.getTextBounds(text, 0, text.length(), mRect); | |
canvas.drawText(text, mDisplayWidth / 2 - mRect.width() / 2, mTextTop, mPaint); | |
} | |
public void setDegree(int rate) { | |
if (rate < 0) { | |
mTargetRate = 0; | |
} else if (rate > 100) { | |
mTargetRate = 100; | |
} else { | |
mTargetRate = rate; | |
} | |
mTargetDegree = mTargetRate * (BASE_DEGREE + mOverDegree * 2) / 100; | |
mCurrentColor = getColor(); | |
mDegree = 0; | |
mRate = 0; | |
mHandler.removeCallbacks(drawR); | |
mHandler.post(drawR); | |
} | |
public void setOverDegree(int degree) { | |
mOverDegree = degree; | |
calValues(); | |
} | |
public void setMarginPercent(float percent) { | |
mMarginPercent = percent; | |
calValues(); | |
} | |
/** | |
* 设置头部偏移,单位为dp | |
* | |
* @param top | |
*/ | |
public void setTopMargin(int top) { | |
mTop = dpToPx(top); | |
calValues(); | |
} | |
/** | |
* 设置刻度盘宽度,单位为dp | |
* | |
* @param width | |
*/ | |
public void setDialWidth(int width) { | |
mDialWidth = dpToPx(width); | |
calValues(); | |
} | |
/** | |
* 设置刻度盘单位刻度,单位为度数 | |
*/ | |
public void setDialUnitDegree(int degree) { | |
mDialUnitDegree = degree; | |
} | |
public void setDialDividerDegree(int degree) { | |
mDialDividerDegree = degree; | |
} | |
public void setProgressWidth(int width) { | |
mProcessWidth = dpToPx(width); | |
} | |
public void setProgressMargin(int width) { | |
mProgressMargin = dpToPx(width); | |
calValues(); | |
} | |
public void setProgressDrawSpeed(int degree) { | |
mDrawProgressSpeed = degree; | |
} | |
public void setTextSize(int sp) { | |
mTextSize = spToPx(sp); | |
} | |
/** | |
* 计算值 | |
*/ | |
private void calValues() { | |
mLeft = (int) (mDisplayWidth * mMarginPercent); | |
mDiameter = mDisplayWidth - mLeft * 2; | |
mOverHeight = (int) Math.ceil(mDiameter * Math.sin(mOverDegree * Math.PI / 180) / 2) + 20; | |
mHeight = mTop + mDiameter / 2 + mOverHeight; | |
mProgressDiameter = mDisplayWidth - mLeft * 2 - mDialWidth * 2 - mProgressMargin * 2; | |
mTextTop = mTop + mDiameter / 2; | |
mDialDividerWidth = mDialWidth + dpToPx(2); | |
mDialTextDiameter = mDiameter - mDialWidth - mDialTextSize - mProgressMargin; | |
} | |
private int getColor() { | |
float rate = mTargetDegree / (BASE_DEGREE + mOverDegree * 2.0f); | |
int position = (int) (Math.ceil((mRawColors.length - 1) * rate)); | |
if (position == 0) { | |
return mRawColors[0]; | |
} else { | |
int startColor = mRawColors[position - 1]; | |
int endColor = mRawColors[position]; | |
return Color.rgb((int) (Color.red(startColor) * (1 - rate) + Color.red(endColor) * rate), (int) (Color.green(startColor) * (1 - rate) + Color.green(endColor) * rate), | |
(int) (Color.blue(startColor) * (1 - rate) + Color.blue(endColor) * rate)); | |
} | |
} | |
private static int dpToPx(int dp) { | |
return (int) (dp * Resources.getSystem().getDisplayMetrics().density); | |
} | |
private static int spToPx(int sp) { | |
return (int) (sp * Resources.getSystem().getDisplayMetrics().scaledDensity); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment