自定义View实现圆形水波进度条(上)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

来源:伯乐在线专栏作者 - Code4Android

链接:http://android.jobbole.com/84776/


每次听到某大牛谈论自定义View,顿时敬佩之心,如滔滔江水连绵不绝,心想我什么时候能有如此境界,好了,心动不如行动,于是我开始了自定义View之路,虽然过程有坎坷,但是结果我还是挺满意的。我知道大牛还遥不可及,但是我已使出洪荒之力。此篇博客记录本人初入自定义View之路。


既然是初出茅庐,自然是按部就班的进行,先来一张效果图




本文章所写项目代码的GitHub链接

https://github.com/xiehui999/CustomBall


自定义属性


自定义属性,就是在资源文件夹下values目录中创建一个attrs.xml文件,

文件结构如下所示,atrr标签就是我们要自定义的一些属性,name就是自定义属性的名字,那么format是做什么的呢?


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="">
        <attr name="centerText" format=""></attr>
        <attr name=" ">
            <enum name=""  value=" "></enum>
            <enum name="" value=" "></enum>
        </attr>
    </declare-styleable>
</resources>


format是属性对应的值的类型,有十个值


  • enm 枚举类型,例 android:orientation=”vertical” 此值有horizontal,和 vertical

  • dimension 尺寸值

  • color 颜色值,例 android:textColor = “#00FF00”

  • boolean 布尔值,true or false

  • flag 位或运算

  • float 浮点型

  • fraction 百分数,

  • reference 参考某一资源ID,例 android:background = “@drawable/ic_launcher”

  • string 字符串类型

  • integer 整型值


知道了这些值得含义,就可以自定义我们自己的属性了,对于这个进度条,我们可以自定义圆的半径,颜色,和圆中心文本的大小,颜色,文本,最后attrs.xml文件为


<?xmlversion="1.0"encoding="utf-8"?>
<resources>
    <declare-styleablename="CustomBallView">
        <attrname="centerText"format="string"></attr>
        <attrname="centerTextSize"format="dimension"></attr>
        <attrname="centerTextColor"format="color"></attr>
        <attrname="ballColor"format="color"></attr>
        <attrname="ballRadius"format="dimension"></attr>
    </declare-styleable>
</resources>



布局文件配置相关内容


在布局文件要配置我们自定义的属性,首先要自定义命名空间,



如上图,如果在as中命名空间写成http://schemas.android.com/apk/res/包名 此时as会报错,这是gradle造成的,在eclipse中如果自定义的属性 是不能用res-auto的 必须得替换成你自定义view所属的包名,如果你在恰好使用的自定义属性被做成了lib 那就只能使用res-auto了,而在android-studio里,无论你是自己写自定义view 还是引用的lib里的自定义的view 都只能使用res-auto这个写法。以前那个包名的写法 在android-studio里是被废弃无法使用的

所以配置后的布局文件如下


<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:customBallView="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.xh.customball.MainActivity"
    tools:showIn="@layout/activity_main">
 
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        android:text="Hello World!" />
 
    <com.example.xh.customball.CustomBall
        android:background="@color/colorPrimary"
        android:layout_centerInParent="true"
        android:layout_margin="10dp"
        customBallView:centerText="30%"
        customBallView:centerTextSize="28dp"
        customBallView:centerTextColor="#000000"
        customBallView:ballColor="@color/colorAccent"
        customBallView:ballRadius="30dp"
        android:layout_width="260dp"
        android:layout_height="260dp">
    </com.example.xh.customball.CustomBall>
</LinearLayout>



自定义控件


有了上边的操作,接下来就开始到了真正自定义控件的时候了,创建一个CustomBall类继承View类,先看构造方法,我们写成构造方法最终调用三个参数的构造方法,获取自定义属性的值及初始化工作就在三个参数构造方法中进行。下面我先来绘制一个圆,文字画在圆心试试手,效果如图



当然绘制这个图形,首先获取我们自定义属性值,可通过下面获取属性值

注意通过TypedArray 获取属性值后要执行typedArray.recycle();回收内存,防止内存泄漏。


/**
* 获取自定义属性
*/
TypedArraytypedArray=context.obtainStyledAttributes(attrs,R.styleable.customBallView);
        centerText=typedArray.getString(R.styleable.customBallView_centerText);
        Log.e("TAG","centerText"+centerText);
        centerTextSize=typedArray.getDimension(R.styleable.customBallView_centerTextSize,24f);
        centerTextColor=typedArray.getColor(R.styleable.customBallView_centerTextColor,0xFFFFFF);
        ballColor=typedArray.getColor(R.styleable.customBallView_ballColor,0xFF4081);
        radius=typedArray.getDimension(R.styleable.customBallView_ballRadius,260f);
        typedArray.recycle();



初始化画笔

/**
     * 初始化画笔
     */
    privatevoidinitPaint(){
        roundPaint = newPaint();
        roundPaint.setColor(ballColor);
        roundPaint.setAntiAlias(true);//抗锯齿
        fontPaint = newPaint();
        fontPaint.setTextSize(centerTextSize);
        fontPaint.setColor(centerTextColor);
        fontPaint.setAntiAlias(true);
        fontPaint.setFakeBoldText(true);//粗体
 
    }



接下来我们先画一个圆,先通过下面方法获取空间本身的宽和高,然后调用canvas.drawCircle(width/2, height/2, radius, roundPaint);画圆,在原点设置为控件中心位置,即点(width/2, height/2),半径为radius,画笔roundPaint,接下来绘制文字,将位子绘制在圆的中心。


width = getWidth();

height = getHeight();


如果我们通过canvas.drawText(centerText, width/2, height/2, fontPaint);绘制文字的话,发现文字并不是在中心位置,那么我们可以做一下调整,canvas.drawText(centerText, width/2, height/2, fontPaint);先通过float textWidth = fontPaint.measureText(centerText);获取文字的宽度,canvas.drawText(centerText, width/2-textWidth /2, height/2, fontPaint);此时文字依然不在中心,那么此时我们研究一下文字到底是怎么绘制的,为什么坐标试试中心了,绘制出来的效果依然有偏差呢。


要关注文字绘制的话,FontMetrics这个类是必须要知道的因为它的作用是测量文字,它里面呢就定义了top,ascent,descent,bottom,leading五个成员变量其他什么也没有。先看源码


publicstaticclassFontMetrics{
        /**
         * The maximum distance above the baseline for the tallest glyph in
         * the font at a given text size.
         */
        publicfloat  top;
        /**
         * The recommended distance above the baseline for singled spaced text.
         */
        publicfloat  ascent;
        /**
         * The recommended distance below the baseline for singled spaced text.
         */
        publicfloat  descent;
        /**
         * The maximum distance below the baseline for the lowest glyph in
         * the font at a given text size.
         */
        publicfloat  bottom;
        /**
         * The recommended additional space to add between lines of text.
         */
        publicfloat  leading;
    }



这个类是Paint的静态内部类,通过注释我们就知道了每个变量的含义,为了更生动的理解这几个变量含义,我们通过下面的一张图来分别解释每个变量的含义



  • Baseline(基线) 在Android中,文字的绘制都是从Baseline处开始的

  • ascent(上坡度)Baseline往上至文字“最高处”的距离我们称之为ascent,

  • descent(下坡度)Baseline往下至文字“最低处”的距离我们称之为descent(下坡度)

  • leading(行间距)表示上一行文字的descent到该行文字的ascent之间的距离

  • top 对于ascent上面还有一部分内边距,内边距加上ascent即为top值

  • bottom descent和内边距的加上descent距离值得注意的一点,Baseline上方的值为负,下方的值为正如下图文字30%的ascent,descent,top,bottom。



通过上面的分析,我们就得出了将文本绘制中心的代码如下


//测量文字的宽度
floattextWidth = fontPaint.measureText(centerText);
        floatx = width / 2 - textWidth / 2;
        Paint.FontMetricsfontMetrics = fontPaint.getFontMetrics();
        floatdy = -(fontMetrics.descent + fontMetrics.ascent) / 2;
        floaty = height / 2  +dy;
        canvas.drawText(centerText,x,y,fontPaint);



至此这个简单自定义的View基本实现,此时我改了布局配置文件为宽高


android:layout_width="wrap_content"

android:layout_height="wrap_content"


或者


 android:layout_width="match_parent"

  android:layout_height="match_parent"


Oh my God,为什么效果是一样的啊,此时再回到自定义的类,我们发现我们没有实现onMeasure里面测量的代码,接下来让我们实现onMeasure操作,如下


@Override
    protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
        super.onMeasure(widthMeasureSpec,heightMeasureSpec);
        //测量模式
        intwidthMode = MeasureSpec.getMode(widthMeasureSpec);
        intheightMode = MeasureSpec.getMode(heightMeasureSpec);
        //测量规格大小
        intwidthSize = MeasureSpec.getSize(widthMeasureSpec);
        intheightSize = MeasureSpec.getSize(heightMeasureSpec);
 
        intwidth;
        intheight;
        if(widthMode == MeasureSpec.EXACTLY){
            width=widthSize;
        }elseif(widthMode == MeasureSpec.AT_MOST){
            width=(int)Math.min(widthSize,radius*2);
        }else{
 
            width=windowWidth;
        }
        if(heightMode == MeasureSpec.EXACTLY){
            height=heightSize;
        }elseif(heightMode == MeasureSpec.AT_MOST){
            height=(int)Math.min(heightSize,radius*2);
        }else{
            height=windowHeight;
        }
        setMeasuredDimension(width,height);
    }



测量主要依靠MeasureSpec,MeasureSpec(测量规格)是一个32位的int数据.其中高2位代表SpecMode即某种测量模式,低32位为SpecSize代表在该模式下的规格大小,测量模式有三种


  • EXACTLY 确切的,在布局文件中设置的宽高是固定的,此时测量大小就是我们设置的宽高

  • AT_MOST 至多,不能超出

  • UNSPECIFIED 未指定


MeasureSpec的详细解释

http://blog.csdn.net/lfdfhl/article/details/50880382


通过上面的分析,绘制此图形的完整代码为 点击查看

https://github.com/xiehui999/CustomBall/blob/master/app/src/main/java/com/example/xh/customball/CustomBall.java


控件升级


上面我们已经实现了圆形和文本的绘制,那么接下来,我们先开始实现中心新进度的更新绘制。先看效果图


android 自定义圆形水波进度条 android app开发中,自定义进度条是常用的功能 今天来自定义圆形水波进度条 自定义View import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Pain 阅读详情

相关推荐

canvas和纯 CSS 实现波浪进度图

使用 SVG 实现波浪效果(SVG、CANVAS 实现贝塞尔曲线) 使用 canvas 实现波浪效果的原理与 SVG 一样,都是利用路径绘制出三次贝塞尔曲线并赋予动画效果。 主要是利用了动态绘制 ctx.bezierCurveTo() 三次贝塞尔曲线实现波浪的运动效果。 纯 CSS 实现波浪效果(这里背景是蓝色静止的,运动是白色的椭圆形) 后面漂浮的波浪效果,其实就是利用了上面的 border-radius: 45% 的椭圆形,只是放大了很多倍,视野之外的图形都 overflow: hidden ,只留下了一条边的视野,并且增加了一些相应的 transform 变换。 为了方便写 DEMO,用到的长度单位是 VW 与 VH,不太了解这两个单位的可以戳这里:vh、vw、vmin、vmax 知多少 在动画过程中,动态的改变 border-radius 的值; 在动画过程中,利用 transform 对旋转椭圆进行轻微的位移、变形; 上面也演示到了,多个椭圆同时转动,赋予不同时长的动画,并且添加轻微的透明度,让整个效果更佳逼真。 一个圆形的进度和波浪状态的滑动的新DEMO查看预览。

Android应用自动更新功能的代码实现

由于Android项目开源所致,市面上出现了N多安卓软件市场。为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量。因此我们有必要给我们的Android应用增加自动更新的功能。 既然实现自动更新,我们首先必须让我们的应用知道是否存在新版本的软件,因此我们可以在自己的网站上放置配置文件,存放软件的版本信息:

kingsonl的专栏 1188

水波球效果

通过白塞尔曲线实现的一个水波球效果,类似剩余流量显示的效果。摘要为什么一定要大于100个字节,啊啊啊.......!

Android 自定义View之咖啡杯动画

效果 大概思路 自定义view,直接继承view 复写onSizeChanged()方法,在此计算杯垫,杯子,烟雾效果的path 在onDraw()方法中,描绘杯垫,杯子 处理烟雾动画效果 画杯子 这里需要画两部分内容,第一部分是杯子,第二部分是杯耳(提手的地方) 我们可以使用addRoundRect来描绘圆角矩形,并且可指定每个圆角的半径即圆角的程度 /** * Add a close...

weixin_34255793的博客 289

简单圆球水波动。手写

* { margin: 0; padding: 0; } .nei { width: 400px; height: 400px; background: red; opacity: 0.2; border-radius: 150px; position: absolute; left: -100px;

Thekingyu的博客 890

一看就懂的自定义View -- 水波圆形进度球

在开发过程中,为了丰富我们的软件功能,我们常常需要很多控件、视图,虽然android为我们提供了很多控件,但是都很普通,功能也不够强大,所以,一个自定义view便成为了我们在开发过程中必须要掌握的。 看完这篇文章,我相信大家会对自定义view有一个初步的认识,也能够打开自定义view的大门。 本文从自定义view的应用出发,对原理不作深究。 本文解释详尽,保证一看就懂,不懂你来找我。 首先

qq_26525715的博客 1373

自定义画圆进度条,带波浪动态效果

代码如下 <template> <view> <view style="margin-top: 200rpx;"> <view > <canvas class="cir-view" canvas-id="myCanvas4"></canvas> </view> </view> </view> </template> <script> cons...

wanmeizty的专栏 909

自定义View实现圆形水波进度条

每次听到某大牛谈论自定义View,顿时敬佩之心,如滔滔江水连绵不绝,心想我什么时候能有如此境界,好了,心动不如行动,于是我开始了自定义View之路,虽然过程有坎坷,但是结果我还是挺满意的。我知道大牛还遥不可及,但是我已使出洪荒之力。此篇博客记录本人初入自定义View之路。既然是初出茅庐,自然是按部就班的进行,先来一张效果图 本文章所写项目代码的GitHub链接自定义属性自定义属性,就是在资源文件夹

Code4Android 8402

Android自定义滑动进度条,Android自定义View实现圆形水波进度条

每次听到某大牛谈论自定义View,顿时敬佩之心,如滔滔江水连绵不绝,心想我什么时候能有如此境界,好了,心动不如行动,于是我开始了自定义View之路,虽然过程有坎坷,但是结果我还是挺满意的。我知道大牛还遥不可及,但是我已使出洪荒之力。此篇博客记录本人初入自定义View之路。既然是初出茅庐,自然是按部就班的进行,先来一张效果图自定义属性自定义属性,就是在资源文件夹下values目录中创建一个attrs...

weixin_42500642的博客 689

自定义View实现圆形水波进度条(下)

来源:伯乐在线专栏作者 - Code4Android 链接:http://android.jobbole.com/84776/ 接上文 通过效果图,我们看到实现此效果就是不断的更新进度值,然后重绘,,那么我们只需开启一个线程实现更新进度值,为了更好的控制我们再加点击事件,当单机时开始增大进度,双击时暂停进度,并弹出Snackbar,其中有一个重置按钮,

2660

android绘制环形进度_Android 自定义 View圆形进度条总结

原标题:Android 自定义 View圆形进度条总结最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View 。在此对项目开发思路做个小结,欢迎大家 Star 和 Fork该项目总共实现了三种圆形进度条效果CircleProgress:圆形进度条,可以实现仿 QQ 健康计步器的效果,支持配置进度条背景色、宽度、起始角度,支持进度条渐变DialProgress:类似 Circ...

weixin_39888412的博客 413

android自定义view圆,Android自定义view实现圆形waveview

最近学习了贝塞尔曲线的一些知识,刚好项目中需要实现一个圆形进度,然后就将实现的waveView记录一下。需要使用的知识大概有自定义view、贝塞尔曲线、valueAnimator(属性动画)、Xfermode等。以下为效果图:废话不多说,直接上代码这里只是一些重要的代码。如果需要demo可以去下载。首先需要自定义view的属性: //圆的颜色 //圆的背景色 //水波纹的颜色 //字体的大小 //...

weixin_39788960的博客 329

Android进度条阴影,Android自定义View圆形进度条总结

最近撸了一个圆形进度条的开源项目,算是***次完完整整的使用自定义 View 。在此对项目开发思路做个小结,欢迎大家 Star 和 Fork。该项目总共实现了三种圆形进度条效果CircleProgress:圆形进度条,可以实现仿 QQ 健康计步器的效果,支持配置进度条背景色、宽度、起始角度,支持进度条渐变DialProgress:类似 CircleProgress,但是支持刻度WaveProgre...

weixin_39642619的博客 500

android多个点的圆形进度条,Android 自定义圆形进度条总结

原标题:Android 自定义圆形进度条总结安卓巴士全球开发者论坛【北京站】安卓巴士全球开发者论坛邀请了在Android开发领域拥有多年经验的老司机,与你相约北京,带上你的开发好友,一起聊聊Android开发中,那些一线程序员技术干货。活动详情: 最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View 。在此对项目开发思路做个小结。该项目总共实现了三种圆形进度条效果Circle...

weixin_42565865的博客 802

使用自定义view模拟充电界面

1.自定义view的图形 代码: public class ProgressCircleView extends androidx.appcompat.widget.AppCompatTextView { private int mHeight; //控件宽高 private int mWidth; // private int mStartX; //起始位置坐标 private int mStartY; // private Paint mPaint; /

weixin_45219242的博客 420

Android智能推荐、MVP架构电商应用、markdown编辑器、多种动画效果源码等

Android精选源码 Android一款基于行为识别和个性化推荐的智能推荐APP android采用mvp架构电商服务平台源码 类似于淘宝,天猫,京东,支持多维属性选择器,购物车… android一个开源的 markdown 编辑器 Android类 Instagram 的色彩渐变效果。 android仿饿了么加入购物车旋转控件动画按钮。 ...

ld11620967的博客 809

Android 自定义 View 圆形进度条总结

Android 自定义圆形进度条总结 版权声明:本文为博主原创文章,未经博主允许不得转载。 微博:厉圣杰 微信公众号:牙锅子 源码:CircleProgress 文中如有纰漏,欢迎大家留言指出。 最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View 。在此对项目开发思路做个小结,欢迎大家 Star 和 Fork 该项目总共实现了三种圆形进度条效果 CircleProgr

I_wait_for_you的专栏 1107

Android-自定义View圆形进度条总结

最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View 。在此对项目开发思路做个小结,欢迎大家 Star 和 Fork。该项目总共实现了三种圆形进度条效果:圆形进度条、带刻度的圆形进度条已经水波进度条

I_wait_for_you的专栏 826
上一篇: Android 安全加密:对称加密
下一篇: 自定义View实现圆形水波进度条(下)
果然是酱
博客等级 码龄13年 12粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值