Android自定义View, 安全中心安全指数进度条,圆弧进度条
来源:互联网 发布:java五子棋视频教程 编辑:程序博客网 时间:2024/06/08 10:01
最近新提出需求, 需要自定义一个安全中心页面,表示安全分数的自定义progressbar.效果在最下方贴图.
下面来说下具体的实现方法:
public class ColorArcProgressBar extends View { private int diameter = 500; //直径 private float centerX; //圆心X坐标 private float centerY; //圆心Y坐标 private Paint allArcPaint; private Paint progressPaint; private Paint vTextPaint; private Paint hintPaint; private Paint degreePaint; private Paint curSpeedPaint; private RectF bgRect; private ValueAnimator progressAnimator; private PaintFlagsDrawFilter mDrawFilter; private SweepGradient sweepGradient; private Matrix rotateMatrix; private float startAngle = 155; private float sweepAngle = 230; private float currentAngle = 0.01f; private float lastAngle; private int[] colors = new int[]{Color.GREEN, Color.YELLOW, Color.RED, Color.RED}; private float maxValues = 60; private float curValues = 0; private float bgArcWidth = dipToPx(10); private float progressWidth = dipToPx(10); private float textSize = dipToPx(50); private float hintSize = dipToPx(9); private float curSpeedSize = dipToPx(9); private int aniSpeed = 1500; private float longDegree = dipToPx(13); private float shortDegree = dipToPx(5); private final int DEGREE_PROGRESS_DISTANCE = dipToPx(1); private String hintColor = "#8d9298"; private String bgArcColor = "#F0F0F0"; private String titleString; private String hintString; private boolean isNeedTitle; private boolean isNeedUnit; private boolean isNeedDial; private boolean isNeedContent; private boolean isNeedProgress = false; // sweepAngle / maxValues 的值 private float k; public ColorArcProgressBar(Context context) { super(context, null); initView(); } public ColorArcProgressBar(Context context, AttributeSet attrs) { super(context, attrs, 0); initCofig(context, attrs); initView(); } public ColorArcProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initCofig(context, attrs); initView(); } /** * 初始化布局配置 */ private void initCofig(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorArcProgressBar); int color1 = a.getColor(R.styleable.ColorArcProgressBar_front_color1, Color.GREEN); int color2 = a.getColor(R.styleable.ColorArcProgressBar_front_color2, color1); int color3 = a.getColor(R.styleable.ColorArcProgressBar_front_color3, color1); int color4 = a.getColor(R.styleable.ColorArcProgressBar_front_color4, color1); int color5 = a.getColor(R.styleable.ColorArcProgressBar_front_color5, color1); colors = new int[]{color1, color2, color3, color4, color5, color5}; sweepAngle = a.getInteger(R.styleable.ColorArcProgressBar_total_engle, 230); bgArcWidth = a.getDimension(R.styleable.ColorArcProgressBar_back_width, dipToPx(10)); progressWidth = a.getDimension(R.styleable.ColorArcProgressBar_front_width, dipToPx(10)); isNeedTitle = a.getBoolean(R.styleable.ColorArcProgressBar_is_need_title, false); isNeedContent = a.getBoolean(R.styleable.ColorArcProgressBar_is_need_content, false); isNeedUnit = a.getBoolean(R.styleable.ColorArcProgressBar_is_need_unit, false); isNeedDial = a.getBoolean(R.styleable.ColorArcProgressBar_is_need_dial, false); hintString = a.getString(R.styleable.ColorArcProgressBar_string_unit); titleString = a.getString(R.styleable.ColorArcProgressBar_string_title); curValues = a.getFloat(R.styleable.ColorArcProgressBar_current_value, 0); maxValues = a.getFloat(R.styleable.ColorArcProgressBar_max_value, 60); setCurrentValues(curValues); setMaxValues(maxValues); a.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = (int) (2 * longDegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE); int height = (int) (2 * longDegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE); setMeasuredDimension(width, height); } private void initView() { diameter = 3 * getScreenWidth() / 5; //弧形的矩阵区域 bgRect = new RectF(); bgRect.top = longDegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE; bgRect.left = longDegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE; bgRect.right = diameter + (longDegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE); bgRect.bottom = diameter + (longDegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE); //圆心 centerX = (2 * longDegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE) / 2; centerY = (2 * longDegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE) / 2; //外部刻度线 degreePaint = new Paint(); degreePaint.setAntiAlias(true); degreePaint.setColor(Color.parseColor("#C8C8C8")); degreePaint.setStrokeWidth(dipToPx(1f)); degreePaint.setTextSize(dipToPx(10f)); //整个弧形 allArcPaint = new Paint(); allArcPaint.setAntiAlias(true); allArcPaint.setStyle(Paint.Style.STROKE); allArcPaint.setStrokeCap(Paint.Cap.ROUND); allArcPaint.setStrokeWidth(bgArcWidth); allArcPaint.setColor(Color.parseColor(bgArcColor)); //当前进度的弧形 progressPaint = new Paint(); progressPaint.setAntiAlias(true); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setStrokeCap(Paint.Cap.ROUND); progressPaint.setStrokeWidth(progressWidth); progressPaint.setColor(Color.GREEN); //内容显示文字 vTextPaint = new Paint(); vTextPaint.setTextSize(textSize); vTextPaint.setColor(Color.BLACK); vTextPaint.setTextAlign(Paint.Align.CENTER); //显示单位文字 hintPaint = new Paint(); hintPaint.setTextSize(hintSize); hintPaint.setColor(Color.parseColor(hintColor)); hintPaint.setTextAlign(Paint.Align.CENTER); //显示标题文字 curSpeedPaint = new Paint(); curSpeedPaint.setTextSize(curSpeedSize); curSpeedPaint.setColor(Color.WHITE); curSpeedPaint.setTextAlign(Paint.Align.CENTER); mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); sweepGradient = new SweepGradient(centerX, centerY, colors, null); rotateMatrix = new Matrix(); } @Override protected void onDraw(Canvas canvas) { //抗锯齿 canvas.setDrawFilter(mDrawFilter); if (isNeedDial) { //画刻度线 TODO 画刻度线可以优化 for (int i = 0; i < 156; i++) { if (i < 28 || i > 128) { canvas.rotate(2.30769f, centerX, centerY); continue; } canvas.drawLine(centerX, centerY + diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longDegree - shortDegree) / 2, centerX, centerY + diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longDegree - shortDegree) / 2 - shortDegree, degreePaint); if (((i - 28) % 20) == 0) { if (i == 128) { canvas.rotate(-2.30769f * 2, centerX, centerY); } else { canvas.rotate(-2.30769f, centerX, centerY); } canvas.rotate(180f, centerX, centerY + diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longDegree - shortDegree) / 2 - shortDegree - dipToPx(10)); canvas.drawText(String.valueOf(i - 28), centerX, centerY + diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longDegree - shortDegree) / 2 - shortDegree - dipToPx(10), degreePaint); canvas.rotate(-180f, centerX, centerY + diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longDegree - shortDegree) / 2 - shortDegree - dipToPx(10)); if (i == 128) { canvas.rotate(2.30769f * 2, centerX, centerY); } else { canvas.rotate(2.30769f, centerX, centerY); } } canvas.rotate(2.30769f, centerX, centerY); } } //整个弧 canvas.drawArc(bgRect, startAngle, sweepAngle, false, allArcPaint); //设置渐变色 rotateMatrix.setRotate(150, centerX, centerY); sweepGradient.setLocalMatrix(rotateMatrix); progressPaint.setShader(sweepGradient); //当前进度 if (isNeedProgress) { canvas.drawArc(bgRect, startAngle, currentAngle, false, progressPaint); } if (isNeedContent) { canvas.drawText(String.format("%.0f", curValues), centerX, centerY, vTextPaint); } if (isNeedUnit) { canvas.drawText(hintString, centerX, centerY + textSize / 2.6f, hintPaint); } if (isNeedTitle) { RectF rectF = new RectF(); rectF.left = centerX - dipToPx(32); rectF.top = centerY + textSize / 1.1f - dipToPx(11); rectF.right = centerX + dipToPx(32); rectF.bottom = centerY + textSize / 1.1f + dipToPx(4); canvas.drawRoundRect(rectF, dipToPx(15), dipToPx(15), vTextPaint); //绘制圆角矩形 canvas.drawText(titleString, centerX, centerY + textSize / 1.1f, curSpeedPaint); } invalidate(); } /** * 设置最大值 */ public void setMaxValues(float maxValues) { this.maxValues = maxValues; k = sweepAngle / maxValues; } /** * 设置当前值 */ public void setCurrentValues(float currentValues) { if (currentValues > maxValues) { currentValues = maxValues; } if (currentValues < 0) { currentValues = 0; } this.curValues = currentValues; lastAngle = currentAngle; setAnimation(lastAngle, currentValues * k, aniSpeed); } /** * 设置整个圆弧宽度 */ public void setBgArcWidth(int bgArcWidth) { this.bgArcWidth = bgArcWidth; } /** * 设置进度宽度 */ public void setProgressWidth(int progressWidth) { this.progressWidth = progressWidth; } /** * 设置速度文字大小 */ public void setTextSize(int textSize) { this.textSize = textSize; } /** * 设置单位文字大小 */ public void setHintSize(int hintSize) { this.hintSize = hintSize; } public void setNeedProgress(boolean needProgress) { isNeedProgress = needProgress; } /** * 设置单位文字 */ public void setUnit(String hintString) { this.hintString = hintString; invalidate(); } /** * 设置直径大小 */ public void setDiameter(int diameter) { this.diameter = dipToPx(diameter); } /** * 设置标题 */ private void setTitle(String title) { this.titleString = title; } /** * 设置是否显示标题 */ private void setIsNeedTitle(boolean isNeedTitle) { this.isNeedTitle = isNeedTitle; } /** * 设置是否显示单位文字 */ private void setIsNeedUnit(boolean isNeedUnit) { this.isNeedUnit = isNeedUnit; } /** * 设置是否显示外部刻度盘 */ private void setIsNeedDial(boolean isNeedDial) { this.isNeedDial = isNeedDial; } /** * 为进度设置动画 */ private void setAnimation(final float last, final float current, int length) { progressAnimator = ValueAnimator.ofFloat(last, current); progressAnimator.setDuration(length); progressAnimator.setTarget(currentAngle); progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { currentAngle = (float) animation.getAnimatedValue(); curValues = currentAngle / k; if (vTextPaint != null) { if (0 <= curValues && curValues < 20f) { vTextPaint.setColor(Color.parseColor("#FB8301")); titleString = "安全等级低"; } else if (20f <= curValues && curValues < 40f) { vTextPaint.setColor(Color.parseColor("#FBB004")); titleString = "安全等级低"; } else if (40f <= curValues && curValues < 60f) { vTextPaint.setColor(Color.parseColor("#C9C730")); titleString = "安全等级中"; } else if (60f <= curValues && curValues < 80f) { vTextPaint.setColor(Color.parseColor("#71CC80")); titleString = "安全等级中"; } else { vTextPaint.setColor(Color.parseColor("#0598F6")); titleString = "安全等级高"; } } } }); progressAnimator.start(); } /** * dip 转换成px */ private int dipToPx(float dip) { float density = getContext().getResources().getDisplayMetrics().density; return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1)); } /** * 得到屏幕宽度 */ private int getScreenWidth() { WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); DisplayMetrics displayMetrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(displayMetrics); return displayMetrics.widthPixels; }}
1.其中再为进度设置动画时,需改变安全等级背景颜色方法较笨, 应该能进一步实现背景颜色随进度条走到的颜色变而变化, 知道的小伙伴,可以在评论中给出答案噢~感谢~
2.在刚开始currentAngle 设置为0.01f,是为了适配oppo手机开始会显示进度条100%的闪烁, 改成0.01f就不会有这种bug了.属于笨方法解决哦~
贴出sttr.xml文件:
<declare-styleable name="ColorArcProgressBar"> <attr name="back_color" format="color"/> <attr name="front_color1" format="color"/> <attr name="front_color2" format="color"/> <attr name="front_color3" format="color"/> <attr name="front_color4" format="color"/> <attr name="front_color5" format="color"/> <attr name="back_width" format="dimension"/> <attr name="front_width" format="dimension"/> <attr name="is_need_title" format="boolean"/> <attr name="is_need_content" format="boolean"/> <attr name="is_need_unit" format="boolean"/> <attr name="is_need_dial" format="boolean"/> <attr name="string_title" format="string"/> <attr name="string_unit" format="string"/> <attr name="total_engle" format="integer"/> <attr name="current_value" format="float"/> <attr name="max_value" format="float"/> </declare-styleable>
在xml中使用:
<com.clwapp.hx.widget.ColorArcProgressBar android:id="@id/color_arc_progressbar" android:layout_width="200dp" android:layout_height="200dp" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/common_13dp" app:back_color="@android:color/darker_gray" app:back_width="10dp" app:front_color1="#FB7E00" app:front_color2="#FAC405" app:front_color3="#73CC7C" app:front_color4="#06A2F3" app:front_color5="#0079FC" app:front_width="10dp" app:is_need_content="true" app:is_need_dial="true" app:is_need_title="true" app:is_need_unit="true" app:max_value="100" app:string_title="安全等级低" app:string_unit="BETA" app:total_engle="230" />
在Activity中使用:
progressBar.setNeedProgress(true);progressBar.setCurrentValues(80);
这样, 自定义progressbar就写完了, 有不足的地方,还请各大神门指正!!!
效果如图:
阅读全文
1 0
- Android自定义View, 安全中心安全指数进度条,圆弧进度条
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android 圆弧形进度条 自定义View
- Android换肤技术总结
- 小程序页面pv统计数过高,导致页面转化率低问题
- logback logback.xml常用配置详解(二)<appender>
- 2017年快结束了,你挣到了啥?
- darwin之复制字符串(Task)
- Android自定义View, 安全中心安全指数进度条,圆弧进度条
- Cocos2d-x下Lua调用自定义C++类和函数的最佳实践
- eclipse中导入项目在jsp文件中出现了这个错误
- CefSharp 集成谷歌浏览器详解(三)--官网示例解析2 CefSettings 介绍
- xml配置详解
- ECharts属性设置
- spacy初学
- 滑动窗口 分析SQL 实践
- 密码安全性检查代码