Android实用view系列------炫酷的进度条

不知不觉距离上次写文章已经过去大半个月了,原本计划每周写一篇的想法在坚持几周之后最终还是被生活中各种各样的琐事打乱,无奈中夹杂这对自己的一点失望。


心痛.jpg

当初的愿望实现了吗
事到如今只好祭奠吗
任岁月风干理想再也找不回真的我
抬头仰望着满天星河
那时候陪伴我的那颗
这里的故事你是否还记得

今天给大家带来的是自定义view系列之炫酷的进度条的效果,让你的进度条从此与众不同。

按照惯例先上效果图,俗话说无图无有真相嘛。

60%的进度条.png
100%的进度条.png
模拟器的效果没有真机好.gif

我们可以看出来这其实就是一个进度条,此时的你或许心生疑惑,MD一个进度条有什么好说的,无论是官方的ProgressBar的还是GitHub开源的一抓一大把,这有什么好讲的。有这样的想法很正常,毕竟我曾经看别人写的文章的时候也会冒出这样的想法。

哈哈

那么我为什么还要写呐,首先并不是我们所有的需求都能在网上找到,其次,即使找到类似的代码修修补补也能用,但对我们的提升并不大,作为一名合格的开发人员只有亲手撸出来的代码用着才踏实嘛,我们是抱着学习的心态看问题,分析问题,并解决它的。

说了那么多废话下边就开始步入正题吧

如果真是一个简简单单的进度条的话确实没什么好讲的,仔细观察效果图后你会发现其实还是有点内容的,麻雀虽小五脏俱全。

这里边有几个点需要说明一下:
①、进度条有动画效果
②、进度条上边有个百分比的样式的绘制
③、百分比tip框跟随进度条移动需要注意的事项

1、带动画的进度条效果

因为我们是自定义view,看到的所有元素都是在onDraw里边绘制出来的,分析进度条效果我们可以分解出几个步骤,先绘制底层百分百进度条(也就是背景色),再绘制真实的进度。

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //  tipHeight + progressMarginTop其实是把进度条绘制到百分比tip框的下边
        //  这里只是给出大概的计算,如有需求可以精确计算高度
        //绘制背景
        canvas.drawLine(getPaddingLeft(),
                tipHeight + progressMarginTop,
                getWidth(),
                tipHeight + progressMarginTop,
                bgPaint);
        //绘制真实进度
        canvas.drawLine(getPaddingLeft(),
                tipHeight + progressMarginTop,
                currentProgress,
                tipHeight + progressMarginTop,
                progressPaint);

    }

进度条画完之后就是让它动起来,我们使用属性动画试试改变当前进度的值重新绘制就可以了,动画效果我们继续使用ValueAnimator

  /**
     * 进度移动动画  通过插值的方式改变移动的距离
     */
    private void initAnimation() {
        progressAnimator = ValueAnimator.ofFloat(0, mProgress);
        progressAnimator.setDuration(duration);
        progressAnimator.setStartDelay(startDelay);
        progressAnimator.setInterpolator(new LinearInterpolator());
        progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float value = (float) valueAnimator.getAnimatedValue();
                //这是我们自己的需求进度只显示整数
                textString = formatNum(format2Int(value));
                //百分比的进度转换成view宽度一样的比例
                currentProgress = value * mWidth / 100;
                //进度回调方法
                if (progressListener != null) {
                    progressListener.currentProgressListener(value);
                }               
                invalidate();
            }
        });
        progressAnimator.start();
    }

到此带动画的进度条就实现了,一起看一下效果吧

progress1.gif

2、绘制上边的百分比布局

image.png

看到这个百分比的提示框,你会想到如何实现呐,很多人会选择使用图片然后变更图片的位置来达到效果,作为一个有追求的程序猿怎能满足于此呐,自己绘制出来岂不更好。
很强势.jpg

接下来我们来分析一下如何绘制这个带三角的矩形

这里说一下我们实现思路:其实第一次我是准备从起点到终点用过画闭合的线做的,需要计算七个点的坐标,最终能实现,但是这种方法太笨了,根本拿不出手哦


根据点绘制闭合的线.png

在苦思的时候突然又看了一眼设计图发现这个矩形是带圆角的,我这样绘制闭合的线是达不到圆角效果的,等等,圆角?圆角不是可以通过绘制圆角矩形画出来么,我擦,貌似这是一个不错的思路,赶紧去验证。


圆角矩形+三角形.png

果不其然,堪称完美,先绘制一个圆角矩形,在其下边绘制一个三角形,至于里边的进度数值直接drawText就行了


嘚瑟.gif
    /**
     * 绘制进度上边提示百分比的view
     *
     * @param canvas
     */
    private void drawTipView(Canvas canvas) {
        drawRoundRect(canvas);
        drawTriangle(canvas);
    }


    /**
     * 绘制圆角矩形
     *
     * @param canvas
     */
    private void drawRoundRect(Canvas canvas) {
        rectF.set(moveDis, 0, tipWidth + moveDis, tipHeight);
        canvas.drawRoundRect(rectF, roundRectRadius, roundRectRadius, tipPaint);
    }

    /**
     * 绘制三角形
     *
     * @param canvas
     */
    private void drawTriangle(Canvas canvas) {
        path.moveTo(tipWidth / 2 - triangleHeight + moveDis, tipHeight);
        path.lineTo(tipWidth / 2 + moveDis, tipHeight + triangleHeight);
        path.lineTo(tipWidth / 2 + triangleHeight + moveDis, tipHeight);
        canvas.drawPath(path, tipPaint);
        path.reset();

    }

3、计算百分比Tip框的起始位置及移动分析

样式绘制出来接下来就是各种计算了,先来张手绘图凑合着看哈

手绘图,忽略字迹看内容哈.png

担心图片不清晰就再对图片内容描述一下,重要信息有四个,进度的起始点A和B、tip框的起始点M和N,动画执行过程是这样的:刚开始的时候只有进度条移动,此时tip框是不动的,当进度条到达tip框中间三角形顶点x坐标的时候,tip框跟着进度开始一起移动,当tip框右边界到达整个进度的右边界的时候,tip框停止移动,进度条继续移动一直到终点。

 /**
     * 进度移动动画  通过插值的方式改变移动的距离
     */
    private void initAnimation() {
        progressAnimator = ValueAnimator.ofFloat(0, mProgress);
        progressAnimator.setDuration(duration);
        progressAnimator.setStartDelay(startDelay);
        progressAnimator.setInterpolator(new LinearInterpolator());
        progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float value = (float) valueAnimator.getAnimatedValue();
                //进度数值只显示整数,我们自己的需求,可以忽略
                textString = formatNum(format2Int(value));
                //把当前百分比进度转化成view宽度对应的比例
                currentProgress = value * mWidth / 100;
                //进度回调方法
                if (progressListener != null) {
                    progressListener.currentProgressListener(value);
                }
                //移动百分比提示框,只有当前进度到提示框中间位置之后开始移动,
                //当进度框移动到最右边的时候停止移动,但是进度条还可以继续移动
                //moveDis是tip框移动的距离
                if (currentProgress >= (tipWidth / 2) &&
                        currentProgress <= (mWidth - tipWidth / 2)) {
                    moveDis = currentProgress - tipWidth / 2;
                }
                invalidate();
            }
        });
        progressAnimator.start();
    }
最终实现的效果
progress.gif

写在最后

到此本篇文章终点部分已经结束,按照惯例应该做下总结的,但今天并没有这个打算(毕竟文章里边技术点描述的很清楚了,哈哈😆)。这里就分享一下我的一些看法吧,敲代码其实是一件很枯燥的事,每天面对一大堆字母时间久了或多或少会心烦,那么我们怎样才能保持一个好的状态去coding呐,培养自己的兴趣,兴趣真的很重要,有了兴趣你会把敲代码当做生活的一部分而不仅仅是工作。这样生活才有意义,否则时间久了真的会颓废。

网络图片,仅供娱乐

github源码地址传送门


谨以此篇来记录自己项目中遇到的问题,献给需要类似功能的小伙伴们。如果你有好的建议欢迎评论指出,大家一起讨论、学习、进步!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,724评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,104评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,142评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,086评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,076评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,914评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,220评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,871评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,318评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,834评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,951评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,574评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,162评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,162评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,383评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,349评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,652评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,489评论 25 707
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,708评论 22 664
  • 前言 最近项目中新增了一个抢购模块,需要一个进度指示条,UI设计了几款出来后,PM一看,不行,太low了,没有逼...
    luckyzh阅读 8,142评论 16 55
  • 学习资料//www.greatytc.com/u/51d1fd73fb72 这里是跟随原作者的博客进行的自...
    wt龙阅读 599评论 0 0
  • 昨夜梦回,梦中人终不再是背影和侧眸,我们终于可以坐下来,聊聊天。你问了我很多关于女生的想法,你说我还是喜欢简单大方...
    纪书阅读 275评论 0 0