您的位置:首页
自己定义进度条PictureProgressBar——从开发到开源公布全过程
2018-04-04 16:56
375 查看
自己定义进度条PictureProgressBar——从开发到开源公布全过程
出处:
炎之铠邮箱:yanzhikai_yjk@qq.com
本文原创。转载请注明本出处!
本项目JCenter地址:https://bintray.com/yanzhikaijky/CustomViewRepository/PictureProgressbar/
本项目GitHub地址:https://github.com/totond/PictureProgressBar
欢迎 Star or Fork和在Issue里提出意见建议。
*本篇文章已授权微信公众号 guolin_blog (郭霖)独家公布
前言
上一篇文章掌握了ProgressBar的自己定义样式和它的扩展ProgressDialog。可是没有进行封装,这一次就继承View从零開始做了一个自己定义进度条——PictureProgressBar,并公布到Github和JCenter上,以下就開始一步一步介绍这个过程。PS:JCenter是一个Android的代码库,把代码放上去,就能够在AS项目里的Gradle文件中compile ‘xxx’这样来引入你的代码了。
本文涉及到:
一个继承自View的自己定义ProgressBar实现全过程一个项目开源的全过程:使用AndroidStudio上传代码到GitHub、JCenter的过程,加入开源协议的过程等。
实现
PictureProgressBar是一个能够带图片和动画效果的进度条,能够先看看它的效果,例如以下图:![](http://i.imgur.com/076zTuA.gif)
实现的逻辑并不复杂,看看流程图:
![](http://i.imgur.com/MTLvZT3.png)
基本的逻辑是在onDraw()方法实现,里面大量利用到Canvas。Canvas的使用能够參考下我曾经这篇笔记。
1.初始化属性
由于前面的属性定义太多了,所以这里不列出来,后面要用到的属性会有介绍,想详细了解的能够看GitHub的介绍文档,那里有个表详细介绍。这里定义初始化方法,用来配置画笔和设置Gradient渐变器,由于Gradient须要进度条的宽高。所以要在Measure过程之后才配置:
//初始化 private void init() { //初始化画笔 paintPicture = new Paint(); paintBackGround = new Paint(); paintBackGround.setColor(backGroundColor); paintBar = new Paint(); paintBar.setColor(barColor); if (isGradient) { //在PreDraw时获取View属性,由于在初始化的时候View还没进行Measure getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { getViewTreeObserver().removeOnPreDrawListener(this); linearGradient = new LinearGradient(0, progressHeight / 2, progressWidth, progressHeight / 2, gradientStartColor, gradientEndColor, Shader.TileMode.CLAMP); paintBar.setShader(linearGradient); return false; } }); } }
2.画进度条
首先就是要画好进度条,Android源代码自带的ProgressBar是基于事件机制来刷新View的,也就是每当有进度改变才会调用刷新View的方法,可是由于我这里要实现动画并且对怎么实现事件机制不是非常熟,所以採用了定时刷新的方法,先把进度条画出来://画进度条 private void drawBar(Canvas canvas){ if (isRound) { //画圆角矩形 rectFBG.set(0, y - progressHeight / 2 + progressHeightOffset, progressWidth, y + progressHeight / 2 + progressHeightOffset); canvas.drawRoundRect(rectFBG, roundX, roundY, paintBackGround); rectFPB.set(0, y - progressHeight / 2 + progressHeightOffset, x, y + progressHeight / 2 + progressHeightOffset); canvas.drawRoundRect(rectFPB, roundX, roundY, paintBar); } else { //画矩形 rectFBG.set(0, 0, getWidth(), getHeight()); canvas.drawRect(rectFBG, paintBackGround); canvas.drawRect(0, 0, x, getHeight(), paintBar); } }
简单说一下上面的一些属性:
- isRound是决定进度条是否圆角的boolean变量,由于认为不是圆角的进度条有点难看,所以就终于公布时默认初始设置是true。
- progressWidth和progressHeight是进度条的宽高。而不是整个View的宽高,由于View是包含进度条和图片,要为图片的显示预留空间。所以进度条宽高会在onMeasure()依据属性设置来定义大小(详细怎么定义后面说)。
- x和y是当前进度的中心点坐标位置。
- progressHeightOffset是进度条的所处高度偏移量。负数为向上偏移,正数为向下偏移。
前面就说过progressHeight是进度条的宽高不一定是整个View的宽高,所以进度条能够处于一个自己定义的位置(眼下仅仅是高度。由于一般都不用设置宽度)。详细的效果能够看前面demo效果的第一个,进度条就是向下偏移而实现了被可爱的丘比龙踩在脚下的效果。
![](http://i.imgur.com/ugxd1Ih.png)
3.绘图片Drawable
接下来是绘图片Drawable的方法,这个Drawable能够是图片或者是Shape,依据当前进度的中心点坐标x、y和图片的半宽高属性halfDrawableWidth、halfDrawableHeight来实现,当中drawableHeightOffset是图片的高度偏移量://绘图 private void drawPicture(Canvas canvas) { if (drawable == null && animMode != ANIM_NULL){ Log.e(TAG,"drawable is null"); return; } drawable.setBounds(x - halfDrawableWidth, getHeight() / 2 - halfDrawableHeight + drawableHeightOffset, x + halfDrawableWidth, getHeight() / 2 + halfDrawableHeight + drawableHeightOffset); drawable.draw(canvas); }
![](http://i.imgur.com/Eior3ne.png)
4.画动画:
先对是否开启动画,当前动画模式做出推断,实现5个动画模式:animMode模式 | 意义 |
---|---|
ANIM_NULL | 无动画模式 |
ANIM_ROTATE | 旋转动画模式 |
ANIM_SCALE | 缩放动画模式 |
ANIM_ROTATE_SCALE | 旋转加缩放动画模式 |
ANIM_FRAME | 帧动画模式 |
//画动画 private void drawAnimPicture(Canvas canvas) { if (isAnimRun) { switch (animMode) { case ANIM_NULL: drawPicture(canvas); break; case ANIM_ROTATE: rotateCanvas(canvas); drawPicture(canvas); break; case ANIM_SCALE: scaleCanvas(canvas); drawPicture(canvas); break; case ANIM_ROTATE_SCALE: rotateCanvas(canvas); scaleCanvas(canvas); drawPicture(canvas); break; case ANIM_FRAME: drawable = getResources().getDrawable(drawableIds[frameIndex]); drawPicture(canvas); if (frameIndex >= drawableIds.length - 1){ frameIndex = 0; }else { frameIndex++; } break; } } else { drawPicture(canvas); } }
实现帧动画是通过轮播图片的方法实现。
实现旋转,缩放的效果。是採用操纵画布Canvas的方法来实现:
//旋转画布 private void rotateCanvas(Canvas canvas) { canvas.rotate(rotateDegree % 360, x, y + drawableHeightOffset); rotateDegree += rotateRate; } //伸缩画布 private void scaleCanvas(Canvas canvas) { if (scaleLevel >= scaleMax) { isScaleIncrease = false; } else if (scaleLevel <= scaleMin) { isScaleIncrease = true; } if (isScaleIncrease) { scaleLevel += scaleRate; } else { scaleLevel -= scaleRate; } canvas.scale(scaleLevel, scaleLevel, x, y + drawableHeightOffset); }
由于drawAnimPicture()方法之后并没有其它使用Canvas的方法了。所以这里不用Canvas.save()和Canvas.restore()来使Canvas恢复到初始状态了,这里说明一下。免得后面有功能拓展的须要加代码时候忘了。
5.重写onMeasure()
重写onMeasure()的意义:让View支持wrap_content。还有设置了进度条的宽高(前面说过,进度条的宽高不一定等于整个View的宽高)://重写onMeasure,以自己定义获取进度条的宽高 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = MeasureSpec.getSize(heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) { //在这里实现计算须要wrap_content时须要的宽 width = halfDrawableWidth * 2; } if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) { //在这里实现计算须要wrap_content时须要的高 height = halfDrawableHeight * 2; } progressWidth = width; //假设不是自己定义设置进度条高度。就直接把高度当作进度条高度 if (!isSetBar) { progressHeight = height; } //假设有图片。就为图片预留空间 if (drawable != null) { progressWidth = width - halfDrawableWidth; } //传入处理后的宽高 setMeasuredDimension(width, height); }
6.封装
自己定义属性
为了让自己定义View的属性能直接通过XML设置,须要用到自己定义属性,在res/value文件夹里新建一个attrs.xml(名字随便,建立位置对即可),定义自己所需的属性和对应类型:<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="PictureProgressBar"> <attr name="backGroundColor" format="color"/> <attr name="barColor" format="color"/> <attr name="drawable" format="reference"/> <attr name="halfDrawableWidth" format="dimension"/> <attr name="halfDrawableHeight" format="dimension"/> <attr name="drawableHeightOffset" format="dimension"/> <attr name="isRound" format="boolean"/> <attr name="roundX" format="dimension"/> <attr name="roundY" format="dimension"/> <attr name="progress" format="integer"/> <attr name="max" format="integer"/> <attr name="isSetBar" format="boolean"/> <attr name="progressHeight" format="dimension"/> <attr name="progressHeightOffset" format="dimension"/> <attr name="refreshTime" format="integer"/> <attr name="animMode" format="enum"> <enum name="ANIM_NULL" value="0"/> <enum name="ANIM_ROTATE" value="1"/> <enum name="ANIM_SCALE" value="2"/> <enum name="ANIM_ROTATE_SCALE" value="3"/> <enum name="ANIM_FRAME" value="4"/> </attr> <attr name="rotateRate" format="integer"/> <attr name="rotateDegree" format="integer"/> <attr name="scaleMax" format="float"/> <attr name="scaleMin" format="float"/> <attr name="scaleRate" format="float"/> <attr name="isGradient" format="boolean"/> <attr name="gradientStartColor" format="color"/> <attr name="gradientEndColor" format="color"/> </declare-styleable> </resources>
一些set、get方法和其它
有了自己定义属性,仅仅是能在XML上使用。想要在Java代码上设置属性,还须要弄一些set、get方法,另一些特殊的属性,在xml设置不了,如帧动画的图片id数组、线性渐变器、进度监听器等,也须要set方法,由于有太多。以下仅仅列举一些特殊的出来://设置进度 public void setProgress(int progress) { if (progress <= max) { this.progress = progress; } else if (progress < 0){ this.progress = 0; } else { this.progress = max; } doProgressRefresh(); } //进行进度改变之后的操作 private synchronized void doProgressRefresh() { if (onProgressChangeListener != null) { onProgressChangeListener.onOnProgressChange(progress); if (progress >= max) { onProgressChangeListener.onOnProgressFinish(); } } } //设置动画开关 public void setAnimRun(boolean isAnimRun) { this.isAnimRun = isAnimRun; } //设置帧动画时要传入的图片ID数组 public void setDrawableIds(int[] drawableIds) { this.drawableIds = drawableIds; } //设置图片 public void setPicture(int id) { drawable = getResources().getDrawable(id); } //设置颜色渐变器 public void setLinearGradient(LinearGradient linearGradient) { this.linearGradient = linearGradient; } //设置进度监听器 public void setOnProgressChangeListener(OnProgressChangeListener onProgressChangeListener) { this.onProgressChangeListener = onProgressChangeListener; } //进度监听器 public interface OnProgressChangeListener { //进度改变时的回调 public void onOnProgressChange(int progress); //进度完毕时的回答 public void onOnProgressFinish(); }
7.公布
公布到GitHub
这个我相信大家都非常熟悉,我这里就简单的列出一下我把这个项目上传到GitHub(我是使用AndroidStudio上自带的功能。简单方便)的步骤吧:1. 首先是本地要安装git。没有的能够下载。
2. 在AndroidStudio的File的Setting选项配置Git信息
![](http://i.imgur.com/Sk0AygU.png)
3. 在Setting配置你的GitHub账号信息,没有的能够注冊,那里有button(我这个是AndroidStudio2.2版本号。不同的版本号可能里面的内容有一点不同),输入完账号password按Test连接一下,失败的确认好账号password多试几次。把timeout设置长点
![](http://i.imgur.com/UjKdeug.png)
4. 在VCS里点击例如以下(一个项目第一次提交时用这个),然后按提示操作commit即可了(由于我这个不是第一次提交就不演示下去了):
![](http://i.imgur.com/1C0ml3U.png)
5. 后面更新项目就是点击Commitbutton了,然后push了:
![](http://i.imgur.com/Tlw82TR.png)
![](http://i.imgur.com/HD0SwW5.png)
事实上到了第4步,在GitHub上就能看到我们的项目了(免得太多图就不贴了):https://github.com/totond/PictureProgressBar
公布到JCenter
我们开发有时候会用到一些第三方库,有一些库非常方便,在AS的Gradle里面compile ‘xxx’就能够引入了,我们把项目提交到JCenter,也能够让别人非常方便地引入了。公布到JCenter有非常多方法,本方法是參考鸿洋_大神的bintray-release插件方法,之后亲自试了非常多坑之后才成功的(鸿洋大神这篇方法有非常多细节没说,详细看它以下的评论)。能够说依据我这个步骤是肯定能成功的,以下我们来看看步骤:
1. 首先是在 https://bintray.com/signup/oss 进行注冊,不要直接在官网注冊,那是注冊企业试用版的。到时候你还要自己点击右上角的倒计时取消企业版切换回个人版。
注意注冊的邮箱不能是qq邮箱。163邮箱(不知道是不是全部中国的都不行)。
2. 注冊完之后首先就是查看自己的API,复制下来备用。后面的上传都要用到:
![](http://i.imgur.com/S3VVdpr.png)
3. 建立一个仓库,用来装代码(填好Name,里面的Type选择Maven,其它的都不用管了,点Create即可):
![](http://i.imgur.com/FajtM4C.png)
![](http://i.imgur.com/PGWqLF2.png)
4. 新建一个Module。把想要上传的代码放进去。上传就是上传这个Module(不这样做的话会在上传的时候报Error:Could not get unknown property ‘main’ for SourceSet container.)在这个Module的Gradle文件中面加入:
apply plugin: 'com.novoda.bintray-release'//最上方加入 publish { userOrg = 'yanzhikaijky' //Binaryusername repoName = 'CustomViewRepository' //Repository的名字 groupId = 'com.yanzhikaijky' //包名 artifactId = 'PictureProgressbar' //项目名 publishVersion = '1.1.0' //版本号号 desc = 'a picture progressbar' //description说明,随便写 website = 'https://github.com/totond/PictureProgressBar'//VCS地址,这里最好写GitHub的,我试过不写然后上传不了 }
* 5. 在项目的Gradle文件中加入(弄完就build一下project):*
//在dependencies里面加 classpath 'com.novoda:bintray-release:0.3.4'//加入bintray-release插件 //以下这个整个加进去 allprojects { repositories { jcenter() } //防止中文凝视出错 tasks.withType(Javadoc) { options { encoding "UTF-8" charSet 'UTF-8' links "http://docs.oracle.com/javase/7/docs/api" } } }
** 6. 在AndroidStudio的Terminal里输入这些命令(**Key里面的星号的内容实际上应该是我们的API KEY,我这里屏蔽掉而已。注意每行命令之间用一个空格隔开。这个非常重要),最后回车提交:
gradlew.bat clean build bintrayUpload -PbintrayUser=yanzhikaijky -PbintrayKey=***************************** -PdryRun=false
![](http://i.imgur.com/OUWZhBk.png)
第一次提交会比較慢(FQ可能会提快速度?),给点耐心,假设报错里面会显示出来。
7. 成功了之后,能够在网页上看到你的项目,左下能够看到怎样加入依赖,右下角会有一个Add To jcenter(由于这个项目早已经add了,所以借用一下鸿洋大神的图片),本项目JCenter地址:https://bintray.com/yanzhikaijky/CustomViewRepository/PictureProgressbar
![](http://i.imgur.com/j70WEWA.png)
8.加入开源协议和说明文档README
加入开源协议
开源项目能够选择一个开源协议来表示自己这个项目的许可声明。关于开源协议的选择,我这里也引用阮一峰老师的一篇文章里面的一幅图来大概说明一下:![](http://i.imgur.com/b13OBoo.png)
最后我选择了Apache v2 License。
至于怎样加入,一个方法是在GitHub创建Repository的时候选择加入(这个我一開始就忘了)。第二个是使用官方推荐的 www.addalicense.com 来给当前存在的Repository加入,然而
![](http://i.imgur.com/u1brY6x.png)
这东西我用不了。仅仅能採用第三种方法手动加入了:能够查看GitHub关于这个的帮助文档,看不懂英文没关系,隔壁有图说明:
![](http://i.imgur.com/7RIpV3R.png)
成功之后主页会多了一个表示开源协议的栏目:
![](http://i.imgur.com/y8kNkmb.png)
加入说明文档Readme
说明文档就是告诉别人你的开源项目怎样使用的文档,能够在Android Project的根文件夹下加入README.md文件然后Push上去或者直接在项目GitHub上Add a README。9.測试
在APP的Gradle里加入依赖项之后。就能够使用了:compile 'com.yanzhikaijky:PictureProgressbar:1.1.0'
这里的測试就是demo用了属性动画来控制进度变化(想了解属性动画的能够看下我这篇笔记),想详细看demo代码的,这里再次给出地址和效果:
![](http://i.imgur.com/076zTuA.gif)
后话
欢迎大家Star or Fork,使用Gradle依赖非常方便,也能够clone来试着按自己想法改动一下,改一下gradlewrapper文件就能够直接在你们的AS上执行了,欢迎提出意见和建议。这个PictureProgressBar的兴许可能会加入一些其它的动画和文字。眼下没有什么好的创意。假设大家有什么创意和意见,欢迎互相交流进步。
更新
version 1.1.1:2017/07/07修复bug:加入了progressPercentage属性来表示进度条进度比例,改动了
setProgress()内容,在里面加入
progressPercentage = progress/max;
防止在输入较大int数值的时候。计算进度操作导致int类型溢出的情况,例如以下载场景下的进度数值。
- version 1.1.2:2017/09/07修复bug:
progress/max得到0的结果,醉了过了两个月才发现。。。
version 1.2.0:2017/09/11更新:
1.修复非圆角进度条宽度设置失效问题。
2.进度条左方预留空间给图片,不会出现进度0%可是还是显示有载入了部分进度的情况。
3.新增进度条的图片设置,相似官方ProgressBar的图片平铺设置功能。详细效果可看README。
最新版本号
compile 'com.yanzhikaijky:PictureProgressbar:1.2.0'
相关文章推荐
- 自定义进度条PictureProgressBar——从开发到开源发布全过程
- 让我们一起来对VSTS扩展开发吧------制作自己的VSTS模版----第五节 分析过程模版的定义文件
- 分享android开发过程中用到的一些开源框架
- 【微信公众平台开发】创建自己定义菜单(四)
- 【课程分享】基于plusgantt的项目管理系统实战开发(Spring3+JDBC+RMI的架构、自己定义工作流)
- 安卓开发中非常炫的效果集合 这几天开发的时候,想做一些好看而且酷炫的特效,于是又开始从网上收集各种特效资源。下面给大家一些我喜欢的把,附代码,喜欢的看源代码,然后加到自己项目去把!! 一个开源项目
- 自己组队开发的sns,功能强大开源哦
- 学习安卓开发过程之中,自己倒腾的两个小项目,一个是音乐播放器,一个是天气预报。
- 今天我来整理下自己开发CM完成第一个项目HTC a5 的编译过程
- 分享android开发过程中用到的一些开源框架
- 根据自己的需要,把别人开发好的东西搬过来,优化and重构,在优化的过程中,甚至也会弄出一套全新的东西(转)
- 安卓应用开发之定义自己的权限
- DWZ富客户端框架(jQuery RIA framework), 是中国人自己开发的基于jQuery实现的Ajax RIA开源框架.
- android自己定义渐变进度条
- Android自己定义控件--圆形进度条(中间有图diao)
- 软件开发过程中提升用户体验的途径[自己整理了下]
- 在oschian上面建立自己的开源项目livefeng的过程
- 安卓高德地图开发自定义线路规划(按着自己定义的经纬度规划线路)
- 分享android开发过程中用到的一些开源框架
- 知方可补不足~开发人员可以自己定义VS文件模版