Android自定义progressBar

通过继承系统ProgressBar实现

效果图

实现

HorizontalProgressBarWithNumber

自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="HorizontalProgressBarWithNumber"><attr name="progress_unreached_color" format="color" /><attr name="progress_reached_color" format="color" /><attr name="progress_reached_bar_height" format="dimension" /><attr name="progress_unreached_bar_height" format="dimension" /><attr name="progress_text_size" format="dimension" /><attr name="progress_text_color" format="color" /><attr name="progress_text_offset" format="dimension" /><attr name="progress_text_visibility" format="enum"><enum name="visible" value="0" /><enum name="invisible" value="1" /></attr></declare-styleable><declare-styleable name="RoundProgressBarWidthNumber"><attr name="radius" format="dimension" /></declare-styleable></resources>

HorizontalProgressBarWithNumber

package com.zhy.view;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.widget.ProgressBar;import com.zhy.library.view.R;public class HorizontalProgressBarWithNumber extends ProgressBar
{private static final int DEFAULT_TEXT_SIZE = 10;private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;/*** painter of all drawing things*/protected Paint mPaint = new Paint();/*** color of progress number*/protected int mTextColor = DEFAULT_TEXT_COLOR;/*** size of text (sp)*/protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);/*** offset of draw progress*/protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);/*** height of reached progress bar*/protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);/*** color of reached bar*/protected int mReachedBarColor = DEFAULT_TEXT_COLOR;/*** color of unreached bar*/protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;/*** height of unreached progress bar*/protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);/*** view width except padding*/protected int mRealWidth;protected boolean mIfDrawText = true;protected static final int VISIBLE = 0;public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs){this(context, attrs, 0);}public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,int defStyle){super(context, attrs, defStyle);obtainStyledAttributes(attrs);mPaint.setTextSize(mTextSize);mPaint.setColor(mTextColor);}@Overrideprotected synchronized void onMeasure(int widthMeasureSpec,int heightMeasureSpec){int width = MeasureSpec.getSize(widthMeasureSpec);int height = measureHeight(heightMeasureSpec);setMeasuredDimension(width, height);mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();}private int measureHeight(int measureSpec){int result = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);if (specMode == MeasureSpec.EXACTLY){result = specSize;} else{float textHeight = (mPaint.descent() - mPaint.ascent());result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachedProgressBarHeight,mUnReachedProgressBarHeight), Math.abs(textHeight)));if (specMode == MeasureSpec.AT_MOST){result = Math.min(result, specSize);}}return result;}/*** get the styled attributes* * @param attrs*/private void obtainStyledAttributes(AttributeSet attrs){// init values from custom attributesfinal TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressBarWithNumber);mTextColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_text_color,DEFAULT_TEXT_COLOR);mTextSize = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_size,mTextSize);mReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,mTextColor);mUnReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,DEFAULT_COLOR_UNREACHED_COLOR);mReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,mReachedProgressBarHeight);mUnReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,mUnReachedProgressBarHeight);mTextOffset = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,mTextOffset);int textVisible = attributes.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,VISIBLE);if (textVisible != VISIBLE){mIfDrawText = false;}attributes.recycle();}@Overrideprotected synchronized void onDraw(Canvas canvas){canvas.save();canvas.translate(getPaddingLeft(), getHeight() / 2);boolean noNeedBg = false;float radio = getProgress() * 1.0f / getMax();float progressPosX = (int) (mRealWidth * radio);String text = getProgress() + "%";// mPaint.getTextBounds(text, 0, text.length(), mTextBound);float textWidth = mPaint.measureText(text);float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;if (progressPosX + textWidth > mRealWidth){progressPosX = mRealWidth - textWidth;noNeedBg = true;}// draw reached barfloat endX = progressPosX - mTextOffset / 2;if (endX > 0){mPaint.setColor(mReachedBarColor);mPaint.setStrokeWidth(mReachedProgressBarHeight);canvas.drawLine(0, 0, endX, 0, mPaint);}// draw progress bar// measure text boundif (mIfDrawText){mPaint.setColor(mTextColor);canvas.drawText(text, progressPosX, -textHeight, mPaint);}// draw unreached barif (!noNeedBg){float start = progressPosX + mTextOffset / 2 + textWidth;mPaint.setColor(mUnReachedBarColor);mPaint.setStrokeWidth(mUnReachedProgressBarHeight);canvas.drawLine(start, 0, mRealWidth, 0, mPaint);}canvas.restore();}/*** dp 2 px* * @param dpVal*/protected int dp2px(int dpVal){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpVal, getResources().getDisplayMetrics());}/*** sp 2 px* * @param spVal* @return*/protected int sp2px(int spVal){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,spVal, getResources().getDisplayMetrics());}}

主要重写了onMeasure与onDraw方法

RoundProgressBarWidthNumber

圆形的进度条和横向的进度条基本变量都是一致的,于是我就让RoundProgressBarWidthNumber extends HorizontalProgressBarWithNumber 了。
然后需要改变的就是测量和onDraw了:

完整代码

package com.zhy.view;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.util.AttributeSet;import com.zhy.library.view.R;public class RoundProgressBarWidthNumber extendsHorizontalProgressBarWithNumber
{/*** mRadius of view*/private int mRadius = dp2px(30);private int mMaxPaintWidth;public RoundProgressBarWidthNumber(Context context){this(context, null);}public RoundProgressBarWidthNumber(Context context, AttributeSet attrs){super(context, attrs);mReachedProgressBarHeight = (int) (mUnReachedProgressBarHeight * 2.5f);TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.RoundProgressBarWidthNumber);mRadius = (int) ta.getDimension(R.styleable.RoundProgressBarWidthNumber_radius, mRadius);ta.recycle();mPaint.setStyle(Style.STROKE);mPaint.setAntiAlias(true);mPaint.setDither(true);mPaint.setStrokeCap(Cap.ROUND);}/*** 这里默认在布局中padding值要么不设置,要么全部设置*/@Overrideprotected synchronized void onMeasure(int widthMeasureSpec,int heightMeasureSpec){mMaxPaintWidth = Math.max(mReachedProgressBarHeight,mUnReachedProgressBarHeight);int expect = mRadius * 2 + mMaxPaintWidth + getPaddingLeft()+ getPaddingRight();int width = resolveSize(expect, widthMeasureSpec);int height = resolveSize(expect, heightMeasureSpec);int realWidth = Math.min(width, height);mRadius = (realWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2;setMeasuredDimension(realWidth, realWidth);}@Overrideprotected synchronized void onDraw(Canvas canvas){String text = getProgress() + "%";float textWidth = mPaint.measureText(text);float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;canvas.save();canvas.translate(getPaddingLeft() + mMaxPaintWidth / 2, getPaddingTop()+ mMaxPaintWidth / 2);mPaint.setStyle(Style.STROKE);// draw unreaded barmPaint.setColor(mUnReachedBarColor);mPaint.setStrokeWidth(mUnReachedProgressBarHeight);canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);// draw reached barmPaint.setColor(mReachedBarColor);mPaint.setStrokeWidth(mReachedProgressBarHeight);float sweepAngle = getProgress() * 1.0f / getMax() * 360;canvas.drawArc(new RectF(0, 0, mRadius * 2, mRadius * 2), 0,sweepAngle, false, mPaint);// draw textmPaint.setStyle(Style.FILL);canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight,mPaint);canvas.restore();}}

首先获取它的专有属性mRadius,然后根据此属性去测量,测量完成绘制;
绘制的过程呢?
先绘制一个细一点的圆,然后绘制一个粗一点的弧度,二者叠在一起就行。文本呢,绘制在中间~~~总体,没什么代码量。
好了,两个进度条就到这了,是不是发现简单很多。总体设计上,存在些问题,如果抽取一个BaseProgressBar用于获取公共的属性;然后不同样子的进度条继承分别实现自己的测量和样子,这样结构可能会清晰些~

使用

布局文件

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:zhy="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="25dp" ><com.zhy.view.HorizontalProgressBarWithNumberandroid:id="@+id/id_progressbar01"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="50dip"android:padding="5dp" /><com.zhy.view.HorizontalProgressBarWithNumberandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="50dip"android:padding="5dp"android:progress="50"zhy:progress_text_color="#ffF53B03"zhy:progress_unreached_color="#ffF7C6B7" /><com.zhy.view.RoundProgressBarWidthNumberandroid:id="@+id/id_progress02"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="50dip"android:padding="5dp"android:progress="30" /><com.zhy.view.RoundProgressBarWidthNumberandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="50dip"android:padding="5dp"android:progress="50"zhy:progress_reached_bar_height="20dp"zhy:progress_text_color="#ffF53B03"zhy:radius="60dp" /></LinearLayout></ScrollView>

MainActivity

package com.zhy.sample.progressbar;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;import com.zhy.annotation.Log;
import com.zhy.view.HorizontalProgressBarWithNumber;public class MainActivity extends Activity {private HorizontalProgressBarWithNumber mProgressBar;private static final int MSG_PROGRESS_UPDATE = 0x110;private Handler mHandler = new Handler() {@Logpublic void handleMessage(android.os.Message msg) {int progress = mProgressBar.getProgress();mProgressBar.setProgress(++progress);if (progress >= 100) {mHandler.removeMessages(MSG_PROGRESS_UPDATE);}mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_UPDATE, 100);};};@Log@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mProgressBar = (HorizontalProgressBarWithNumber) findViewById(R.id.id_progressbar01);mHandler.sendEmptyMessage(MSG_PROGRESS_UPDATE);}}

知识点

  • paint.ascent()和paint.descent()

1.基准点是baseline
2.ascent:是baseline之上至字符最高处的距离
3.descent:是baseline之下至字符最低处的距离
4.leading:是上一行字符的descent到下一行的ascent之间的距离,也就是相邻行间的空白距离
5.top:是指的是最高字符到baseline的值,即ascent的最大值
6.bottom:是指最低字符到baseline的值,即descent的最大值

  • View.resolveSize(int size,int measureSpec)

代码如下

public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {int result = size;int specMode = MeasureSpec.getMode(measureSpec);int specSize =  MeasureSpec.getSize(measureSpec);switch (specMode) {case MeasureSpec.UNSPECIFIED:result = size;break;case MeasureSpec.AT_MOST:if (specSize < size) {result = specSize | MEASURED_STATE_TOO_SMALL;} else {result = size;}break;case MeasureSpec.EXACTLY:result = specSize;break;}return result | (childMeasuredState&MEASURED_STATE_MASK);}

源代码下载

源代码

参考链接

Android 打造形形色色的进度条 实现可以如此简单 - Hongyang - 博客频道 - CSDN.NET

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/494067.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

干货分享:自动驾驶核心技术进展之车用毫米波雷达

来源&#xff1a;智车科技摘要&#xff1a;电动化、智能化、网联化、共享化是汽车未来发展的大势。伴随着这一趋势&#xff0c;自动驾驶汽车应用而生&#xff0c;且国内很多自动驾驶研发企业快速成长。“自动驾驶”等相关热词也一直是行业关注的焦点。为了让中国汽车行业的机构…

Android主题换肤实现

本系列文章主要是对一个Material Design的APP的深度解析&#xff0c;主要包括以下内容 基于Material Design Support Library作为项目整体框架。对应博文&#xff1a;Android Material Design 兼容库的使用详解RecyclerView的万能适配器。对应博文:打造一个RecyclerView的万能…

windows下MBCS和UNICODE编码的转换

1. 从MBCS转到UNICODE 方法a&#xff09; 直接调用windows api char name[100] "大鳄.hxboar";wchar_t wname[100];//setlocale(LC_ALL, "chinese"); int nLen MultiByteToWideChar(CP_ACP, 0,name, -1, NULL, NULL);MultiByteToWideChar(CP_ACP, 0, name…

ShareSDK集成微信、QQ、微博分享

1、前言 为什么要使用第三方的作为集成分享的工具呢&#xff1f;而不去用官方的呢&#xff1f;有什么区别么&#xff1f; 一个字”快”&#xff0c;如果你使用官方的得一个个集成他们的SDK&#xff0c;相信这是一个痛苦的过程。 2、准备需要分享的各个平台的key 这个需要…

深度|一篇文章解读人工智能的原理及产业升级机会

来源&#xff1a;人工智能腾讯数码摘要&#xff1a;人工智能看上去高高在上&#xff0c;实际上前沿科技公司都寄希望于这种长期研究为其目前的业务带来新的发展机会&#xff0c;神经网络、机器学习、深度学习构建了人工智能基础&#xff0c;本文阐述了三大基础是如何运作和实现…

可自由扩展的圆角矩形制作方法

转自&#xff1a;http://golen.blog.sohu.com/96114249.html 制作一个好的web标准站点,扩展性要多考虑,扩展性做的好的网站,会给后期的维护和升级会带来很大的方便.现在总结一下我做web以来,可扩展的圆角矩形的制作方法:方法一:命名:round.gif: 代码如下: <!DOCTYPE html PU…

GE刚刚换帅,就向艾默生出售智能平台业务?刚刚换帅,GE又向艾默生出售智能平台业务,未来究竟何去何从?...

来源&#xff1a;路透社、知识自动化等物联网智库 整理发布摘要&#xff1a;智能平台出售背后&#xff0c;GE和艾默生各自有何打算&#xff1f;GE多事之秋能否迎来回春转机&#xff1f;昨晚&#xff0c;据消息&#xff1a;艾默生电气公司(Emerson Electric)同意收购通用电气&am…

豆瓣加载动画实现

最终效果如下 ValueAnimator类API 简介 ofFloat(float… values) 构建ValueAnimator&#xff0c;设置动画的浮点值&#xff0c;需要设置2个以上的值setDuration(long duration) 设置动画时长&#xff0c;默认的持续时间为300毫秒。setInterpolator(TimeInterpolator value) 设…

下一次 IT 变革:边缘计算(Edge computing)

来源&#xff1a;云头条摘要&#xff1a;外媒 ZDnet 发布了此篇边缘计算领域的重要文章&#xff0c;详细分析了各机构不同的定义、市场状况、前景等&#xff0c;经编译&#xff0c;供各位参考数十亿物联网设备和5G网络这两股力量必将推动计算工作负载的部署方式发生深远而重大的…

WebService入门

webservice 的概念&#xff0c;解决什么问题&#xff1f; webservice 就是一个应用程序&#xff0c;它提供一种通过web 方式访问的api. 解决两个系统或者&#xff08;应用程序&#xff09;之间的远程调用….. 调用是跨语言&#xff0c;跨平台… webservice 最基本的组成部分…

Google联手Facebook 要在AI研究上搞什么大事?

来源&#xff1a;网易智能 摘要&#xff1a;Google和Facebook宣布&#xff0c;使开源机器学习框架PyTorch与Tensor-Processing Units&#xff08;TPU&#xff09;进行合作。这种伙伴关系标志着人工智能研究合作进入新时代。“今天&#xff0c;我们很高兴地宣布&#xff0c;Goog…

WebService之CXF框架

本文主要包括以下内容 ant工具的使用利用cxf实现webservicecxf与spring整合 ajax访问webservice ant 工具 1、为什么要用到ant这个工具呢&#xff1f; Ant做为一种工具已经广泛被使用&#xff0c;并且历史悠久。 使用ant的内置命令&#xff0c;可以编译java源文件(javac)…

Java之IO操作总结

所谓IO&#xff0c;也就是Input与Output的缩写。在java中&#xff0c;IO涉及的范围比较大&#xff0c;这里主要讨论针对文件内容的读写 其他知识点将放置后续章节 对于文件内容的操作主要分为两大类 分别是&#xff1a; 字符流字节流 其中&#xff0c;字符流有两个抽象类&…

谷歌无人车离奇车祸曝光:人类安全员睡着后,误触关闭了自动驾驶

来源&#xff1a;量子位离奇&#xff0c;真离奇。一场已经被掩盖数月的谷歌无人车&#xff08;Waymo&#xff09;离奇车祸&#xff0c;刚刚被The Information曝光。车祸的发生地&#xff0c;就在距离谷歌加州山景城总部不远的高速公路上。那是一个六月的早晨。一辆Waymo无人车正…

强烈推荐:240多个jQuery插件

概述 jQuery 是继 prototype 之后又一个优秀的 Javascript 框架。其宗旨是—写更少的代码,做更多的事情。它是轻量级的 js 库(压缩后只有21k) &#xff0c;这是其它的 js 库所不及的&#xff0c;它兼容 CSS3&#xff0c;还兼容各种浏览器&#xff08;IE 6.0, FF 1.5, Safari 2.…

揭秘|超乎想象!未来50年将出现的九大黑科技……

来源&#xff1a;世界科技创新论坛Insititute for the Future是一家专门做预测的研究机构。该机构的首席研究总监Mark Frauenfelder详细描述了人类在未来能够用上&#xff0c;而今天却仍被认为不可能发生的事物。赶快一起来看看这些未来将出现的黑科技吧。1、大脑移植&#xff…

Android手绘效果实现

效果图 原理 大概介绍一下实现原理。首先你得有一张图&#xff08;废话~&#xff09;,接下来就是把这张图的轮廓提取出来&#xff0c;轮廓提取算法有很多&#xff0c;本人不是搞图像处理的&#xff0c;对图像处理感兴趣的童鞋可以查看相关资料。如果你有好的轮廓提取算法&…

干货|120页精华PPT详解工业机器人本体设计运算及仿真

来源&#xff1a;哈尔滨工业大学摘要&#xff1a;120页精华PPT详解工业机器人本体设计运算及仿真未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括&#xff1a;建立AI智能系统智商评测体…

环信SDK集成

利用环信SDK可以实现即时通讯&#xff0c;但在集成的过程中碰到了不少的坑。 注意 选择项目路径&#xff0c;这里以最新版环信demo为例 注意&#xff1a;环信的ChatDemoUI这个demo里边因为研发的同事为了照顾老版本的AndroidStudio使用者&#xff0c;已经用eclipse生成了bui…

协作机器人先驱宣布倒闭!累计融资10.3亿元,贝佐斯投资八轮

来源&#xff1a;量子位一家机器人领域的头部玩家&#xff0c;还不是说倒下就倒下了。上个月&#xff0c;协作机器人的先驱Rethink Robotics刚刚宣布出售第2500个机器人产品&#xff0c;而昨天&#xff0c;就又宣布关门大吉了。CEO Scott Eckert在接受外媒The Robot Report采访…