说到自定义View,相信很多同学都是从ProgressBar开始的,主要是因为它写起来会比较简单,然后可以操作一遍自定义View的流程。刚好这两天有个朋友叫帮忙写个ProgressBar,虽然之前写了至少3个了,但也还是答应了下来,他给出的效果图如下:
先上最后的效果如下:
这里挑几个主要方法说明一下,最后会贴出完整代码。
onMeasure()计算出view的大小,同时计算出几个关键位置
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//这里就取父容器给定的默认大小
int widthSize = getDefaultSize(0, widthMeasureSpec);
int heightSize = getDefaultSize(0, heightMeasureSpec);
/**
* 获取真实用于画view的正方形大小,这里需要为边界处齿轮的圆边预留出gearStrokeWidth的宽度
* 同时预留出齿轮动画需要占用的宽度gearAnimLength
*/
int realWidth = (int) (widthSize - getPaddingLeft() - getPaddingRight() - gearStrokeWidth * 2 - 2 * gearAnimLength);
int realHeight = (int) (heightSize - getPaddingTop() - getPaddingBottom() - gearStrokeWidth * 2 - 2 * gearAnimLength);
//我们的真实用来画view的范围取一个正方形,这里正方形的边长取可用长和宽的最小值
realSize = realWidth >= realHeight ? realHeight : realWidth;
//这里算出整个用于绘画的正方形的中心点
centerPoint = new Point((int) (getPaddingLeft() + realWidth / 2 + gearStrokeWidth + gearAnimLength), (int) (getPaddingTop() + realHeight / 2 + gearStrokeWidth + gearAnimLength));
//计算出外部齿轮圆的半径,以齿轮中间到圆心计算
outerCircleRadius = (realSize - gearWidth) / 2;
if (outerCircleRadius < 0) {
outerCircleRadius = 0;
}
//计算出内圆的半径
innerCircleRadius = realSize / 2 - gearWidth - circlePadding;
if (innerCircleRadius < 0) {
innerCircleRadius = 0;
}
//设置View大小
setMeasuredDimension(widthSize, heightSize);
}
onDraw()画View,这里分四块来画,drawInnerCircle(canvas) 画内圆、drawGear(canvas)画齿轮、drawProgressDot(canvas)画内圆上的进度球、drawProgressText(canvas)画进度文字。
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawInnerCircle(canvas);
drawGear(canvas);
drawProgressDot(canvas);
drawProgressText(canvas);
}
以上都是往画板上画对应图形的方法,只有drawGear(canvas)中会涉及到动画时会稍微复杂一些,这些齿轮本质都是线条,只是根据动画进度在长度上会有一些计算。
drawGear(canvas)
private void drawGear(Canvas canvas) {
float atom = (float) (Math.PI * 5 / 180);
gearStartAngle = (1 - gearRange) * Math.PI;
gearEndAngle = (1 + gearRange) * Math.PI;
if (gearEndAngle == 2 * Math.PI) {
gearEndAngle -= atom;
}
double diffAngle = gearEndAngle - gearStartAngle;
float startX, startY, stopX, stopY;
/**
* 这里找到drawProgress附近的9根线条
* 以下为每5度一条线,总线条根数为72根
*/
int totalLineCount = 72;
//最靠近当前drawProgress的线条的位置
pLinePoint = (int) (totalLineCount - Math.ceil(totalLineCount * drawProgress / maxProgress));
int point = (int) (gearStartAngle / atom);
for (double angle = gearStartAngle; angle < gearEndAngle; angle = angle + atom) {
/**
* 这里计算颜色有些诡异,由于我们计算角度是从底下逆时针开始计算,
* 而我们的仪表盘进度顺时针开始计算,所以这里是gearEndAngle-angle,而不是gearStartAngle+angle
*/
mGearPaint.setColor(transitColor((float) ((gearEndAngle - angle) / diffAngle)));
float startR = outerCircleRadius;
float endR = outerCircleRadius;
if (animProgress != 1) {
if (point == gearPoints[pLinePoint + 36]) {
startR = startR + 5 * gearAnimGradient / 2;
endR = endR + gearAnimLength;
} else if (point == gearPoints[pLinePoint + 35] || point == gearPoints[pLinePoint + 37]) {
startR = startR + 4 * gearAnimGradient / 2;
endR = endR + gearAnimLength - gearAnimGradient;
} else if (point == gearPoints[pLinePoint + 34] || point == gearPoints[pLinePoint + 38]) {
startR = startR + 3 * gearAnimGradient / 2;
endR = endR + gearAnimLength - 2 * gearAnimGradient;
} else if (point == gearPoints[pLinePoint + 33] || point == gearPoints[pLinePoint + 39]) {
startR = startR + 2 * gearAnimGradient / 2;
endR = endR + gearAnimLength - 3 * gearAnimGradient;
} else if (point == gearPoints[pLinePoint + 32] || point == gearPoints[pLinePoint + 40]) {
startR = startR + gearAnimGradient / 2;
endR = endR + gearAnimLength - 4 * gearAnimGradient;
}
}
startX = (float) (centerPoint.x + Math.sin(angle) * (startR - gearWidth / 2));
startY = (float) (centerPoint.y + Math.cos(angle) * (startR - gearWidth / 2));
stopX = (float) (centerPoint.x + Math.sin(angle) * (endR + gearWidth / 2));
stopY = (float) (centerPoint.y + Math.cos(angle) * (endR + gearWidth / 2));
canvas.drawLine(startX, startY, stopX, stopY, mGearPaint);
point++;
}
}
其他的细节也不好用代码描述了,下面贴出完整代码:
HxjProgressBar.java
public class HxjProgressBar extends View {
private static final int DEFAULT_PROGRESS_TEXT_SIZE = 30;//sp
private static final int DEFAULT_TIPS_SIZE = 14;//sp
private static final int DEFAULT_CIRCLE_PADDING = 14;//sp
private static final int DEFAULT_GEAR_WIDTH = 8;//dp
private static final int DEFAULT_INNER_STROKE_WIDTH = 1;//dp
private static final int DEFAULT_GEAR_STROKE_WIDTH = 2;//dp
private static final int DEFAULT_PROGRESS_DOT_RADIUS = 2;//dp
private static final long PROGRESS_ANIM_DURATION = 1200L;
private static final long MIN_PROGRESS_ANIM_DURATION = 400L;
/**
* 中间进度文字大小
*/
private float progressTextSize;
/**
* 提示文字大小
*/
private float tipsSize;
/**
* 提示文字颜色
*/
private int tipsColor;
/**
* 内圆半径
*/
private float innerCircleRadius;
/**
* 外圆半径
*/
private float outerCircleRadius;
/**
* 内外圆空白处的宽度
*/
private float circlePadding;
/**
* 内圆颜色
*/
private int innerCircleColor;
/**
* 起始颜色
*/
private int selectStartColor;
/**
* 结束颜色
*/
private int selectEndColor;
/**
* 外圈齿轮宽度
*/
private float gearWidth;
/**
* 内圆画笔宽度
*/
private float innerStrokeWidth;
/**
* 齿轮画笔宽度
*/
private float gearStrokeWidth;
/**
* 外部齿轮的范围,取值:0-1,默认为1,即一个满圆,0.5为上半圆
*/
private float gearRange = 1;
/**
* 最大进度
*/
private float maxProgress;
/**
* 真实画View的区域理想为正方形
* 该正方形的大小
*/
private float realSize;
/**
* view用于绘画的中心点
*/
private Point centerPoint;
/**
* 齿轮起始角度
*/
private double gearStartAngle;
/**
* 齿轮结束角度
*/
private double gearEndAngle;
/**
* 进度条上的小圆球半径
*/
private float progressDotRadius;
/**
* 进度单位
*/
private String progressUnit;
/**
* 辅助说明
*/
private String tips;
/**
* 进度小数位数
*/
private int decimals;
/**
* 当前进度
*/
private float mProgress;
/**
* 当前动画进度
*/
private float drawProgress;
private float gearAnimLength;
private float gearAnimGradient;
private Paint mInnerCirclePaint;
private Paint mGearPaint;
private Paint mProgressDotPaint;
private Paint mProgressPaint;
private Paint mUnitPaint;
private ValueAnimator progressAnimator;
private String progressText;
private float animProgress = 1;
private int[] gearPoints = new int[144];
private int pLinePoint;
public HxjProgressBar(Context context) {
this(context, null);
}
public HxjProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public HxjProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(attrs);
initPaint();
initGearPoints();
}
/**
* 这里初始化一个齿轮位置数组,附带左右边界36个位置的齿轮位置
* 齿轮的总数为72根,在这里为了处理齿轮边界动画,在数组中左右各加36个齿轮位置
*/
private void initGearPoints() {
for (int i = 0; i < 36; i++) {
gearPoints[i] = 36 + i;
gearPoints[108 + i] = i;
}
for (int i = 0; i < 72; i++) {
gearPoints[i + 36] = i;
}
}
private void initPaint() {
mInnerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿
mInnerCirclePaint.setAntiAlias(true);//防抖动
mInnerCirclePaint.setColor(innerCircleColor);
mInnerCirclePaint.setStrokeWidth(innerStrokeWidth);
mInnerCirclePaint.setStyle(Paint.Style.STROKE);
mGearPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿
mGearPaint.setAntiAlias(true);//防抖动
mGearPaint.setStrokeCap(Paint.Cap.ROUND);//设置画笔末端样式
mGearPaint.setStrokeWidth(gearStrokeWidth);
mProgressDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿
mProgressDotPaint.setAntiAlias(true);//防抖动
mProgressDotPaint.setColor(selectStartColor);
mProgressDotPaint.setStyle(Paint.Style.FILL);
mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿
mProgressPaint.setAntiAlias(true);//防抖动
mUnitPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿
mUnitPaint.setAntiAlias(true);//防抖动
}
private void initAttrs(AttributeSet attrs) {
Context context = getContext();
float scaledDensity = getResources().getDisplayMetrics().scaledDensity;
float density = getResources().getDisplayMetrics().density;
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true);
int accentColor = typedValue.data;
context.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
int primaryColor = typedValue.data;
context.getTheme().resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);
int primaryDarkColor = typedValue.data;
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HxjProgressBar);
progressTextSize = typedArray.getDimension(R.styleable.HxjProgressBar_progressTextSize, (int) (DEFAULT_PROGRESS_TEXT_SIZE * scaledDensity + 0.5));
tipsSize = typedArray.getDimension(R.styleable.HxjProgressBar_tipsSize, (int) (DEFAULT_TIPS_SIZE * scaledDensity + 0.5));
circlePadding = typedArray.getDimension(R.styleable.HxjProgressBar_circlePadding, (int) (DEFAULT_CIRCLE_PADDING * density + 0.5));
gearWidth = typedArray.getDimension(R.styleable.HxjProgressBar_gearWidth, (int) (DEFAULT_GEAR_WIDTH * density + 0.5));
gearAnimLength = gearWidth / 2;
gearAnimGradient = gearAnimLength / 7F;
innerCircleColor = typedArray.getColor(R.styleable.HxjProgressBar_innerCircleColor, accentColor);
selectStartColor = typedArray.getColor(R.styleable.HxjProgressBar_selectStartColor, primaryColor);
tipsColor = typedArray.getColor(R.styleable.HxjProgressBar_tipsColor, accentColor);
selectEndColor = typedArray.getColor(R.styleable.HxjProgressBar_selectEndColor, primaryDarkColor);
innerStrokeWidth = typedArray.getDimension(R.styleable.HxjProgressBar_innerStrokeWidth, (int) (DEFAULT_INNER_STROKE_WIDTH * density + 0.5));
gearStrokeWidth = typedArray.getDimension(R.styleable.HxjProgressBar_gearStrokeWidth, (int) (DEFAULT_GEAR_STROKE_WIDTH * density + 0.5));
progressDotRadius = typedArray.getDimension(R.styleable.HxjProgressBar_progressDotRadius, (int) (DEFAULT_PROGRESS_DOT_RADIUS * density + 0.5));
maxProgress = typedArray.getFloat(R.styleable.HxjProgressBar_maxProgress, 100F);
mProgress = typedArray.getFloat(R.styleable.HxjProgressBar_progress, 0F);
progressUnit = typedArray.getString(R.styleable.HxjProgressBar_progressUnit);
decimals = typedArray.getInteger(R.styleable.HxjProgressBar_decimals, 0);
tips = typedArray.getString(R.styleable.HxjProgressBar_tips);
drawProgress = mProgress;
formatProgress(mProgress);
gearRange = typedArray.getFloat(R.styleable.HxjProgressBar_gearRange, 1);
gearRange = correctGearRange(gearRange);
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//这里就取父容器给定的默认大小
int widthSize = getDefaultSize(0, widthMeasureSpec);
int heightSize = getDefaultSize(0, heightMeasureSpec);
/**
* 获取真实用于画view的正方形大小,这里需要为边界处齿轮的圆边预留出gearStrokeWidth的宽度
* 同时预留出齿轮动画需要占用的宽度gearAnimLength
*/
int realWidth = (int) (widthSize - getPaddingLeft() - getPaddingRight() - gearStrokeWidth * 2 - 2 * gearAnimLength);
int realHeight = (int) (heightSize - getPaddingTop() - getPaddingBottom() - gearStrokeWidth * 2 - 2 * gearAnimLength);
//我们的真实用来画view的范围取一个正方形,这里正方形的边长取可用长和宽的最小值
realSize = realWidth >= realHeight ? realHeight : realWidth;
//这里算出整个用于绘画的正方形的中心点
centerPoint = new Point((int) (getPaddingLeft() + realWidth / 2 + gearStrokeWidth + gearAnimLength), (int) (getPaddingTop() + realHeight / 2 + gearStrokeWidth + gearAnimLength));
//计算出外部齿轮圆的半径,以齿轮中间到圆心计算
outerCircleRadius = (realSize - gearWidth) / 2;
if (outerCircleRadius < 0) {
outerCircleRadius = 0;
}
//计算出内圆的半径
innerCircleRadius = realSize / 2 - gearWidth - circlePadding;
if (innerCircleRadius < 0) {
innerCircleRadius = 0;
}
//设置View大小
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawInnerCircle(canvas);
drawGear(canvas);
drawProgressDot(canvas);
drawProgressText(canvas);
}
/**
* 画进度文字
* @param canvas
*/
private void drawProgressText(Canvas canvas) {
if (animProgress <= 0.5) {
mProgressPaint.setTextSize((1 - 0.5F * animProgress) * progressTextSize);
} else {
mProgressPaint.setTextSize((0.75F + 0.25F * animProgress) * progressTextSize);
}
mProgressPaint.setTextAlign(Paint.Align.CENTER);
int progressWidth = (int) mProgressPaint.measureText(progressText);
Paint.FontMetrics fontMetrics = mProgressPaint.getFontMetrics();
float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
mUnitPaint.setTextSize(progressTextSize / 2);
mUnitPaint.setTextAlign(Paint.Align.LEFT);
int unitWidth = (int) mUnitPaint.measureText(progressUnit);
//添加渐变shader
LinearGradient gradient = new LinearGradient(centerPoint.x - progressWidth / 2.0F,
centerPoint.y,
centerPoint.x + progressWidth / 2.0F,
centerPoint.y,
selectStartColor,
selectEndColor,
Shader.TileMode.MIRROR);
mProgressPaint.setShader(gradient);
float baseY;
//这里在计算进度text的绘制高度时考虑是否需要绘制tips,不需要时完全居中,需要时则以centerY为baseY略微偏上
if (!TextUtils.isEmpty(tips)) {
baseY = centerPoint.y;
} else {
baseY = centerPoint.y - top / 2 - bottom / 2;
}
canvas.drawText(progressText, centerPoint.x - unitWidth / 2.0F, baseY, mProgressPaint);
if (!TextUtils.isEmpty(progressUnit)) {
mUnitPaint.setShader(gradient);
canvas.drawText(progressUnit, centerPoint.x - unitWidth / 2.0F + progressWidth / 2.0F, baseY, mUnitPaint);
}
mUnitPaint.setTextSize(tipsSize);
mUnitPaint.setShader(null);
mUnitPaint.setColor(tipsColor);
mUnitPaint.setTextAlign(Paint.Align.CENTER);
if (!TextUtils.isEmpty(tips)) {
canvas.drawText(tips, centerPoint.x, centerPoint.y + innerCircleRadius / 2, mUnitPaint);
}
}
/**
* 画内圆
*
* @param canvas
*/
private void drawInnerCircle(Canvas canvas) {
canvas.drawCircle(centerPoint.x, centerPoint.y, innerCircleRadius, mInnerCirclePaint);
}
/**
* 画齿轮
*
* @param canvas
*/
private void drawGear(Canvas canvas) {
float atom = (float) (Math.PI * 5 / 180);
gearStartAngle = (1 - gearRange) * Math.PI;
gearEndAngle = (1 + gearRange) * Math.PI;
if (gearEndAngle == 2 * Math.PI) {
gearEndAngle -= atom;
}
double diffAngle = gearEndAngle - gearStartAngle;
float startX, startY, stopX, stopY;
/**
* 这里找到drawProgress附近的9根线条
* 以下为每5度一条线,总线条根数为72根
*/
int totalLineCount = 72;
//最靠近当前drawProgress的线条的位置
pLinePoint = (int) (totalLineCount - Math.ceil(totalLineCount * drawProgress / maxProgress));
int point = (int) (gearStartAngle / atom);
for (double angle = gearStartAngle; angle < gearEndAngle; angle = angle + atom) {
/**
* 这里计算颜色有些诡异,由于我们计算角度是从底下逆时针开始计算,
* 而我们的仪表盘进度顺时针开始计算,所以这里是gearEndAngle-angle,而不是gearStartAngle+angle
*/
mGearPaint.setColor(transitColor((float) ((gearEndAngle - angle) / diffAngle)));
float startR = outerCircleRadius;
float endR = outerCircleRadius;
if (animProgress != 1) {
if (point == gearPoints[pLinePoint + 36]) {
startR = startR + 5 * gearAnimGradient / 2;
endR = endR + gearAnimLength;
} else if (point == gearPoints[pLinePoint + 35] || point == gearPoints[pLinePoint + 37]) {
startR = startR + 4 * gearAnimGradient / 2;
endR = endR + gearAnimLength - gearAnimGradient;
} else if (point == gearPoints[pLinePoint + 34] || point == gearPoints[pLinePoint + 38]) {
startR = startR + 3 * gearAnimGradient / 2;
endR = endR + gearAnimLength - 2 * gearAnimGradient;
} else if (point == gearPoints[pLinePoint + 33] || point == gearPoints[pLinePoint + 39]) {
startR = startR + 2 * gearAnimGradient / 2;
endR = endR + gearAnimLength - 3 * gearAnimGradient;
} else if (point == gearPoints[pLinePoint + 32] || point == gearPoints[pLinePoint + 40]) {
startR = startR + gearAnimGradient / 2;
endR = endR + gearAnimLength - 4 * gearAnimGradient;
}
}
startX = (float) (centerPoint.x + Math.sin(angle) * (startR - gearWidth / 2));
startY = (float) (centerPoint.y + Math.cos(angle) * (startR - gearWidth / 2));
stopX = (float) (centerPoint.x + Math.sin(angle) * (endR + gearWidth / 2));
stopY = (float) (centerPoint.y + Math.cos(angle) * (endR + gearWidth / 2));
canvas.drawLine(startX, startY, stopX, stopY, mGearPaint);
point++;
}
}
/**
* 画进度球
*
* @param canvas
*/
private void drawProgressDot(Canvas canvas) {
double angle = 2 * Math.PI - drawProgress / maxProgress * 2 * Math.PI;
float dotX = (float) (centerPoint.x + innerCircleRadius * Math.sin(angle));
float dotY = (float) (centerPoint.y + innerCircleRadius * Math.cos(angle));
LinearGradient gradient = new LinearGradient(dotX + progressDotRadius,
dotY - progressDotRadius,
dotX - progressDotRadius,
dotY + progressDotRadius,
selectEndColor,
selectStartColor,
Shader.TileMode.MIRROR);
mProgressDotPaint.setShader(gradient);
canvas.drawCircle(dotX, dotY, progressDotRadius, mProgressDotPaint);
}
/**
* 计算颜色过渡
* @param progress
* @return
*/
private int transitColor(float progress) {
int startA = Color.alpha(selectStartColor);
int startR = Color.red(selectStartColor);
int startG = Color.green(selectStartColor);
int startB = Color.blue(selectStartColor);
int endA = Color.alpha(selectEndColor);
int endR = Color.red(selectEndColor);
int endG = Color.green(selectEndColor);
int endB = Color.blue(selectEndColor);
return Color.argb((int) (startA + (endA - startA) * progress),
(int) (startR + (endR - startR) * progress),
(int) (startG + (endG - startG) * progress),
(int) (startB + (endB - startB) * progress));
}
public float getProgress() {
return mProgress;
}
public void setProgress(float progress) {
progress = correctProgress(progress);
if (progress == mProgress) {
return;
}
cancelCurrenAnim();
mProgress = progress;
drawProgress = mProgress;
formatProgress(mProgress);
animProgress = 1;
invalidate();
}
private void formatProgress(float progress) {
if (decimals <= 0) {
progressText = String.valueOf((int) progress);
} else {
progressText = String.format("%." + decimals + "f", progress);
}
}
public void setProgressWithAnim(float progress) {
progress = correctProgress(progress);
if (progress == mProgress) {
return;
}
final float lastProgress = mProgress;
final float diff = progress - lastProgress;
mProgress = progress;
cancelCurrenAnim();
progressAnimator = ValueAnimator.ofFloat(0, 1);
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
animProgress = (float) animation.getAnimatedValue();
if (animProgress <= 0.5) {
formatProgress(lastProgress);
} else {
formatProgress(mProgress);
}
drawProgress = lastProgress + diff * animProgress;
invalidate();
}
});
progressAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
drawProgress = mProgress;
formatProgress(mProgress);
invalidate();
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
progressAnimator.setInterpolator(new OvershootInterpolator());
long duration = MIN_PROGRESS_ANIM_DURATION + (long) ((PROGRESS_ANIM_DURATION - MIN_PROGRESS_ANIM_DURATION) * ((mProgress - lastProgress) / maxProgress));
progressAnimator.setDuration(duration);
progressAnimator.start();
}
private void cancelCurrenAnim() {
if (progressAnimator != null && progressAnimator.isRunning()) {
progressAnimator.cancel();
}
}
private float correctProgress(float progress) {
if (progress < 0) {
progress = 0;
}
if (progress > maxProgress) {
progress = maxProgress;
}
return progress;
}
public float getProgressTextSize() {
return progressTextSize;
}
public void setProgressTextSize(float progressTextSize) {
this.progressTextSize = progressTextSize;
invalidate();
}
public float getTipsSize() {
return tipsSize;
}
public void setTipsSize(float tipsSize) {
this.tipsSize = tipsSize;
invalidate();
}
public float getCirclePadding() {
return circlePadding;
}
public void setCirclePadding(float circlePadding) {
this.circlePadding = circlePadding;
invalidate();
}
public int getInnerCircleColor() {
return innerCircleColor;
}
public void setInnerCircleColor(int innerCircleColor) {
this.innerCircleColor = innerCircleColor;
invalidate();
}
public int getSelectStartColor() {
return selectStartColor;
}
public void setSelectStartColor(int selectStartColor) {
this.selectStartColor = selectStartColor;
invalidate();
}
public int getSelectEndColor() {
return selectEndColor;
}
public void setSelectEndColor(int selectEndColor) {
this.selectEndColor = selectEndColor;
invalidate();
}
public float getGearWidth() {
return gearWidth;
}
public void setGearWidth(float gearWidth) {
this.gearWidth = gearWidth;
invalidate();
}
public float getInnerStrokeWidth() {
return innerStrokeWidth;
}
public void setInnerStrokeWidth(float innerStrokeWidth) {
this.innerStrokeWidth = innerStrokeWidth;
invalidate();
}
public float getGearStrokeWidth() {
return gearStrokeWidth;
}
public void setGearStrokeWidth(float gearStrokeWidth) {
this.gearStrokeWidth = gearStrokeWidth;
invalidate();
}
public float getGearRange() {
return gearRange;
}
public void setGearRange(float gearRange) {
gearRange = correctGearRange(gearRange);
if (this.gearRange == gearRange) {
return;
}
this.gearRange = gearRange;
invalidate();
}
private float correctGearRange(float range) {
if (range < 0) {
range = 0;
}
if (range > 1) {
range = 1;
}
return range;
}
public float getMaxProgress() {
return maxProgress;
}
public void setMaxProgress(float maxProgress) {
this.maxProgress = maxProgress;
invalidate();
}
public float getProgressDotRadius() {
return progressDotRadius;
}
public void setProgressDotRadius(float progressDotRadius) {
this.progressDotRadius = progressDotRadius;
invalidate();
}
public String getProgressUnit() {
return progressUnit;
}
public void setProgressUnit(String progressUnit) {
this.progressUnit = progressUnit;
}
public String getTips() {
return tips;
}
public void setTips(String tips) {
this.tips = tips;
}
public int getDecimals() {
return decimals;
}
public void setDecimals(int decimals) {
this.decimals = decimals;
}
}
支持自定义的属性如下:
attr.xml
这里只是将大致流程记录下来,整个View的逻辑代码较多,参考价值不会太大。每个UI小姐姐想要的效果都不太一样,需要根据不同的要求来具体实现。