Skip to content

Instantly share code, notes, and snippets.

@ishitcno1
Created June 4, 2015 03:57
Show Gist options
  • Save ishitcno1/875933317d91eca68f0f to your computer and use it in GitHub Desktop.
Save ishitcno1/875933317d91eca68f0f to your computer and use it in GitHub Desktop.
android dial view
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