自定义View基础2

在上一篇博客中介绍了自定义View的几个常用类,在这一篇博客中接着介绍另外的一个常用类,Paint类:

Paint翻译为“画笔”,为绘图定义各种参数:颜色、线条样式、图案样式等。通常的绘图思路是先定义Paint对象,指定绘图参数,再通过Canvas对象进行图形绘制,绘图的结果因Paint的不同而不同。绘图的方法定义在Canvas类中,Paint类用于指定绘图的各种参数。

4.Paint类

Paint类用于定义绘图时的参数,主要包含颜色、文本、图形样式、位图模式、滤镜等几个方面。 通过控制这些参数,我们就可以控制Paint的样式,绘制不同风格的文本、图片等。

颜色是指绘图时使用的颜色,在 Android 中颜色可以指定透明度,使用 16 进制来表示颜色时,格式通常为#AARRGGBB,其中,AA 表示透明度、RR 表示红色、GG 表示绿色、BB 表示蓝色,Color类定义了颜色信息,内置了常用颜色的int型常量,比如Color.RED 红色,Color.BLUE 蓝色,同时在Color类中定义的一个静态方法parseColor(String colorString)将16进制装换为color类型,比如:

[java]  view plain  copy
  1. int color = Color.parseColor("#FF552E");//将16进制的FF552E转换成Android中直接使用的颜色值  
① 创建一个Paint对象

[java]  view plain  copy
  1. // 创建一个画笔  
  2. public Paint()  
  3. // 创建一个画笔,并指定一个flags  
  4. public Paint(int flags)    
  5. // 从已有的画笔对象创建一个画笔  
  6. public Paint(Paint paint)  
  7.   
  8. // 创建一个画笔  
  9. Paint paint = new Paint();  
  10. paint.setFlags(Paint.ANTI_ALIAS_FLAG);// 设置抗锯齿  
  11. // 下面这一行代码等价于上面两行代码  
  12. Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);  

② Paint类与颜色相关的方法

[java]  view plain  copy
  1. // 设置颜色  
  2. public native void setColor(int color);  
  3. // 设置透明度,a的范围取 0~255 之间的整数  
  4. public native   void setAlpha(int a);  
  5. // 指定透明度、 红、 绿、 蓝定义一种颜色  
  6. public void setARGB(int a,  int r,  int g,  int b)  
  7. // 获取透明度  
  8. public native int getAlpha();  
  9. // 获取颜色  
  10. public native void getColor(int color);  
③ Paint类与文本相关的方法

[java]  view plain  copy
  1. // 设置文本大小,单位是 px,这个和我们平时使用的字体单位sp不同,所以最好进行转换  
  2. public native void setTextSize(float textSize)  
  3. // 设置文本的对齐方式,可选值有Paint.Align.LEFT、Paint.Align.CENTER、Paint.Align.RIGHT等  
  4. public void setTextAlign(Paint.Align align)  
  5. // 设置文本的倾斜程度,skewx 取值于 -1~1 之间,正负表示倾斜的方向  
  6. public native void setTextSkewX(float skewx)  
  7. // 给文本添加下载线,underline 为 true 表示添加  
  8. public native void setUnderlineText(boolean underline)  
  9. // 设置文本的粗体样式,bold 为 true 表示粗体  
  10. public native void setFakeBoldText(boolean bold)  
  11. // 为文本添加删除线,strike 为 true 时表示添加  
  12. public native void setStrikeThruText(boolean strike)  
④ Paint类与图形样式相关的方法

[java]  view plain  copy
  1. // 设置绘制的图形是空心样式还是实心样式,默认为实心样式  
  2. public void setStyle(Paint.Style style)  
  3. style的可选值有:  
  4. public static enum Style {  
  5. FILL  
  6. FILL_AND_STROKE,  
  7. STROKE   
  8. }  
其中,FILL 表示实心样式,对于闭合图形来说,会用指定的颜色进行填充;STROKE表示空心样式,绘制时只有线条而无填充效果;FILL_AND_STROKE 表示同时使用实心样式和空心样式。

[java]  view plain  copy
  1. // 当绘图样式为STROKE时,该方法用于指定线条连接处的拐角样式,能使绘制的图形更加平滑  
  2. public void setStrokeJoin(Paint.Join join)  
  3. 可选值如下:  
  4. public static enum Join {  
  5. BEVEL,  
  6. MITER,  
  7. ROUND  
  8. }  
Join三种类型区别可以用下图表示:

[java]  view plain  copy
  1. // 该方法用于设置落笔时的样式,控制我们的画笔在离开画板时留下的最后一点图形,默认BUTT  
  2. public void setStrokeCap(Paint.Cap cap)  
  3. 可选值如下:  
  4. public static enum Cap {  
  5. BUTT,  
  6. ROUND,  
  7. SQUARE  
  8. }  
Cap三种类型区别可以用下图表示:

[java]  view plain  copy
  1. // 设置画笔粗细,参数为float类型,可以小于1  
  2. public native void setStrokeWidth(float width)  
  3. // 重置画笔  
  4. public void reset()  
下面的代码是在canvas上面绘制一段文字和两个不同样式的矩形:

[java]  view plain  copy
  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     paint.setFlags(Paint.ANTI_ALIAS_FLAG);// 设置画笔去锯齿  
  4.     paint.setColor(Color.parseColor("#FF0000")); // 设置画笔颜色  
  5.     paint.setTextSize(50);// 设置字体大小  
  6.     paint.setTextSkewX(0.2f);// 设置字体倾斜  
  7.     paint.setFakeBoldText(true); // 设置字体加粗  
  8.     paint.setUnderlineText(true);// 设置给文字添加下划线  
  9.     canvas.drawText("Android自定义控件"100100, paint);// 绘制文字  
  10.   
  11.     paint.reset(); // 重置画笔  
  12.     paint.setFlags(Paint.ANTI_ALIAS_FLAG);// 设置画笔去锯齿  
  13.     paint.setColor(Color.parseColor("#0000FF")); // 设置画笔颜色  
  14.     paint.setStyle(Paint.Style.STROKE);// 设置内容不填充  
  15.     paint.setStrokeWidth(30);// 设置边框宽度  
  16.     paint.setStrokeJoin(Paint.Join.ROUND); // 设置Join  
  17.     // paint.setStrokeCap(Paint.Cap.ROUND);// 设置Cap  
  18.     canvas.drawRect(100150400350, paint);// 绘制一个矩形  
  19.   
  20.     paint.reset(); // 重置画笔  
  21.     paint.setFlags(Paint.ANTI_ALIAS_FLAG);// 设置画笔去锯齿  
  22.     paint.setColor(Color.parseColor("#00FF00")); // 设置画笔颜色  
  23.     paint.setStyle(Paint.Style.FILL);// 设置内容填充  
  24.     // paint.setStrokeCap(Paint.Cap.BUTT);// 设置Cap,样式为STROKE时才有效  
  25.     canvas.drawRect(450,150,850,350,paint);// 绘制一个矩形  
  26. }  
结果如图:


⑤ Paint类高级使用之阴影、渐变和位图

首先说明:在绘图中,有一个叫layer(层)的概念,默认情况下,我们的文字和图形绘制在主层(mainlayer)上,其实也可以将内容绘制在新建的layer上。而上阴影就是在main layer的下面添加了一个阴影层(shaderlayer),可以为阴影指定模糊度、偏移量和阴影颜色。

阴影:

[java]  view plain  copy
  1. Paint类的setShadowLayer()方法,可以设置阴影效果:  
  2. public void setShadowLayer(float radius, float dx, float dy, int shadowColor)  
  3. radius:阴影半径  
  4. dx:x方向阴影的偏移量  
  5. dy:y方向阴影的偏移量  
  6. shadowColor:阴影的颜色  
阴影layer显示阴影时, shader layer有两种类:View.LAYER_TYPE_SOFTWARE、View.LAYER_TYPE_HARDWARE

layer的默认类型为LAYER_TYPE_HARDWARE,但阴影只能在View.LAYER_TYPE_SOFTWARE环境下工作,所以,我们如果需要显示阴影想过,就要调用View类的public void setLayerType(int layerType, Paint paint)方法为Paint对象指定层的类型:
setLayerType(View.LAYER_TYPE_SOFTWARE, paint);

我在一个View的onDraw()方法中编写了一下代码:

[java]  view plain  copy
  1. @Override  
  2.     protected void onDraw(Canvas canvas) {  
  3.         // 初始化画笔基本属性  
  4.         Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  5.         paint.setColor(Color.parseColor("#f0f5f9"));  
  6.         paint.setStyle(Paint.Style.FILL);  
  7.         paint.setStrokeWidth(5);  
  8.         paint.setTextSize(100);  
  9.   
  10.         this.setLayerType(LAYER_TYPE_SOFTWARE, paint);// 设置图层类型  
  11.         paint.setShadowLayer(1055, Color.RED);   
  12.         canvas.drawText("Android"50200, paint);  
  13.         paint.setShadowLayer(5,3,3,Color.GREEN);     
  14.         canvas.drawText("自定义组件",50,320,paint);   
  15.   
  16.     }  
运行的到的结果如图所示:

需要注意的是,一旦定义了阴影层,接下来的所有绘制都会带阴影效果了,如果想取消阴影,请将setShadowLayer()方法的radius参数设置为0

渐变:

渐变(Gradient)是绘图过程中颜色或位图以特定规律进行变化,能增强物体的质感和审美情趣。生活中的渐变非常多,例如公路两边的电线杆、树木、建筑物的阳台、铁轨的枕木延伸到远方等等,很多的自然理象都充满了渐变的形式特点。Android同样对渐变进行了完善支持,通过渐变,可以绘制出更加逼真的效果。
Graphics2D渐变种类有:
线性渐变:LinearGradient
径向渐变:RadialGradient
扫描渐变:SweepGradient
位图渐变:BitmapShader
混合渐变:ComposeShader

定义渐变时,必须指定一个渐变区域,根据定义的渐变内容和渐变模式填满该区域。每一种渐变都被定义成了一个类,他们都继承自同一个父类——Shader。绘图时,调用Paint类的setShader(Shader shader)方法指定一种渐变类型,绘制出来的绘图填充区域都将使用指定的渐变颜色或位图进行填充。

线性渐变、径向渐变和扫描渐变属于颜色渐变,指定2种或2种以上的颜色,根据颜色过渡算法自动计算出中间的过渡颜色,从而形成渐变效果,对于开发人员来说,无需关注中间的渐变颜色。


同时,这三种渐变有三种渐变模式可以选择(A、B表示两种颜色):
ABAB型:A、B两种颜色重复变化,通过TileMode类的REPEAT常量来表示;
ABBA型:A、B两种颜色镜像变化,通过TileMode类的MIRROR常量来表示;
AABB型:A、B两种颜色只出现一次,通过TileMode类的CLAMP常量来表示。


线性渐变:

线性渐变(LinearGradient)根据指定的角度、颜色和模式使用渐变颜色填充绘图区域。我们必须定义两个点(x0,y0)和(x1,y1),渐变的方向与这两个点的连线垂直。

LinearGradient的构造方法如下:

[java]  view plain  copy
  1. publicLinearGradient(floatx0,floaty0,floatx1,floaty1,intcolor0,intcolor1,TileModetile):本方法用于两种颜色的渐变,各参数意义如下:  
  2. x0、y0:用于决定线性方向的第一个点的坐标(x0,y0);  
  3. x1、y1:用于决定线性方向的第二个点的坐标(x1,y1);  
  4. color0:第一种颜色;  
  5. color1:第二种颜色;  
  6. tile:渐变模式  
  7.   
  8. publicLinearGradient(floatx0,floaty0,floatx1,floaty1,intcolors[],floatpositions[],TileMode tile),这是一个功能更加强大的构造方法,我们来看看该构造方法参数的作用:  
  9. x0、y0:起始点的坐标  
  10. x1、y1:终止点的坐标  
  11. colors:多种颜色  
  12. positions:颜色的位置(比例)  
  13. TileMode:渐变模式  
以下代码都是以Shader.TileMode.CLAMP模式,并且都是2种渐变颜色,只是改变了渐变矩形的大小,能得到不同的效果
[java]  view plain  copy
  1. private void linerGradientTest(Canvas canvas) {  
  2.         canvas.save();//保存画布  
  3.         Rect rect = new Rect(5050200200); // 创建矩形  
  4.         // 以Shader.TileMode.CLAMP模式创建线性渐变  
  5.         LinearGradient lg = new LinearGradient(rect.left, rect.top, rect.right, rect.bottom, Color.RED, Color.BLUE, Shader.TileMode.CLAMP);  
  6.         paint.setShader(lg);//设置渐变  
  7.         canvas.drawRect(rect, paint); // 画矩形  
  8.   
  9.         Rect rect1 = new Rect(rect);// 根据rect来创建一个新的矩形  
  10.         rect1.inset(7070);// 缩小渐变矩形  
  11.         canvas.translate(rect.width() + 200);// 将画布水平平移20像素  
  12.         LinearGradient lg1 = new LinearGradient(rect1.left, rect1.top, rect1.right, rect1.bottom, Color.RED, Color.BLUE, Shader.TileMode.CLAMP);  
  13.         paint.setShader(lg1);  
  14.         canvas.drawRect(rect, paint);  
  15.   
  16.         Rect rect2 = new Rect(rect); // 根据rect来创建一个新的矩形  
  17.         rect1.inset(-70, -70); // 放大渐变矩形  
  18.         canvas.translate(rect.width() + 200);  
  19.         LinearGradient lg2 = new LinearGradient(rect2.left, rect2.top, rect2.right, rect2.bottom, Color.RED, Color.BLUE, Shader.TileMode.CLAMP);  
  20.         paint.setShader(lg2);  
  21.         canvas.drawRect(rect, paint);  
  22.   
  23.         canvas.restore();// 还原画布  
  24.     }  

下面的代码分别使用了两种渐变颜色和三种渐变颜色:

[java]  view plain  copy
  1. private void linerGradient(Canvas canvas) {  
  2.     canvas.save();//保存画布  
  3.     Rect rect = new Rect(3030450450);  
  4.     // 使用2种渐变颜色  
  5.     LinearGradient lg = new LinearGradient(rect.left, rect.top + rect.height() / 2, rect.right, rect.top + rect.height() / 2, Color.RED, Color.BLUE, Shader.TileMode.CLAMP);  
  6.     paint.setShader(lg);  
  7.     canvas.drawRect(rect, paint);  
  8.   
  9.     canvas.translate(rect.width() + 200);  
  10.     // 使用3种渐变颜色  
  11.     LinearGradient lg1 = new LinearGradient(rect.left, rect.top + rect.height() / 2, rect.right, rect.top + rect.height() / 2new int[]{Color.RED, Color.BLUE,Color.YELLOW},new float[]{0.3f,0.6f,0.8f}, Shader.TileMode.CLAMP);  
  12.     paint.setShader(lg1);  
  13.     canvas.drawRect(rect, paint);  
  14.   
  15.     canvas.restore();// 还原画布  
  16. }  

径向渐变

径向渐变是以指定的点为中心,向四周以渐变颜色进行圆周扩散,和线性渐变一样,支持两种或多种颜色。
径向渐变的主要构造方法如下:

[java]  view plain  copy
  1. public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile),该构造方法支持两种颜色,下面是参数的作用:  
  2. x、y:中心点坐标  
  3. radius:渐变半径  
  4. color0:起始颜色  
  5. color1:结束颜色  
  6. TileMode:渐变模式  
  7. public RadialGradient(float x, float y, float radius,  int colors[], float positions[], TileMode tile),该构造方法支持3种或3种以上颜色的渐变,各参数的作用如下:  
  8. x、y:中心点坐标  
  9. radius:渐变半径  
  10. colors:多种颜色  
  11. positions:颜色的位置(比例)  
  12. TileMode:渐变模式  

以下代码定义了径向渐变:

[java]  view plain  copy
  1. private void radiaGradientTest(Canvas canvas) {  
  2.     canvas.save();  
  3.     // 2种颜色圆形渐变  
  4.     RadialGradient rg = new RadialGradient(200,200,180,Color.RED,Color.GREEN, Shader.TileMode.CLAMP);  
  5.     paint.setShader(rg);  
  6.     canvas.drawCircle(200200180, paint);  
  7.   
  8.     canvas.translate(420,0);  
  9.     // 2种颜色矩形渐变  
  10.     RadialGradient rg1 = new RadialGradient(200,200,180,Color.RED,Color.GREEN, Shader.TileMode.CLAMP);  
  11.     paint.setShader(rg1);  
  12.     canvas.drawRect(200380360, paint);  
  13.   
  14.     canvas.translate(-420450);  
  15.     // 3种颜色圆形渐变  
  16.     RadialGradient rg2 = new RadialGradient(200,200,220,new int[]{Color.RED, Color.GREEN,Color.YELLOW},new float[]{0.3f,0.6f,0.8f}, Shader.TileMode.CLAMP);  
  17.     paint.setShader(rg2);  
  18.     canvas.drawCircle(200200180, paint);  
  19.   
  20.     canvas.translate(420,0);  
  21.     // 3种颜色矩形渐变  
  22.     RadialGradient rg3 = new RadialGradient(200,200,220,new int[]{Color.RED, Color.GREEN,Color.YELLOW},new float[]{0.3f,0.6f,0.8f}, Shader.TileMode.CLAMP);  
  23.     paint.setShader(rg3);  
  24.     canvas.drawRect(20,0,380,360,paint);  
  25.     canvas.restore();  
  26. }  
运行结果如图:

扫描渐变

SweepGradient类似于军事题材电影中的雷达扫描效果,固定圆心,将半径假想为有形并旋转一周而绘制的渐变颜色。
SweepGradient定义了两个主要的构造方法:

[java]  view plain  copy
  1. publicSweepGradient(floatcx,floatcy,intcolor0,intcolor1)  
  2. 支持两种颜色的扫描渐变,参数的作用如下:  
  3. cx、cy:圆点坐标;  
  4. color0:起始颜色;  
  5. color1:结束颜色。  
  6. publicSweepGradient(floatcx,floatcy,intcolors[],floatpositions[])  
  7. 支持多种颜色的扫描渐变,参数的作用如下:  
  8. cx、cy:圆点坐标;  
  9. colors:多种颜色;  
  10. positions:颜色的位置(比例)  
以下代码定义了扫描渐变:

[java]  view plain  copy
  1. private void sweepGradientTest(Canvas canvas) {  
  2.     canvas.save();  
  3.     SweepGradient sg = new SweepGradient(300,300,new int[]{Color.GREEN,Color.YELLOW,Color.BLUE,Color.GREEN}, null);  
  4.     paint.setShader(sg);  
  5.     canvas.drawCircle(300300280, paint);  
  6.   
  7.     SweepGradient sg1 = new SweepGradient(300,300,new int[]{Color.GREEN,Color.YELLOW,Color.BLUE,Color.GREEN}, new float[]{0.2f,0.5f,0.8f,0.9f});  
  8.     paint.setShader(sg1);  
  9.     canvas.drawCircle(300300280, paint);  
  10.     canvas.restore();  
  11. }  
运行结果如图:


位图渐变

位图渐变其实就是在绘制的图形中将指定的位图作为背景,如果图形比位图小,则通过渐变模式进行平铺,TileMode.CLAMP模式不平铺,TileMode.REPEAT模式表示平铺,TileMode.MIRROR模式也表示平铺,但是交错的位图是彼此的镜像,方向相反。可以同时指定水平和垂直两个方向
的渐变模式。
BitmapShader只有一个构造方法:
public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY),参数如下:
bitmap:位图;
tileX:x方向的重复模式;
tileY:y方向的重复模式。

以下代码定义了一个水平和竖直方向都平铺的位图渐变:

[java]  view plain  copy
  1. private void bitmaGradientTest(Canvas canvas) {  
  2.     Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);  
  3.     BitmapShader bs = new BitmapShader(bmp,Shader.TileMode.REPEAT, Shader.TileMode.MIRROR);  
  4.     Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  5.     paint.setShader(bs);  
  6.     canvas.drawRect(new Rect(00,10001000), paint);  
  7. }  

运行结果如图:

混合渐变

混合渐变ComposeShader是将两种不同的渐变通过位图运算后得到的一种更加复杂的渐变。
ComposeShader有两个构造方法:

[java]  view plain  copy
  1. publicComposeShader(ShadershaderA,ShadershaderB,Xfermodemode)  
  2. publicComposeShader(ShadershaderA,ShadershaderB,Modemode)  
shaderA和shaderB是两个渐变对象,mode为位图运算类型,16种运算模式如图(图片来源网络):

以下代码定义了位图渐变和扫描渐变相结合:

[java]  view plain  copy
  1. private void composeGradientTest(Canvas canvas) {  
  2.     Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);  
  3.     BitmapShader bs = new BitmapShader(bmp,Shader.TileMode.REPEAT, Shader.TileMode.MIRROR);//定义位图渐变  
  4.     // 定义扫描渐变  
  5.     SweepGradient sg = new SweepGradient(500525new int[]{Color.GREEN, Color.YELLOW, Color.BLUE, Color.GREEN}, null);  
  6.     ComposeShader sc = new ComposeShader(bs,sg, PorterDuff.Mode.SRC_IN);  
  7.     Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  8.     paint.setShader(sc);  
  9.     canvas.drawRect(new Rect(00,10001000), paint);  
  10. }  
运行结果如下图:



位图运算PorterDuffXfermode

位图运算为位图的功能繁衍ᨀ供了强大的技术基础,增强了位图的可塑性和延伸性,使很多看起来非常复杂的效果和功能都能轻易实现,比如圆形头像、不规则图片、橡皮擦、稀奇古怪的自定义进度条等等。

位图运算模式定义在PorterDuff类的内部枚举类型Mode中,对应了16个不同的枚举值

[java]  view plain  copy
  1. publicenumMode{  
  2.     /**[0,0]*/  
  3.     CLEAR(0),  
  4.     /**[Sa,Sc]*/  
  5.     SRC(1),  
  6.     /**[Da,Dc]*/  
  7.     DST(2),  
  8.     /**[Sa+(1-Sa)*Da,Rc=Sc+(1-Sa)*Dc]*/  
  9.     SRC_OVER(3),  
  10.     /**[Sa+(1-Sa)*Da,Rc=Dc+(1-Da)*Sc]*/  
  11.     DST_OVER(4),  
  12.     /**[Sa*Da,Sc*Da]*/  
  13.     SRC_IN(5),  
  14.     /**[Sa*Da,Sa*Dc]*/  
  15.     DST_IN(6),  
  16.     /**[Sa*(1-Da),Sc*(1-Da)]*/  
  17.     SRC_OUT(7),  
  18.     /**[Da*(1-Sa),Dc*(1-Sa)]*/  
  19.     DST_OUT(8),  
  20.     /**[Da,Sc*Da+(1-Sa)*Dc]*/  
  21.     SRC_ATOP(9),  
  22.     /**[Sa,Sa*Dc+Sc*(1-Da)]*/  
  23.     DST_ATOP(10),  
  24.     /**[Sa+Da-2*Sa*Da,Sc*(1-Da)+(1-Sa)*Dc]*/  
  25.     XOR(11),  
  26.     /**[Sa+Da-Sa*Da, 
  27.         Sc*(1-Da)+Dc*(1-Sa)+min(Sc,Dc)]*/  
  28.     DARKEN(16),  
  29.     /**[Sa+Da-Sa*Da, 
  30.         Sc*(1-Da)+Dc*(1-Sa)+max(Sc,Dc)]*/  
  31.     LIGHTEN(17),  
  32.     /**[Sa*Da,Sc*Dc]*/  
  33.     MULTIPLY(13),  
  34.     /**[Sa+Da-Sa*Da,Sc+Dc-Sc*Dc]*/  
  35.     SCREEN(14),  
  36.     /**Saturate(S+D)*/  
  37.     ADD(12),  
  38.     OVERLAY(15);  
  39.   
  40.     Mode(intnativeInt){  
  41.         this.nativeInt=nativeInt;  
  42.     }  
  43.   
  44.     /** 
  45.     *@hide 
  46.     */  
  47.     publicfinalintnativeInt;  
  48. }  
具体使用哪一种模式才能达到效果,可以参考下图(图片来源网络):


以下代码通过位图运算简单实现了圆形图片的制作:

[java]  view plain  copy
  1. public class CircleImage extends View {  
  2.     private Paint paint;  
  3.     private Bitmap bitmap;  
  4.     private int width,height,centerX,centerY,radius;  
  5.   
  6.     public CircleImage(Context context) {  
  7.         this(context, null);  
  8.     }  
  9.   
  10.     public CircleImage(Context context, AttributeSet attrs) {  
  11.         this(context, attrs, 0);  
  12.     }  
  13.   
  14.     public CircleImage(Context context, AttributeSet attrs, int defStyleAttr) {  
  15.         super(context, attrs, defStyleAttr);  
  16.         init();  
  17.     }  
  18.   
  19.     private void init() {  
  20.         paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  21.   
  22.         bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.a); // 从资源文件中获取图片并变为Bitmap对象  
  23.         // 获取图片的宽和高,并计算圆心位置  
  24.         width = bitmap.getWidth();  
  25.         height = bitmap.getHeight();  
  26.         centerX = width / 2;  
  27.         centerY = height / 2;  
  28.         radius = Math.min(width,height) / 2;  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void onDraw(Canvas canvas) {  
  33.         super.onDraw(canvas);  
  34.         /** 
  35.          * Canvas类中的saveLayer()方法,表示出创建一个图层入栈并返回该图层所在栈中的位置, 
  36.          * 而restoreToCount()方法表示将指定栈中位置的图层绘制到canvas上面显示。 
  37.          */  
  38.         int saveLayer = canvas.saveLayer(00, width, height, paint, Canvas.ALL_SAVE_FLAG);  
  39.         // 画一个圆,也就是需要显示出来的圆  
  40.         canvas.drawCircle(centerX,centerY,radius,paint);  
  41.         //设置位图模式为PorterDuff.Mode.SRC_IN  
  42.         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));  
  43.         canvas.drawBitmap(bitmap, 00, paint);  
  44.         // 清空位图模式  
  45.         paint.setXfermode(null);  
  46.         // 给圆形图片画一个3像素的边框  
  47.         paint.setStrokeWidth(3);  
  48.         paint.setStyle(Paint.Style.STROKE);  
  49.         paint.setColor(Color.parseColor("#65f692"));  
  50.         canvas.drawCircle(centerX,centerY,radius,paint);  
  51.   
  52.         canvas.restoreToCount(saveLayer);  
  53.     }  
  54. }  
运行结果如图所示:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值