最终效果如下,没使用任何图片,全手工绘制,比较基础,给大家刚入门的做一个总结
流程要点
1 初始化
主要是Paint的属性和控件颜色、距离、大小的定义,这些需要在制作过程细心调整
mDefaultWidthm、DefaultHeight 可以在onMeasure()测量的时候定义,表示控件不设置具体大小时的初始化宽高
private float mLineThickness;
private int mDefaultHeight;
private int mDefaultWidth;
private Paint mLinePaint;
private Paint mTrianglePaint;
private int mTriangleLength;
private float mProgressLength;
private int mColorBlue;
private int mColorRed;
private float mTriangleCenterLength;
private int mProgress;
private int mBorderPadding;
private void init() {
mColorBlue = getResources().getColor(R.color.blue0DD2FF);
mColorRed = getResources().getColor(R.color.redFA4254);
mColorWhite = getResources().getColor(R.color.white);
final DisplayMetrics metrics = getResources().getDisplayMetrics();
mDefaultHeight = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
40,metrics);
mDefaultWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
270,metrics);
mTriangleLength =(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,metrics);
mBorderPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,5, metrics);
mTriangleCenterLength = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,7,metrics);
mProgressLength = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,0,metrics);
mLineWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 250, metrics);
mLineThickness = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, metrics);
mLinePaint = new Paint();
mLinePaint.setAntiAlias(true);
mLinePaint.setStrokeWidth(mLineThickness);
mTrianglePaint = new Paint();
/*去锯齿*/
mTrianglePaint.setAntiAlias(true);
/*设置paint的颜色*/
mTrianglePaint.setColor(mColorBlue);
/*设置paint的 style 为STROKE:空心 Fill实心*/
mTrianglePaint.setStyle(Paint.Style.FILL);
}
2 绘制
主要为渐变线的绘制和三角形绘制
渐变线可使用LinearGradient来实现,LinearGradient为Shader的子类,可以实现多种渐变效果
构造函数一:从x到y点的渐变,渐变色只有两种
public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
TileMode tile){
mType = TYPE_COLOR_START_AND_COLOR_END;
mX0 = x0;
mY0 = y0;
mX1 = x1;
mY1 = y1;
mColor0 = color0;
mColor1 = color1;
mTileMode = tile;
init(nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt));
}
构造函数二:从x到y点的渐变,渐变色可以多种,并设置渐变的间隔,传递两个数组,前者为渐变色,后者为渐变色的间距,如从0到0.3f再到1f,实现3种渐变色
public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
TileMode tile){
if (colors.length < 2) {
throw new IllegalArgumentException("needs >= 2 number of colors");
}
if (positions != null && colors.length != positions.length) {
throw new IllegalArgumentException("color and position arrays must be of equal length");
}
mType = TYPE_COLORS_AND_POSITIONS;
mX0 = x0;
mY0 = y0;
mX1 = x1;
mY1 = y1;
mColors = colors;
mPositions = positions;
mTileMode = tile;
init(nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt));
}
而三角形的绘制则需要精确的计算三个点的距离,这里注意绘制线条时要隔开一定间隔(长度为三角形边长一半),同时线条最后也要空出一段间隔否则三角形就显示不全
具体运用看实现代码
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
LinearGradient gradient = new LinearGradient(0, 0, getMeasuredWidth(),
getMeasuredHeight(), new int[]{mColorBlue, Color.WHITE, mColorRed}, new float[]{0f, 0.7f, 1f}, Shader.TileMode.MIRROR);
// LinearGradient gradient = new LinearGradient(0, 0, 400, 400, , getResources().getColor(R.color.gowild_grade_redFA4254), Shader.TileMode.MIRROR);
mLinePaint.setShader(gradient);
canvas.drawLine(mBorderPadding, 0, getBarLength()+mBorderPadding, 0, mLinePaint);
Path path = new Path();
path.moveTo(mProgressLength + mBorderPadding, mLineThickness);
path.lineTo(getRightBottomX(), getBottomY());
path.lineTo(getLeftBottomX(), getBottomY());
path.close();
canvas.drawPath(path, mTrianglePaint);
}
3 进度设置
提供一个方法给外界设置进度,关键点在于刷新界面的时机,如果直接在setProgress中调用invalidate(),是无法正常刷新进度的。
正确的做法是在设置进度时保存变量,在onSizeChanged()之中,已经测量完毕界面的时候再刷新进度的位置,这时进度即可正常显示
public void setProgress(int progress) {
Logger.d(TAG,"setProgress"+progress);
if (progress < 0 | progress > 100) {
return;
}
mProgress = progress;
invalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (mProgress != 0) {
mProgressLength = (float) mProgress / 100 * getBarLength();
invalidate();
}
super.onSizeChanged(w, h, oldw, oldh);
}