专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
开发者全社区  ·  某司年会真High ·  22 小时前  
开发者全社区  ·  2025新名词:「闲置员工」 ·  昨天  
开发者全社区  ·  年会上被迫营业的小姐姐 ·  昨天  
开发者全社区  ·  北师大第一大美女 ·  2 天前  
开发者全社区  ·  天王回乡的瓜 ·  2 天前  
51好读  ›  专栏  ›  安卓开发精选

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

安卓开发精选  · 公众号  · android  · 2016-09-23 08:37

正文

(点击 上方公众号 ,可快速关注)


来源:伯乐在线专栏作者 - 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" ?>

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文件为


xml version = "1.0" encoding = "utf-8" ?>

declare - styleable name = "CustomBallView" >

attr name = "centerText" format = "string" > attr >

attr name = "centerTextSize" format = "dimension" > attr >

attr name = "centerTextColor" format = "color" > attr >

attr name = "ballColor" format = "color" > attr >

attr name = "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里是被废弃无法使用的

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


xml version = "1.0" encoding = "utf-8" ?>

LinearLayout xmlns : 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();回收内存,防止内存泄漏。


/**

* 获取自定义属性

*/

TypedArray typedArray = 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 ();


初始化画笔


/**

* 初始化画笔

*/

private void initPaint () {

roundPaint = new Paint ();

roundPaint . setColor ( ballColor );

roundPaint . setAntiAlias ( true ); //抗锯齿

fontPaint = new Paint ();

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五个成员变量其他什么也没有。先看源码


public static class FontMetrics {

/**

* The maximum distance above the baseline for the tallest glyph in

* the font at a given text size.

*/

public float top ;

/**

* The recommended distance above the baseline for singled spaced text.

*/

public float ascent ;

/**

* The recommended distance below the baseline for singled spaced text.

*/

public float descent ;

/**

* The maximum distance below the baseline for the lowest glyph in

* the font at a given text size.

*/

public float bottom ;

/**

* The recommended additional space to add between lines of text.

*/

public float 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。



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


//测量文字的宽度

float textWidth = fontPaint . measureText ( centerText );

float x = width / 2 - textWidth / 2 ;

Paint . FontMetrics fontMetrics = fontPaint . getFontMetrics ();

float dy = - ( fontMetrics . descent + fontMetrics . ascent ) / 2 ;

float y = height / 2 + dy ;

canvas . drawText ( centerText , x , y , fontPaint );


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


android : layout_width = "wrap_content"

android : layout_height = "wrap_content"


或者


android : layout_width =







请到「今天看啥」查看全文


推荐文章
开发者全社区  ·  某司年会真High
22 小时前
开发者全社区  ·  2025新名词:「闲置员工」
昨天
开发者全社区  ·  年会上被迫营业的小姐姐
昨天
开发者全社区  ·  北师大第一大美女
2 天前
开发者全社区  ·  天王回乡的瓜
2 天前
THLDL领导力  ·  欲为大树,莫与草争(深度好文)
8 年前
携程每日特惠  ·  我们竟然找到了世界上真正的圣诞老人!
8 年前
射手座网  ·  射手座的最古怪性癖,不可思议!
7 年前