目录
- 前言
- 一、GradientProgressView准备工作
- 二、制作
- 1.初始化特点
- 2.丈量宽高
- 3.依据状况来画突变色进展
- 4.制作
- 总结
前言
我们常运用shape完成突变色,可是shape的极限却只有三色,如果有超过三种色彩的View的要求,那么我们就不得不去自界说View来完成这个需求。不过它的难度也是很低的,完成起来很轻松。接下来我分析一下我的思路。 先上图:
一、GradientProgressView准备工作
- color:突变进展条的多种色彩
- 图形:如果是圆柱形就运用RectF,矩形就用Rect,一个用于显现原色进展,一个用于显现突变进展条
- 突变染色器:LinearGradient
- 宽高:mHeight、mWidth
- 圆柱的半径:mRadius 特点代码如下
private int colorStart; // 色彩:进展1
private int colorEnd; // 色彩:进展5
private int colorStart2;// 色彩:进展2
private int colorEnd0;// 色彩:进展4
private int colorCenter;// 色彩:进展3
private Paint mGradientPaint;// 突变画笔
private Paint mPaint;// 默许画笔
private RectF mBackGroundRect; // 原色图形
private RectF mGradientRect;// 染色图形
private LinearGradient backGradient;// 突变色
private int mHeight;
private int mWidth;
private int mRadius;
二、制作
1.初始化特点
由于这个自界说View只为了满意公司需求,所有我并未将其的功能扩展开来,所有没有自界说特点,都是写死在代码中,后续有空再优化。 首要三过程:初始化色彩,初始化画笔,初始化图形。 最好先写死需求的宽高,防止在运用的运用还未丈量就进行制作
private void init(Context context, @Nullable AttributeSet attrs){
// 初始化画笔
mGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
colorStart = Color.parseColor("#63DC80");
colorStart2 = Color.parseColor("#A8DB5B");
colorCenter = Color.parseColor("#FFCE48");
colorEnd0 = Color.parseColor("#FE7B39");
colorEnd = Color.parseColor("#E8402B");
mPaint.setColor(Color.parseColor("#EDEDED"));
if (attrs!=null){
}
//设置抗锯齿
mGradientPaint.setAntiAlias(true);
//设置防抖动
mGradientPaint.setDither(true);
mGradientPaint.setStyle(Paint.Style.FILL);
//设置抗锯齿
mPaint.setAntiAlias(true);
//设置防抖动
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.FILL);
mBackGroundRect = new RectF();
// 防止烘托还未完成果显现,使得宽高还未丈量。先在初始化这儿界说好跟xml中相同的宽高
mWidth = (int) (Resources.getSystem().getDisplayMetrics().widthPixels-context.getResources().getDimension(R.dimen.base_dp_56));
mHeight = (int) (context.getResources().getDimension(R.dimen.base_dp_8));
}
2.丈量宽高
这一步一般来说已经是有规范的代码模板了,所以我这儿也没什么创新的当地,照抄就完事了,这儿便浅浅介绍一下丈量的过程吧。 其流程是:
- 先用
getMode()和getSize()
获取丈量形式和宽高,再依据不同的形式获取宽高。 - 形式有三种:EXACTLY(精确值形式)、AT_MOST(最大值形式)、UNSPECIFIED(未指定形式)
- 如果是EXACTLY(精确值形式),那么该特点就是确认的,即当时View的宽高
- 如果是AT_MOST(最大值形式),那么该特点就是父容器的宽高
- 如果是UNSPECIFIED(未指定形式),那么该特点要么是0,要么是EXACTLY(精确值形式)下当时view的特点。 用图来阐明,即为:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/**
* 从供给的丈量标准中获取丈量形式和宽高值
*/
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
Log.d("TAG", "onMeasure: "+widthMode);
Log.d("TAG", "onMeasure: "+widthSize);
if (widthMode == MeasureSpec.EXACTLY) {
//丈量形式是EXACTLY,阐明view的宽度值是确认的
mWidth = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
/**
* 丈量形式是AT_MOST,阐明view的宽度值最大是父View能供给的巨细
* 比方开发者设置wrap_content,那可能是希望填充父View
*/
mWidth = Math.max(mWidth,widthSize);
}
if (heightMode == MeasureSpec.EXACTLY) {
mHeight = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
mHeight = Math.min(mHeight,heightSize);
}
/**
* 为了View能更好的展示,需求设置下宽高比
*/
float times = mWidth / (float)mHeight;
if (times < 2.5 ) {
if (mHeight < DensityUtil.dip2px(getContext(),60)) {
mHeight = DensityUtil.dip2px(getContext(),60);
}
mWidth = (int) (mHeight * 2.5);
}
mRadius = (int) getContext().getResources().getDimension(R.dimen.base_dp_20);
//保存核算后的宽高
setMeasuredDimension(mWidth,mHeight);
}
3.依据状况来画突变色进展
这儿由于需求原因,我将本来的进展条五色平分进展,所以这儿用到已经丈量好的宽度特点mWidth
。
这儿的流程也很简略,扼要说下
- 暴露方法给外界调用
- 获取进展
- 依据进展来给突变染色器:LinearGradient初始化
- 一同给圆柱形RectF初始化宽高
- 最后调用
invalidate()
从头制作该View
public void setAirType(String degree){
int level = mWidth / 5;
switch (degree){
case "1":
mGradientRect = new RectF(0,0,level,mHeight);
// 由于突变色调集,需求色彩大于等于2,这儿取巧,设置相同色彩
backGradient = new LinearGradient(0, 0, level, 0, new int[]{colorStart,colorStart}, null, Shader.TileMode.CLAMP);
break;
case "2":
mGradientRect = new RectF(0,0,level*2,mHeight);
backGradient = new LinearGradient(0, 0, level*2, 0, new int[]{colorStart, colorStart2}, null, Shader.TileMode.CLAMP);
break;
case "3":
mGradientRect = new RectF(0,0,level*3,mHeight);
backGradient = new LinearGradient(0, 0, level*3, 0, new int[]{colorStart, colorStart2,colorCenter}, null, Shader.TileMode.CLAMP);
break;
case "4":
mGradientRect = new RectF(0,0,level*4,mHeight);
backGradient = new LinearGradient(0, 0, level*4, 0, new int[]{colorStart, colorStart2,colorCenter,colorEnd0}, null, Shader.TileMode.CLAMP);
break;
case "5":
mGradientRect = new RectF(0,0,mWidth,mHeight);
backGradient = new LinearGradient(0, 0, mWidth, 0, new int[]{colorStart, colorStart2,colorCenter,colorEnd0,colorEnd}, null, Shader.TileMode.CLAMP);
break;
}
invalidate();
}
4.制作
这儿我选用最简略粗犷的方法,直接叠了两个圆柱进展条,一个是原色的进展条,一个是突变色的进展条,这儿我们可以自行优化,即在backGradient 特点初始化的时分进展调整等。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawRoundRect(canvas);
}
private void drawRoundRect(Canvas canvas) {
mBackGroundRect.left = 0;
mBackGroundRect.top = 0;
mBackGroundRect.bottom = mHeight;
mBackGroundRect.right = mWidth;
// 制作底色圆角矩形
canvas.drawRoundRect(mBackGroundRect, mRadius, mRadius, mPaint);
// 突变绘图
mGradientPaint.setShader(backGradient);
//制作布景 圆角矩形
if (mGradientRect != null) {
canvas.drawRoundRect(mGradientRect, mRadius, mRadius, mGradientPaint);
}
}
完好代码贴上,便利各位友友运用
public class GradientProgressView extends View {
private int colorStart; // 色彩:进展1
private int colorEnd; // 色彩:进展5
private int colorStart2;// 色彩:进展2
private int colorEnd0;// 色彩:进展4
private int colorCenter;// 色彩:进展3
private List<Integer> colorList; // 色彩调集
private List<Float> colorSize; // 色彩位置
private Paint mGradientPaint;// 突变画笔
private Paint mPaint;// 默许画笔
private RectF mBackGroundRect; // 原色图形
private RectF mGradientRect;// 染色图形
private LinearGradient backGradient;// 突变色
private int mHeight;
private int mWidth;
private int mRadius;
public GradientProgressView(Context context) {
super(context);
}
public GradientProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}
public GradientProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init(Context context, @Nullable AttributeSet attrs){
// 初始化画笔
mGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
colorStart = Color.parseColor("#63DC80");
colorStart2 = Color.parseColor("#A8DB5B");
colorCenter = Color.parseColor("#FFCE48");
colorEnd0 = Color.parseColor("#FE7B39");
colorEnd = Color.parseColor("#E8402B");
mPaint.setColor(Color.parseColor("#EDEDED"));
if (attrs!=null){
}
//设置抗锯齿
mGradientPaint.setAntiAlias(true);
//设置防抖动
mGradientPaint.setDither(true);
mGradientPaint.setStyle(Paint.Style.FILL);
//设置抗锯齿
mPaint.setAntiAlias(true);
//设置防抖动
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.FILL);
mBackGroundRect = new RectF();
// 防止烘托还未完成果显现,使得宽高还未丈量。先在初始化这儿界说好跟xml中相同的宽高
mWidth = (int) (Resources.getSystem().getDisplayMetrics().widthPixels-context.getResources().getDimension(R.dimen.base_dp_56));
mHeight = (int) (context.getResources().getDimension(R.dimen.base_dp_8));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/**
* 从供给的丈量标准中获取丈量形式和宽高值
*/
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
Log.d("TAG", "onMeasure: "+widthMode);
Log.d("TAG", "onMeasure: "+widthSize);
if (widthMode == MeasureSpec.EXACTLY) {
//丈量形式是EXACTLY,阐明view的宽度值是确认的
mWidth = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
/**
* 丈量形式是AT_MOST,阐明view的宽度值最大是父View能供给的巨细
* 比方开发者设置wrap_content,那可能是希望填充父View
*/
mWidth = Math.max(mWidth,widthSize);
}
if (heightMode == MeasureSpec.EXACTLY) {
mHeight = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
mHeight = Math.min(mHeight,heightSize);
}
/**
* 为了View能更好的展示,需求设置下宽高比
*/
float times = mWidth / (float)mHeight;
if (times < 2.5 ) {
if (mHeight < DensityUtil.dip2px(getContext(),60)) {
mHeight = DensityUtil.dip2px(getContext(),60);
}
mWidth = (int) (mHeight * 2.5);
}
mRadius = (int) getContext().getResources().getDimension(R.dimen.base_dp_20);
//保存核算后的宽高
setMeasuredDimension(mWidth,mHeight);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}
public void setAirType(String degree){
int level = mWidth / 5;
switch (degree){
case "1":
mGradientRect = new RectF(0,0,level,mHeight);
// 由于突变色调集,需求色彩大于等于2,这儿取巧,设置相同色彩
backGradient = new LinearGradient(0, 0, level, 0, new int[]{colorStart,colorStart}, null, Shader.TileMode.CLAMP);
break;
case "2":
mGradientRect = new RectF(0,0,level*2,mHeight);
backGradient = new LinearGradient(0, 0, level*2, 0, new int[]{colorStart, colorStart2}, null, Shader.TileMode.CLAMP);
break;
case "3":
mGradientRect = new RectF(0,0,level*3,mHeight);
backGradient = new LinearGradient(0, 0, level*3, 0, new int[]{colorStart, colorStart2,colorCenter}, null, Shader.TileMode.CLAMP);
break;
case "4":
mGradientRect = new RectF(0,0,level*4,mHeight);
backGradient = new LinearGradient(0, 0, level*4, 0, new int[]{colorStart, colorStart2,colorCenter,colorEnd0}, null, Shader.TileMode.CLAMP);
break;
case "5":
mGradientRect = new RectF(0,0,mWidth,mHeight);
backGradient = new LinearGradient(0, 0, mWidth, 0, new int[]{colorStart, colorStart2,colorCenter,colorEnd0,colorEnd}, null, Shader.TileMode.CLAMP);
break;
}
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawRoundRect(canvas);
}
private void drawRoundRect(Canvas canvas) {
mBackGroundRect.left = 0;
mBackGroundRect.top = 0;
mBackGroundRect.bottom = mHeight;
mBackGroundRect.right = mWidth;
// 制作底色圆角矩形
canvas.drawRoundRect(mBackGroundRect, mRadius, mRadius, mPaint);
// 突变绘图
mGradientPaint.setShader(backGradient);
//制作布景 圆角矩形
if (mGradientRect != null) {
canvas.drawRoundRect(mGradientRect, mRadius, mRadius, mGradientPaint);
}
}
}
xml调用
<com.itaem.blviewtest.GradientProgressView
android:id="@+id/gradientProgress"
android:layout_width="match_parent"
android:layout_height="@dimen/base_dp_8"
android:layout_marginTop="12dp"
android:layout_marginHorizontal="@dimen/base_dp_44"/>
总结
仍是由于时间问题,该自界说View仅仅单纯满意需求,并没有太大的扩展性功能,后续有时间我也行会出一篇后续将自界说View补上,完成一个功能性较为强壮的突变色进展条。 自界说View的魅力就是当你完成功能需求的时分的满意感,不亚于曾经做完一道数学大题。那种痛快和欣喜,老实说我有点爱上自界说View了。
当然如果有可以优化的点,我们记住分享在评论区,一同进步。