【Android】Paint的效果研究
原文:http://wpf814533631.iteye.com/blog/1847661
在Paint中有很多的属性可以设置,比如可以设置阴影,颜色过滤等等,这些会产生不同的奇妙效果,今天就对各种属性探索一下。
方法一:
1 //设置绘制的颜色,a代表透明度,r,g,b代表颜色值。 2 setARGB(int a,int r,int g,int b);
这个不多说了,还有两个类似的方法,将设置alpha和rgb分割开来了。注意的是这里的a值是0~255的范围,不是小数。
方法二:
//设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。 setAntiAlias(boolean aa);
也不多说,你可以试验一下效果,设置后会平滑一些;
方法三:
1 //设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰 2 setDither(boolean dither);
方法四:
1 //设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等 2 setMaskFilter(MaskFilter maskfilter);
MaskFilter类可以为Paint分配边缘效果。
对MaskFilter的扩展可以对一个Paint边缘的alpha通道应用转换。Android包含了下面几种MaskFilter:
BlurMaskFilter 指定了一个模糊的样式和半径来处理Paint的边缘。
EmbossMaskFilter 指定了光源的方向和环境光强度来添加浮雕效果。
要应用一个MaskFilter,可以使用setMaskFilter方法,并传递给它一个MaskFilter对象。下面的例子是对一个已经存在的Paint应用一个EmbossMaskFilter:
1 // 设置光源的方向 2 float[] direction = new float[]{ 1, 1, 1 }; 3 4 //设置环境光亮度 5 float light = 0.4f; 6 7 // 选择要应用的反射等级 8 float specular = 6; 9 10 // 向mask应用一定级别的模糊 11 float blur = 3.5f; 12 13 EmbossMaskFilter emboss=new EmbossMaskFilter(direction,light,specular,blur); 14 15 // 应用mask 16 myPaint.setMaskFilter(emboss);
可以看一下下面的图,是不是有浮雕的效果??
再看下面使用BlurMaskFilter:
1 //前面一个控制阴影的宽度,后面一个参数控制阴影效果 2 maskFilter = new BlurMaskFilter(10, BlurMaskFilter.Blur.SOLID);
是不是有阴影效果呢??
方法五:
1 //设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果 2 setColorFilter(ColorFilter colorfilter);
这个方法也值得试验一下:
MaskFilter是对一个Paint的alpha通道的转换,而ColorFilter则是对每一个RGB通道应用转换。所有由ColorFilter所派生的类在执行它们的转换时,都会忽略alpha通道。
这个貌似比较麻烦,改天再说。
方法六:
1 //设置绘制路径的效果,如点画线等 2 setPathEffect(PathEffect effect);
又是一个很好玩的方法:
到目前为止,所有的效应都会影响到Paint填充图像的方式;PathEffect是用来控制绘制轮廓(线条)的方式。PathEffect对于绘制Path基本图形特别有用,但是它们也可以应用到任何Paint中从而影响线条绘制的方式。
使用PathEffect,可以改变一个形状的边角的外观并且控制轮廓的外表。Android包含了多个PathEffect,包括:
1)CornerPathEffect 可以使用圆角来代替尖锐的角从而对基本图形的形状尖锐的边角进行平滑。
2)DashPathEffect 可以使用DashPathEffect来创建一个虚线的轮廓(短横线/小圆点),而不是使用实线。你还可以指定任意的虚/实线段的重复模式。
3) DiscretePathEffect 与DashPathEffect相似,但是添加了随机性。当绘制它的时候,需要指定每一段的长度和与原始路径的偏离度。
4)PathDashPathEffect 这种效果可以定义一个新的形状(路径)并将其用作原始路径的轮廓标记。
下面的效果可以在一个Paint中组合使用多个Path Effect。
1)SumPathEffect 顺序地在一条路径中添加两种效果,这样每一种效果都可以应用到原始路径中,而且两种结果可以结合起来。
2)ComposePathEffect 将两种效果组合起来应用,先使用第一种效果,然后在这种效果的基础上应用第二种效果。
对象形状的PathEffect的改变会影响到形状的区域。这就能够保证应用到相同形状的填充效果将会绘制到新的边界中。
使用setPathEffect方法可以把PathEffect应用到Paint对象中,如下所示:
1 paint.setPathEffect(new CornerPathEffect(10));
其他效果懒得测试了,这个在模拟器上跑的时候效果也不明显,但是真机上跑的时候的确圆滑了许多,看上去很舒服
方法七:
1 //设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果 2 setXfermode(Xfermode xfermode);
橡皮擦,这是个好方法啊,看看。
可以通过修改Paint的Xfermode来影响在Canvas已有的图像上面绘制新的颜色的方式。
在正常的情况下,在已有的图像上绘图将会在其上面添加一层新的形状。如果新的Paint是完全不透明的,那么它将完全遮挡住下面的Paint;如果它是部分透明的,那么它将会被染上下面的颜色。下面的Xfermode子类可以改变这种行为:
1)AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。
2)PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素XOR操作。
3)PorterDuffXfermode 这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。
要应用转换模式,可以使用setXferMode方法,如下所示:
1 AvoidXfermode avoid = new AvoidXfermode(Color.BLUE, 10, AvoidXfermode.Mode. AVOID); 2 borderPen.setXfermode(avoid);
这里可以实现完美的橡皮擦功能!代码异常简单:
1 Xfermode xFermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR); 2 paint.setXfermode(xFermode);
这是使用的最后一个子类,关于16条Porter-Duff规则,如下:
1 private static final Xfermode[] sModes = { 2 new PorterDuffXfermode(PorterDuff.Mode.CLEAR), 3 new PorterDuffXfermode(PorterDuff.Mode.SRC), 4 new PorterDuffXfermode(PorterDuff.Mode.DST), 5 new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER), 6 new PorterDuffXfermode(PorterDuff.Mode.DST_OVER), 7 new PorterDuffXfermode(PorterDuff.Mode.SRC_IN), 8 new PorterDuffXfermode(PorterDuff.Mode.DST_IN), 9 new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT), 10 new PorterDuffXfermode(PorterDuff.Mode.DST_OUT), 11 new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP), 12 new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP), 13 new PorterDuffXfermode(PorterDuff.Mode.XOR), 14 new PorterDuffXfermode(PorterDuff.Mode.DARKEN), 15 new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN), 16 new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY), 17 new PorterDuffXfermode(PorterDuff.Mode.SCREEN) 18 };
它们每个显示的效果具体如下:
第一个就是Clear效果!
上面很多的图都是由SDK APIDemos运行所得~~有时间仔细研究一下Graphics中的每个Activity。
- /**
- * Paint类介绍
- *
- * Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色,
- * 样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,
- * 大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。
- *
- * 1.图形绘制
- * setARGB(int a,int r,int g,int b);
- * 设置绘制的颜色,a代表透明度,r,g,b代表颜色值。
- *
- * setAlpha(int a);
- * 设置绘制图形的透明度。
- *
- * setColor(int color);
- * 设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。
- *
- * setAntiAlias(boolean aa);
- * 设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
- *
- * setDither(boolean dither);
- * 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
- *
- * setFilterBitmap(boolean filter);
- * 如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示
- * 速度,本设置项依赖于dither和xfermode的设置
- *
- * setMaskFilter(MaskFilter maskfilter);
- * 设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等 *
- * setColorFilter(ColorFilter colorfilter);
- * 设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果
- *
- * setPathEffect(PathEffect effect);
- * 设置绘制路径的效果,如点画线等
- *
- * setShader(Shader shader);
- * 设置图像效果,使用Shader可以绘制出各种渐变效果
- *
- * setShadowLayer(float radius ,float dx,float dy,int color);
- * 在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色
- *
- * setStyle(Paint.Style style);
- * 设置画笔的样式,为FILL,FILL_OR_STROKE,或STROKE
- *
- * setStrokeCap(Paint.Cap cap);
- * 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式
- * Cap.ROUND,或方形样式Cap.SQUARE
- *
- * setSrokeJoin(Paint.Join join);
- * 设置绘制时各图形的结合方式,如平滑效果等
- *
- * setStrokeWidth(float width);
- * 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
- *
- * setXfermode(Xfermode xfermode);
- * 设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
- *
- * 2.文本绘制
- * setFakeBoldText(boolean fakeBoldText);
- * 模拟实现粗体文字,设置在小字体上效果会非常差
- *
- * setSubpixelText(boolean subpixelText);
- * 设置该项为true,将有助于文本在LCD屏幕上的显示效果
- *
- * setTextAlign(Paint.Align align);
- * 设置绘制文字的对齐方向
- *
- * setTextScaleX(float scaleX);
- * 设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果
- *
- * setTextSize(float textSize);
- * 设置绘制文字的字号大小
- *
- * setTextSkewX(float skewX);
- * 设置斜体文字,skewX为倾斜弧度
- *
- * setTypeface(Typeface typeface);
- * 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等
- *
- * setUnderlineText(boolean underlineText);
- * 设置带有下划线的文字效果
- *
- * setStrikeThruText(boolean strikeThruText);
- * 设置带有删除线的效果
- *
- */
- private class MyView2 extends View {
- public MyView2(Context context) {
- super(context);
- }
- @Override
- protected void onDraw(Canvas canvas)
- {
- super.onDraw(canvas);
- canvas.drawColor(Color.WHITE);
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setColor(Color.RED);
- paint.setStyle(Paint.Style.STROKE);//设置为空心
- paint.setStrokeWidth(3);
- canvas.drawCircle(40, 40, 30, paint);
- canvas.drawRect(10, 90, 70, 150, paint);
- canvas.drawRect(10, 170, 70, 200, paint);
- canvas.drawOval(new RectF(10, 220, 70, 250), paint);
- Path path = new Path();//三角形
- path.moveTo(10, 330);
- path.lineTo(70, 330);
- path.lineTo(40, 270);
- path.close();
- canvas.drawPath(path, paint);
- Path path1 = new Path();//梯形
- path1.moveTo(10, 410);//绘画基点
- path1.lineTo(70, 410);
- path1.lineTo(55, 350);
- path1.lineTo(25, 350);
- path1.close();//把开始的点和最后的点连接在一起,构成一个封闭图形
- /*
- * 最重要的就是movtTo和close,如果是Style.FILL的话,不设置close,也没有区别,可是如果是STROKE模式,
- * 如果不设置close,图形不封闭。
- *
- * 当然,你也可以不设置close,再添加一条线,效果一样。
- */
- canvas.drawPath(path1, paint);
- ///////////////////////////////////////第二列
- paint.setColor(Color.BLUE);
- paint.setStyle(Paint.Style.FILL);//设置实心
- canvas.drawCircle(120, 40, 30, paint);
- canvas.drawRect(90, 90, 150, 150, paint);
- canvas.drawRect(90, 170, 150, 200, paint);
- RectF re2 = new RectF(90, 220, 150, 250);
- canvas.drawOval(re2, paint);
- Path path2 = new Path();
- path2.moveTo(90, 330);
- path2.lineTo(150, 330);
- path2.lineTo(120, 270);
- path2.close();
- canvas.drawPath(path2, paint);
- Path path3 = new Path();
- path3.moveTo(90, 410);
- path3.lineTo(150, 410);
- path3.lineTo(135, 350);
- path3.lineTo(105, 350);
- path3.close();
- canvas.drawPath(path3, paint);
- ////////////////////////////////////////////////////第三列
- /*
- * LinearGradient shader = new LinearGradient(0, 0, endX, endY, new
- * int[]{startColor, midleColor, endColor},new float[]{0 , 0.5f,
- * 1.0f}, TileMode.MIRROR);
- * 参数一为渐变起初点坐标x位置,参数二为y轴位置,参数三和四分辨对应渐变终点
- * 其中参数new int[]{startColor, midleColor,endColor}是参与渐变效果的颜色集合,
- * 其中参数new float[]{0 , 0.5f, 1.0f}是定义每个颜色处于的渐变相对位置, 这个参数可以为null,如果为null表示所有的颜色按顺序均匀的分布
- */
- Shader mShader = new LinearGradient(0, 0, 100, 100,
- new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW },
- null, Shader.TileMode.REPEAT);
- // Shader.TileMode三种模式
- // REPEAT:沿着渐变方向循环重复
- // CLAMP:如果在预先定义的范围外画的话,就重复边界的颜色
- // MIRROR:与REPEAT一样都是循环重复,但这个会对称重复
- paint.setShader(mShader);// 用Shader中定义定义的颜色来话
- canvas.drawCircle(200, 40, 30, paint);
- canvas.drawRect(170, 90, 230, 150, paint);
- canvas.drawRect(170, 170, 230, 200, paint);
- RectF re3 = new RectF(170, 220, 230, 250);
- canvas.drawOval(re3, paint);
- Path path4 = new Path();
- path4.moveTo(170, 330);
- path4.lineTo(230, 330);
- path4.lineTo(200, 270);
- path4.close();
- canvas.drawPath(path4, paint);
- Path path5 = new Path();
- path5.moveTo(170, 410);
- path5.lineTo(230, 410);
- path5.lineTo(215, 350);
- path5.lineTo(185, 350);
- path5.close();
- canvas.drawPath(path5, paint);
- //////////////////////////////////第4列
- paint.setTextSize(24);
- canvas.drawText("圆形", 240, 50, paint);
- canvas.drawText("正方形", 240, 120, paint);
- canvas.drawText("长方形", 240, 190, paint);
- canvas.drawText("椭圆形", 240, 250, paint);
- canvas.drawText("三角形", 240, 320, paint);
- canvas.drawText("梯形", 240, 390, paint);
- }
- }