说到自定义控件,我想说其实我们做Android的,都学过Java基础,都明白什么是面向对象的思想, 既然有人造了轮子,我们直接拿来用就可以,当然有时间我们还是要研究自定义控件常用的一些类、方法等,然后把别人的自定义控件修改成自己所要的需求。
一、理论基础篇
1.直接继承View或者View的子类,View类中没有提供无参的构造方法,IDE会提醒你声明一个带有父类一样签名列表的构造方法。
2. 在自定义View的构造方法中必须添加一个AttributeSet类型的签名来解析这些属性;否则布局中引用自定义控件的时候会报错,因为控件要有宽和高的属性值;
3.在onDraw(Canvas canvas){ }方法实现要画的东西;这个时候需要画笔和画布,重写这个方法就可以拿到画布,new 个画布就可以;
4. 给画布设置属性:设置相应的属性调用setter方法就可以,比如说抗锯齿(让画出来的东西更加圆滑光泽),setAntiAlias(true)就可以;
5. 创建画笔的时候刚开始用有些人就会直接在onDraw()方法中new 画笔,运行后开发工具会报错,因为onDraw()方法是一个经常会调用的方法, 调用一次就创建一个画笔对象,会很占内存,建议在构造方法里面创建;
6.画笔有了,画笔的属性有了,要画什么东西? 通过画布对象canvas调用drawXXX()方法,画相应你要画的东西;
7. 要注意的是,如果没有特别说明,设置参数的单位一般都是px像素;
8. 如果要实现动画效果,会调用到重绘方法invalidate();
二、深入说明—— 画笔中设置颜色过滤类ColorFilter
1.set(Paint src) --- 为当前的画笔设置一个画笔,就是把一个画笔的属性设置copy给我们的画笔;
2.setAntiAlias(boolean aa) -- 一般圆形要设置抗锯齿,像矩形这种一般就不用;
3.setColorFilter(ColorFilter filter) --- 设置颜色过滤,获取我们想要的色彩结果;ColorFilter有三个子类LightingColorFilter、PortDuffColorFilter、ColorMatrixColorFilter。现在找工作那么难,一定要深究;
4.ColorMatrixColorFilter-- 色彩矩阵颜色过滤器。 在Android中图片是以RGBA像素点的形式加载到内存中,修改这些像素信息需要一个叫做ColorMatrix类支持,其定义了一个4x5的float[]类型的矩阵;第一行表示R(红色)的向量,第二行表示G(绿色)的向量,第三表示B(蓝色)的向量,最后一行表示A(透明度)的向量。1代表保持原图的RGB值,其取值范围在0.0F--2.0F之间。每一行的第5列代表偏移值。 单个颜色的时候我们直接用setColor()方法就行,如果是一张图片的时候我们就要用到矩阵这个东西。
5.LightingColorFilter -- 光照颜色过滤,该类有且只有一个构造方法:LightingColorFilter (intmul,intadd);
这个方法非常非常地简单!mul全称是colorMultiply意为色彩倍增,而add全称是colorAdd意为色彩添加,这两个值都是16进制的色彩值0xAARRGGBB。当LightingColorFilter(0xFFFFFFFF, 0x00000000)的时候原图是不会有任何改变的,如果我们想增加红色的值,那么LightingColorFilter(0xFFFFFFFF, 0x00XX0000)就好,其中XX取值为00至FF。那么这个方法有什么存在的意义呢?存在必定合理,这个方法存在一定是有它可用之处的,前些天有个盆友在群里问点击一个图片如何直接改变它的颜色而不是为他多准备另一张点击效果的图片,这种情况下该方法就派上用场了!
6.PortDuffColorFilter---PorterDuffColorFilter跟LightingColorFilter一样,只有一个构造方法:PorterDuffColorFilter(intcolor, PorterDuff.Mode mode),这个构造方法也接受两个值,一个是16进制表示的颜色值这个很好理解,而另一个是PorterDuff内部类Mode中的一个常量值,这个值表示混合模式。那么什么是混合模式呢?混合混合必定是有两种东西混才行,第一种就是我们设置的color值而第二种当然就是我们画布上的元素了!,比如这里我们把Color的值设为红色,而模式设为PorterDuff.Mode.DARKEN变暗。
三、深入说明—— 画笔中设置混合模式类Xfermode
1.Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的“过渡”其实就是图像混合的一种,这个方法跟我们上面讲到的setColorFilter蛮相似的,首先它与set一样没有公开的实现的方法:同理可得其必然有一定的子类去实现一些方法供我们使用,查看API文档发现其果然有三个子类:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode,这三个子类实现的功能要比setColorFilter的三个子类复杂得多。
2.AvoidXfermode--首先我要告诉大家的是这个API因为不支持硬件加速在API 16已经过时了(大家可以在HardwareAccel查看那些方法不支持硬件加速)……如果想在高于API 16的机子上测试这玩意,必须现在应用或手机设置中关闭硬件加速,在应用中我们可以通过在AndroidManifest.xml文件中设置application节点下的android:hardwareAccelerated属性为false来关闭硬件加速:-- 现在不用了,就不研究了。
3.PixelXorXfermode--与AvoidXfermode一样也在API 16过时了,不研究。
4.PorterDuffXfermode,该类同样有且只有一个含参的构造方法PorterDuffXfermode(PorterDuff.Mode mode),这个PorterDuff.Mode大家看后是否会有些面熟,它跟上面我们讲ColorFilter时候用到的PorterDuff.Mode是一样的!麻雀虽小五脏俱全,虽说构造方法的签名列表里只有一个PorterDuff.Mode的参数,但是它可以实现很多酷毙的图形效果!!而PorterDuffXfermode就是图形混合模式的意思。对于PorterDuff.Mode mode在API中Android为我们提供了18种。
四、深入说明 -- 字体测量类 FontMetrics
1.而它里面呢就定义了top,ascent,descent,bottom,leading五个成员变量其他什么也没有:
这五个成员变量除了top和bottom我们较熟悉外其余三个都很陌生是做什么用的呢?首先我给大家看张图:
就是说我们FontMetrics的这些值跟我们要绘制什么文本是无关的,而仅与绘制文本Paint的size和typeface有关我们来分别更改这两个值看看:mPaint.setTextSize(70);
如图所示所有值都改变了,我们再为Paint设置一个typeface:mPaint.setTypeface(Typeface.SERIF);
如果我现在字体居中,单纯是canvas.getWidth() /2和canvas.getHeight() /2 是不够准确的,必须用到上面的五个参数减去相应的距离:
实际情况中有很多不同的需求不如靠近某个区域离某个区域需要多少距离等等,熟练地去学会计算文本测绘中的各个值就显得很有必要了!
五、深入说明 -- 文字画笔TextPaint
2. Paint有一个唯一的子类TextPaint就是专门为文本绘制量身定做的“笔”,而这支笔就如API所描述的那样能够在绘制时为文本添加一些额外的信息,这些信息包括:baselineShift,bgColor,density,drawableState,linkColor等等。
换行绘制?使用StaticLayout结合TextPaint实现换行,StaticLayout是android.text.Layout的一个子类,很明显它也是为文本处理量身定做的,其内部实现了文本绘制换行的处理。
六、深入说明 -- 模糊遮罩滤镜类MaskFilter
1.setMaskFilter(MaskFilter maskfilter)
MaskFilter类中没有任何实现方法,而它有两个子类BlurMaskFilter和EmbossMaskFilter,前者为模糊遮罩滤镜(比起称之为过滤器哥更喜欢称之为滤镜)而后者为浮雕遮罩滤镜,我们先来看第一个:BlurMaskFilter-- 已经过时, 如果你想在Android系统Api大于15(Android系统4.0)以上的,不支持应用硬件加速,必须关闭硬件加速,在清单文件的Application节点下面直接添加android:hardwareAccelerated为false来关闭的,或者直接view的初始化画笔的方法里面:setLayerType(LAYER_TYPE_SOFTWARE, null)。
2.EmbossMaskFilter -- 他可以实现一种类似浮雕的效果,说白了就是让你绘制的图像感觉像是从屏幕中“凸”起来更有立体感一样(在设计软件中类似的效果称之为斜面浮雕),比较少用。
七、深入说明 -- 路径效果类PathEffect
1.setPathEffect(PathEffect effect),PathEffect见文知意很明显就是路径效果的意思~~那这玩意肯定跟路径Path有关咯?那是必须的撒!PathEffect跟上面的很多类一样没有具体的实现,但是其有六个子类,这六个子类分别可以实现不同的路径效果:
2.CornerPathEffect,当我们不设置路径效果的时候路径的默认效果就如上图第一条线那样直的转折生硬;而CornerPathEffect则可以将路径的转角变得圆滑如图第二条线的效果,这六种路径效果类都有且只有一个含参的构造方法,CornerPathEffect的构造方法只接受一个参数radius,意思就是转角处的圆滑程度,我们尝试更改一下上面的代码:mEffects[1] =newCornerPathEffect(50);
3.DiscretePathEffect离散路径效果相对来说则稍微复杂点,其会在路径上绘制很多“杂点”的突出来模拟一种类似生锈铁丝的效果如上图第三条线,其构造方法有两个参数,第一个呢指定这些突出的“杂点”的密度,值越小杂点越密集,第二个参数呢则是“杂点”突出的大小,值越大突出的距离越大反之反之;
4.DashPathEffect的效果相对与上面两种路径效果来说要略显复杂,其虽说也是包含了两个参数,但是第一个参数是一个浮点型的数组,那这个数组有什么意义呢?其实是这样的,我们在定义该参数的时候只要浮点型数组中元素个数大于等于2即可,也就是说上面我们的代码可以写成这样的:mEffects[3] =newDashPathEffect(newfloat[] {20,10}, mPhase); 从图中我们可以看到我们之前的那种线条变成了一长一短的间隔线条,而float[] {20, 10}的偶数参数20(注意数组下标是从0开始哦)定义了我们第一条实线的长度,而奇数参数10则表示第一条虚线的长度,如果此时数组后面不再有数据则重复第一个数以此往复循环,比如我们20,10后没数了,那么整条线就成了[20,10,20,10,20,10…………………………]这么一个状态,而DashPathEffect的第二个参数我称之为偏移值,动态改变其值会让路径产生动画的效果;
5.PathDashPathEffect和DashPathEffect是类似的,不同的是PathDashPathEffect可以让我们自己定义路径虚线的样式,比如我们将其换成一个个小圆组成的虚线。
6.ComposePathEffect和SumPathEffect都可以用来组合两种路径效果,唯一不同的是组合的方式,ComposePathEffect(PathEffect outerpe, PathEffect innerpe)会先将路径变成innerpe的效果,再去复合outerpe的路径效果,即:outerpe(innerpe(Path));而SumPathEffect(PathEffect first, PathEffect second)则会把两种路径效果加起来再作用于路径。
八、深入说明 -- 着色器Shader
1.setShader(Shader shader),这五个Shader里最异类的是BitmapShader,因为只有它是允许我们载入一张图片来给图像着色,那我们还是先来看看这个怪胎吧。构造方法BitmapShader (Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY);重点讲解第二个参数,CLAMP--边缘拉伸; MIRROR -- 镜像;REPEAT -- 重复;
2.LinearGradient -- 线性渐变,顾名思义这锤子玩意就是来画渐变的,实际上Shader的五个子类中除了上面我们说的那个怪胎,还有个变形金刚ComposeShader外其余三个都是渐变只是效果不同而已。两个构造方法:LinearGradient(floatx0,floaty0,floatx1,floaty1,intcolor0,intcolor1, Shader.TileMode tile),这是LinearGradient最简单的一个构造方法,参数虽多其实很好理解x0和y0表示渐变的起点坐标而x1和y1则表示渐变的终点坐标,这两点都是相对于屏幕坐标系而言的,而color0和color1则表示起点的颜色和终点的颜色;仅仅两种颜色的渐变根本无法满足我们身体的欲望,太单调乏味!我们是不是可以定义多种颜色渐变呢?答案是必须的,LinearGradient的另一个构造方法LinearGradient(floatx0,floaty0,floatx1,floaty1,int[] colors,float[] positions, Shader.TileMode tile)。
3.SweepGradient---的意思是梯度渐变,也称之为扫描式渐变,因为其效果有点类似雷达的扫描效果,他也有两个构造方法:SweepGradient(floatcx,floatcy,intcolor0,intcolor1);和mPaint.setShader(newSweepGradient(screenX, screenY,newint[] { Color.GREEN, Color.WHITE, Color.GREEN },null))。
4.RadialGradient -- 径向渐变,径向渐变说的简单点就是个圆形中心向四周渐变的效果,他也一样有两个构造方法;
5.ComposeShader -- 就是组合Shader的意思,顾名思义就是两个Shader组合在一起作为一个新Shader,两个构造方法:ComposeShader (Shader shaderA, Shader shaderB, Xfermode mode);ComposeShader (Shader shaderA, Shader shaderB, PorterDuff.Mode mode);