paint_painter - CSDN
  • Paint的用法总结

    2019-02-28 12:52:05
    Paint的用法总结 上一期在总结canvas的用法时候谈到绘制需要的四个组件:一个保存像素的Bitmap,一个主持绘画操作的Canvas(往Bitmap写东西),一个绘制的基本元素(例如Rect,Path,Text,Btimap),一支画笔(用来...

    Paint的用法总结

    上一期在总结canvas的用法时候谈到绘制需要的四个组件:一个保存像素的Bitmap,一个主持绘画操作的Canvas(往Bitmap写东西),一个绘制的基本元素(例如Rect,Path,Text,Btimap),一支画笔(用来描述绘画的颜色与风格)。

    在上一期文章《关于Canvas的用法,这些都只是基操》里总结了canvas的一些用法,那么这次就来总结一下画笔Paint的一些用法。 还是一样的套路,先看看类描述:Paint是持有绘制几何图形、文字、位图等样式、颜色信息的类,那么总结下来可以大致描述,Paint是描述的绘制样式以及颜色信息的类。

    Paint关于颜色信息的描述

    canvas在绘制的时候颜色也不完全由paint决定,canvas在画颜色以及位图的时候,颜色画出来的跟paint的颜色不一致,因为canva在画颜色的时候,颜色信息是直接设置到参数里的,这个颜色由参数的色值来决定;在画bitmap的时候,bitmap中有相关的颜色信息,绘制出来的颜色由bitmap的颜色信息来决定;其余的绘制颜色就由paint来决定。

    Paint设置颜色

    Paint设置颜色有两个方法,setcolor以及setARGB跟canvas的绘制颜色一样,比较简单,另外paint还有一个setAlpha方法,这个是只设置alpha信息的

    Paint设置着色器

    Paint除了直接设置颜色,还可以通过setShader方法设置着色器,其实用过ps的都知道,着色器其实就是一种颜色填充方式,单一的颜色,也可以看做是纯色的着色器,如果设置了着色器,那么颜色填充方式就以着色器的颜色信息为准。使用着色器并不能直接使用Shader类,应该使用其子类:

    LinearGradient线性渐变

    /**
       *
       * @param x0       渐变线开始点的x坐标
       * @param y0       渐变线开始点的y坐标
       * @param x1       渐变线结束点的x坐标
       * @param y1       渐变线结束点的y坐标
       * @param color0   渐变线的起始颜色
       * @param color1   渐变线的结束颜色
       * @param tile     平铺的模式(需要填充的面积大于渐变的区间时的平铺模式)
    */
        val linearGradient = LinearGradient(0f, 0f, 200f, 200f, Color.RED, Color.BLUE, Shader.TileMode.MIRROR)
        mPaint.shader = linearGradient
        canvas?.drawText("kevinxieyeah", 5f, 200f, mPaint)
    复制代码

    还可以指定多个颜色的线性渐变

    /**
     *
     * @param x0          渐变线开始点的x坐标
     * @param y0          渐变线开始点的y坐标
     * @param x1          渐变线结束点的x坐标
     * @param y1          渐变线结束点的y坐标
     * @param colors      颜色的int数组
     * @param positions   位置的float数组
     * @param tile        平铺的模式(需要填充的面积大于渐变的区间时的平铺模式)
    */
    val linearGradient = LinearGradient(0f, 0f, 200f, 200f, intArrayOf(Color.RED, Color.BLUE, Color.GREEN), floatArrayOf(0f, 0.5f, 1f), Shader.TileMode.MIRROR)
    复制代码

    还有一个tile模式,我们指定三个值 MIRROR

    CLAMP
    REPEAT

    RadialGradient环形渐变

    /**
     *
     * @param centerX     渐变的中心点x坐标
     * @param centerY     渐变的中心点y坐标
     * @param radius      渐变的半径
     * @param centerColor 渐变的开始颜色
     * @param edgeColor   渐变的结束颜色
     * @param tileMode    填充模式
     */
    val radialGradient = RadialGradient(300f, 300f, 500f, Color.RED, Color.GREEN, Shader.TileMode.CLAMP)
    mPaint.shader = radialGradient
    canvas?.drawRect(Rect(0, 0, 1000, 1000), mPaint)
    复制代码

    环形渐变也可以指定多个颜色值,跟线性渐变类似,填充模式跟线性渐变也类似

    SweepGradient扫描渐变

    /**
     *
     * @param cx       渐变的中心点x坐标
     * @param cy       渐变的中心点y坐标
     * @param color0   渐变的开始颜色
     * @param color1   渐变的结束颜色
     */
    val sweepGradient = SweepGradient(300f, 300f, Color.RED, Color.GREEN)
    mPaint.shader = sweepGradient
    canvas?.drawRect(Rect(0, 0, 1000, 1000), mPaint)
    复制代码

    扫描渐变也可以指定多个颜色值,跟线性渐变类似,但是没有填充模式

    BitmapShader图片着色器

    /**
     * @param bitmap 要填充的bitmap
     * @param tileX x方向的填充模式
     * @param tileY y方向的填充模式
     */
    val bitmapShader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
    mPaint.shader = bitmapShader
    canvas?.drawRect(Rect(0, 0, 1000, 1000), mPaint)
    复制代码

    改变一下y方向的模式看看效果 REPEAT
    MIRROR

    ComposeShader组合着色器

    val bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.a)
    val bitmapShader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.MIRROR)
    val radialGradient = RadialGradient(300f, 300f, 500f, Color.RED, Color.GREEN, Shader.TileMode.CLAMP)
    /**
     * @param shaderA  目标着色器
     * @param shaderB  源着色器
     * @param mode     混合模式
    */
    val composeShader = ComposeShader(bitmapShader, radialGradient, PorterDuff.Mode.LIGHTEN)
    mPaint.shader = composeShader
    canvas?.drawRect(Rect(0, 0, 1000, 1000), mPaint)
    复制代码

    顾名思义,把着色器混合着用,后面可以传PorterDuff.Mode和XferMode,XferMode其实就是对PorterDuff.Mode的封装,所以还是需要了解每一种混合模式之间的区别。

    PorterDuff.Mode

    混合模式我们对照图来达到我们需要的效果就可以了

    Paint设置ColorFilter

    为绘制的内容提供颜色过滤,他有三个子类LightingColorFilter、PorterDuffColorFilter、ColorMatrixColorFilter,还是逐一使用看看效果先

    LightingColorFilter

    是不是有一种无法预测结果的感觉?其实颜色混合都有其对应的算法去处理颜色,网上看到扔物线大神这个对LightingColorFilter的解释,LightingColorFilter 的构造方法是 LightingColorFilter(int mul, int add) ,参数里的 mul 和 add 都是和颜色值格式相同的 int 值,其中 mul 用来和目标像素相乘,add 用来和目标像素相加

    R' = R * mul.R / 0xff + add.R
    G' = G * mul.G / 0xff + add.G
    B' = B * mul.B / 0xff + add.B
    复制代码

    PorterDuffColorFilter

    val bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.a)
    mPaint.colorFilter = PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DARKEN)
    canvas?.drawBitmap(bitmap, 50f, 50f, mPaint)
    复制代码

    PorterDuffColorFilter是使用一种特定的颜色对绘制的内容按照PorterDuff.Mode来进行处理

    ColorMatrixColorFilter

    还是借用扔物线大神的解释,ColorMatrixColorFilter 使用一个 ColorMatrix 来对颜色进行处理。 ColorMatrix 这个类,内部是一个 4x5 的矩阵

    [ a, b, c, d, e,
      f, g, h, i, j,
      k, l, m, n, o,
      p, q, r, s, t ]
    复制代码

    通过计算, ColorMatrix 可以把要绘制的像素进行转换。对于颜色 [R, G, B, A] ,转换算法是这样的:

    R’ = a*R + b*G + c*B + d*A + e;
    G’ = f*R + g*G + h*B + i*A + j;
    B’ = k*R + l*G + m*B + n*A + o;
    A’ = p*R + q*G + r*B + s*A + t;
    复制代码

    Paint设置XferMode

    setXfermode其实就是将你绘制的内容作为源图像与canvas已经存在的内容目标图像按照设置的模式进行混合,其实默认的模式是SRC_OVER,也就是像我们常见的后画的内容覆盖先画的内容。

    val xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
    canvas?.drawRect(Rect(300, 300, 800, 800), mPaint)
    mPaint.xfermode = xfermode
    mPaint.color = Color.RED
    canvas?.drawCircle(300f, 300f, 100f, mPaint)
    mPaint.xfermode = null
    复制代码

    出现了奇怪的效果,绘制的圆变成了黑色,没有达到我们预期的裁剪效果,解决方法是将设置XferMode的绘制单独放在一个图层,通过saveLayer可以避免奇怪的效果

    Paint关于样式的描述

    Paint的flag配置

    我们在创建paint的时候可以传递一个flag值,这些值对应的设置如下:

    • Paint.ANTI_ALIAS_FLAG :抗锯齿标志
    • Paint.FILTER_BITMAP_FLAG : 使位图过滤的位掩码标志
    • Paint.DITHER_FLAG : 使位图进行有利的抖动的位掩码标志
    • Paint.UNDERLINE_TEXT_FLAG : 下划线
    • Paint.STRIKE_THRU_TEXT_FLAG : 中划线
    • Paint.FAKE_BOLD_TEXT_FLAG : 加粗
    • Paint.LINEAR_TEXT_FLAG : 使文本平滑线性扩展的油漆标志
    • Paint.SUBPIXEL_TEXT_FLAG : 使文本的亚像素定位的绘图标志
    • Paint.EMBEDDED_BITMAP_TEXT_FLAG : 绘制文本时允许使用位图字体的绘图标志

    我们可以通过设置flag来给paint设置这些配置,也可以用一些专门的帮助方法,比如:setAntiAlias、setDither、setLinearText、setSubpixelText、setUnderlineText、setStrikeThruText、setFakeBoldText、setFilterBitmap,这些方法都是对以上flag的帮助设置,用哪种方法都可以。

    Paint的style

    paint可以通过setStyle(Style style)方法来设置style,Style用三种模式,FILL(填充)、STROKE(描边)、FILL_AND_STROKE(填充以及描边)

    val path = Path()
    path.lineTo(0f, 300f)
    path.lineTo(500f, 300f)
    path.lineTo(600f, 0f)
    canvas?.drawPath(path, mPaint)
    复制代码

    从上面两张图对比就可以看出填充和描边的区别,但是记住填充并不是一定要闭合的区间,因为一旦paint的style是填充,那么他会默认将path按照闭合区间来填充

    Paint的描边设置

    我们可以通过setStrokeWidth来设置描边的宽度,用setStrokeCap来设置线条两头的形状

    mPaint.strokeCap = Paint.Cap.BUTT
    canvas?.drawLine(100f, 100f, 500f, 100f, mPaint)
    mPaint.strokeCap = Paint.Cap.ROUND
    canvas?.drawLine(100f, 200f, 500f, 200f, mPaint)
    mPaint.strokeCap = Paint.Cap.SQUARE
    canvas?.drawLine(100f, 300f, 500f, 300f, mPaint)
    复制代码

    还可以通过setStrokeJoin来设置线条相交处的处理

    BEVEL

    ROUND
    MITER

    setStrokeMiter是对于 setStrokeJoin() 的一个补充,它用于设置 MITER 型拐角的延长线的最大值,夹角太小时,就会造成尖角过长时,自动改用 BEVEL 的方式来渲染连接点

    setPathEffect(PathEffect effect)是用来设置描边的效果,看一下有哪些子类

    我们来分别设置看看效果

    • DashPathEffect(floatArrayOf(10f, 10f, 20f, 20f), 0f),第一个参数 intervals 是一个数组,它指定了虚线的格式:数组中元素必须为偶数(最少是 2 个),按照(画线长度、空白长度、画线长度、空白长度)的顺序排列,第二个参数 phase 是虚线的偏移量。

    • PathDashPathEffect(path, 10f, 0f, PathDashPathEffect.Style.ROTATE)是使用指定的Path来绘制描边。

    • CornerPathEffect(30f)就是对路径进行圆角

    • DiscretePathEffect(5f, 5f)是把绘制改为使用定长的线段来拼接,并且在拼接的时候对路径进行随机偏离。segmentLength 是用来拼接的每个线段的长度, deviation 是偏离量。

    • SumPathEffect(dashPathEffect, cornerPathEffect)把两个效果直接叠加在一起

    • ComposePathEffect(dashPathEffect, cornerPathEffect)把两个效果直进行组合成一个新的效果

    Paint的色彩优化

    Paint 的色彩优化有两个方法: setDither(boolean dither) 和 setFilterBitmap(boolean filter) 。它们的作用都是让画面颜色变得更加自然。

    setDither设置抖动,在图像降低色彩深度绘制时,避免出现大片的色带与色块

    setFilterBitmap设置双线性过滤,图像在放大绘制的时候,默认使用的是最近邻插值过滤,这种算法简单,但会出现马赛克现象;而如果开启了双线性过滤,就可以让结果图像显得更加平滑。

    Paint的设置阴影

    mPaint.setShadowLayer(30f, 0f, 0f, Color.RED)
    canvas?.drawText("kevinxie", 50f, 300f, mPaint)
    复制代码

    Paint的设置遮罩过滤

    遮罩其实就是在图像上面附加一层遮盖物,可以使用setMaskFilter(MaskFilter maskfilter)来进行设置,MaskFilter有EmbossMaskFilter、BlurMaskFilter两个子类,我们来使用一下看看效果

    • BlurMaskFilter模糊效果

      四种模糊的style

    • EmbossMaskFilter浮雕效果,相对于之前的BlurMaskFilter来说,EmbossMaskFilter的可用性比较低,因为它实现的效果不是很霸气。正如其名,他可以实现一种类似浮雕的效果,说白了就是让你绘制的图像感觉像是从屏幕中“凸”起来更有立体感一样。

    上述两种效果已经过时,在4.0以上要看到效果需要关闭硬件加速

    恩,差不多,就到这里了!!!

    展开全文
  • Paint 全面解析

    千次阅读 2017-06-22 14:15:12
    paint的方法分为两类:负责图形绘制、路径相关setStrokeWidth(float width)设置画笔宽度setStyle(Paint.Style style)设置画笔样式 Style有三类: Paint.Style.FILL :填充内部 Paint.Style.FILL_AND_STROKE :填充...

    paint的方法分为两类:

    负责图形绘制、路径相关

    setStrokeWidth(float width)设置画笔宽度

    setStyle(Paint.Style style)设置画笔样式

    • Style有三类:
      • Paint.Style.FILL :填充内部
      • Paint.Style.FILL_AND_STROKE :填充内部和描边
      • Paint.Style.STROKE :仅描边、
    • 注意STROKE、FILL_OR_STROKE与FILL模式下外轮廓的位置会扩大。

    例子:

        private void PaintStyle(Canvas canvas) {
            float Y = 70;
            float X = 70;
            float R = 50;
            float DX = 130;
            Paint paint = new Paint();
            paint.setColor(Color.RED);//设置颜色
            paint.setStyle(Paint.Style.FILL);//填充内部
            canvas.drawCircle(X, Y, R, paint);
    
            paint.setStyle(Paint.Style.STROKE);//描边
            canvas.drawCircle(X + DX, Y, R, paint);
    
            paint.setStyle(Paint.Style.FILL_AND_STROKE);//填充内部和描边
            canvas.drawCircle(X + DX * 2, Y, R, paint);
    
            paint.setAntiAlias(true);
            paint.setStyle(Paint.Style.STROKE);//描边
            canvas.drawCircle(X + DX * 3, Y, R, paint);
    
            paint.setStrokeWidth(20);//设置画笔宽度
            paint.setStyle(Paint.Style.STROKE);//填充内部和描边
            canvas.drawCircle(X + DX * 4, Y, R, paint);
        }

    运行结果:
    这里写图片描述

    setStrokeCap(Paint.Cap cap)设置线冒样式

    • Cap取值有
      • Cap.ROUND(圆形线冒)
      • Cap.SQUARE(方形线冒)
      • Paint.Cap.BUTT(无线冒)
    • 注:冒多出来的那块区域就是线帽!就相当于给原来的直线加上一个帽子一样,所以叫线帽

    例子:

        private void PaintCap(Canvas canvas) {
            float SX = 50;
            float SY = 200;
            float EX = 500;
            float EY = 200;
            float DY = 50;
            Paint paint_line = new Paint();
            paint_line.setColor(Color.RED);
            paint_line.setStrokeWidth(30);
    
            paint_line.setStrokeCap(Paint.Cap.ROUND);//圆形线帽
            canvas.drawLine(SX, SY, EX, EY, paint_line);
    
            paint_line.setStrokeCap(Paint.Cap.BUTT);//无线帽
            canvas.drawLine(SX, SY + DY, EX, EY + DY, paint_line);
    
            paint_line.setStrokeCap(Paint.Cap.SQUARE);//方形线帽
            canvas.drawLine(SX, SY + DY * 2, EX, EY + DY * 2, paint_line);
        }

    运行结果:
    这里写图片描述

    setStrokeJoin(Paint.Join join)设置线段连接处样式

    取值有:Join.MITER(结合处为锐角)、Join.Round(结合处为圆弧)、Join.BEVEL(结合处为直线)

    例子:

        private void drawStrokeJoin(Canvas canvas) {
            Paint paint_line = new Paint();
            paint_line.setColor(Color.RED);
            paint_line.setStyle(Paint.Style.STROKE);
            paint_line.setStrokeWidth(30);
            paint_line.setAntiAlias(true);
            float SX = 50;
            float SY = 400;
            float DY = 50;
    
            Path path = new Path();
            path.moveTo(SX , SY);
            path.lineTo(SX + DY, SY + DY);
            path.lineTo(SX + DY * 2, SY - DY);
            paint_line.setStrokeJoin(Paint.Join.MITER);//结合处为锐角
            canvas.drawPath(path, paint_line);
    
            path.reset();
            SX = SX + DY * 3;
            path.moveTo(SX , SY);
            path.lineTo(SX + DY, SY + DY);
            path.lineTo(SX + DY * 2, SY - DY);
            paint_line.setStrokeJoin(Paint.Join.ROUND);//结合处为圆弧
            canvas.drawPath(path, paint_line);
    
            path.reset();
            SX = SX + DY * 3;
            path.moveTo(SX , SY);
            path.lineTo(SX + DY, SY + DY);
            path.lineTo(SX + DY * 2, SY - DY);
            paint_line.setStrokeJoin(Paint.Join.BEVEL);//结合处为直线
            canvas.drawPath(path, paint_line);
    
        }

    运行结果:
    这里写图片描述

    set(Paint paint)方法设置一个外部画笔

    例子:

        private void paintSet(Canvas canvas) {
            Paint paintA = new Paint();
            paintA.setColor(Color.BLUE);
            Paint paintB = new Paint();
            paintB.setStrokeWidth(20);
            paintB.setColor(Color.GREEN);
            paintB.setARGB(200, 100, 200, 150);
            paintA.set(paintB);
            float alpha = paintA.getAlpha();
            float color = paintA.getColor();
            canvas.drawLine(100, 600, 200, 700, paintA);
            paintA.setColor(Color.BLUE);
            paintA.setAntiAlias(true);//获取与设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢,一般会开启。设置后会平滑一些;
            paintA.setTextSize(30);
            canvas.drawText("alpha:" + alpha + "  color:" + color, 200, 700, paintA);
        }

    运行结果:
    这里写图片描述

    setPathEffect(PathEffect effect)设置绘制路径的效果

    继承关系:
    这里写图片描述

    CornerPathEffect——圆形拐角效果

    paint.setPathEffect(new CornerPathEffect(100));
    利用半径R=50的圆来代替原来两条直线间的夹角

    DashPathEffect——虚线效果

    比如,我们定义new float[] {20,10};那这个虚线段就是由两段线段组成的,第一个可见的线段长为20,每二个线段不可见,长度为10
    • phase:开始绘制的偏移值
     比如:画同一条线段,偏移值为15
     paint.setPathEffect(new DashPathEffect(new float[]{20,10,50,100},15));

    PathDashPathEffect

    利用以另一个路径为单位,延着路径盖章.相当于PS的印章工具
    Style有三种:
    TRANSLATE
    ROTATE
    MORPH

    SumPathEffect

    • SumPathEffect(PathEffect first, PathEffect second)
      • first特效和second特效分别对原始路径进行影响,最终对两种特效的结果进行合并

    ComposePathEffect

    • ComposePathEffect(PathEffect outerpe, PathEffect innerpe)
      • 先应用innerpe特效,然后在此基础上,应用outerpe特效,两个特效的顺序执行。

    DiscretePathEffect

    • public DiscretePathEffect(float segmentLength, float deviation)
      • 把原有的路线,在指定的间距处插入一个突刺
      • 第一个这些突出的“杂点”的间距,值越小间距越短,越密集
      • 第二个是突出距离
    例子PathDashPathEffect:
        private Path getPath(){
            Path path = new Path();
            // 定义路径的起点
            path.moveTo(0, 0);
    
            // 定义路径的各个点
            for (int i = 0; i <= 40; i++) {
                path.lineTo(i*35, (float) (Math.random() * 150));
            }
            return path;
        }
    
        private Paint getPaint(){
            Paint paint = new Paint();
            paint.setStrokeWidth(4);
            paint.setColor(Color.GREEN);
            paint.setStyle(Paint.Style.STROKE);
            paint.setAntiAlias(true);
            return paint;
        }
        private void drawPathDashPathEffect(Canvas canvas){
            Paint paint = getPaint();
    
            Path path  = new Path();
            path.moveTo(100,600);
            path.lineTo(400,150);
            path.lineTo(700,900);
            canvas.drawPath(path,paint);
            canvas.drawPath(path,paint);
    
            canvas.translate(0,200);
    
            /**
             * 利用以另一个路径为单位,延着路径盖章.相当于PS的印章工具
             */
            paint.setPathEffect(new PathDashPathEffect(getStampPath(),35,0, PathDashPathEffect.Style.MORPH));
            canvas.drawPath(path,paint);
        }
    private Path getStampPath(){
            Path path  = new Path();
            path.moveTo(0,20);
            path.lineTo(10,0);
            path.lineTo(20,20);
            path.close();
    
            path.addCircle(0,0,3, Path.Direction.CCW);
    
            return path;
        }

    这里写图片描述

        private void drawPathDashPathEffectDemo(Canvas canvas){
            Paint paint = getPaint();
    
            Path path = getPath();
            canvas.drawPath(path,paint);
    
            canvas.translate(0,200);
    
            paint.setPathEffect(new PathDashPathEffect(getStampPath(),35,0, PathDashPathEffect.Style.MORPH));
            canvas.drawPath(path,paint);
    
            canvas.translate(0,200);
            paint.setPathEffect(new PathDashPathEffect(getStampPath(),35,0, PathDashPathEffect.Style.ROTATE));
            canvas.drawPath(path,paint);
    
            canvas.translate(0,200);
            paint.setPathEffect(new PathDashPathEffect(getStampPath(),35,0, PathDashPathEffect.Style.TRANSLATE));
            canvas.drawPath(path,paint);
        }

    这里写图片描述

    例子DiscretePathEffect:
        private Path getPath(){
            Path path = new Path();
            // 定义路径的起点
            path.moveTo(0, 0);
    
            // 定义路径的各个点
            for (int i = 0; i <= 40; i++) {
                path.lineTo(i*35, (float) (Math.random() * 150));
            }
            return path;
        }
    
        private Paint getPaint(){
            Paint paint = new Paint();
            paint.setStrokeWidth(4);
            paint.setColor(Color.GREEN);
            paint.setStyle(Paint.Style.STROKE);
            paint.setAntiAlias(true);
            return paint;
        }
        private void drawDiscretePathEffectDemo(Canvas canvas){
            Paint paint = getPaint();
            Path path = getPath();
    
            canvas.drawPath(path,paint);
            /**
             * 把原有的路线,在指定的间距处插入一个突刺
             * 第一个这些突出的“杂点”的间距,值越小间距越短,越密集
             * 第二个是突出距离
             */
            canvas.translate(0,200);
            paint.setPathEffect(new DiscretePathEffect(2,5));
            canvas.drawPath(path,paint);
    
            canvas.translate(0,200);
            paint.setPathEffect(new DiscretePathEffect(6,5));
            canvas.drawPath(path,paint);
    
    
            canvas.translate(0,200);
            paint.setPathEffect(new DiscretePathEffect(6,15));
            canvas.drawPath(path,paint);
        }

    这里写图片描述

    例子CornerPathEffect、DashPathEffect:
        private void drawDashPathEffect(Canvas canvas){
            Paint paint = new Paint();
            paint.setStrokeWidth(4);
            paint.setColor(Color.GREEN);
            paint.setStyle(Paint.Style.STROKE);
            paint.setAntiAlias(true);
            Path path = new Path();
            path.moveTo(100,600);
            path.lineTo(400,100);
            path.lineTo(700,900);
    
            canvas.drawPath(path,paint);
            paint.setColor(Color.RED);
    
            //使用DashPathEffect画线段
            paint.setPathEffect(new DashPathEffect(new float[]{10,30,50,100},0));
            canvas.translate(0,100);
            canvas.drawPath(path,paint);
    
            //画同一条线段,偏移值为15
            paint.setPathEffect(new CornerPathEffect(100));
            paint.setColor(Color.BLUE);
            canvas.translate(0,100);
            canvas.drawPath(path,paint);
        }

    运行结果:
    这里写图片描述

    例子SumPathEffect、ComposePathEffect:
        private Path getPath(){
            Path path = new Path();
            // 定义路径的起点
            path.moveTo(0, 0);
    
            // 定义路径的各个点
            for (int i = 0; i <= 40; i++) {
                path.lineTo(i*35, (float) (Math.random() * 150));
            }
            return path;
        }
    
        private Paint getPaint(){
            Paint paint = new Paint();
            paint.setStrokeWidth(4);
            paint.setColor(Color.GREEN);
            paint.setStyle(Paint.Style.STROKE);
            paint.setAntiAlias(true);
            return paint;
        }
        private void drawComposePathEffectDemo(Canvas canvas){
            //画原始路径
            Paint paint = getPaint();
            Path path = getPath();
            canvas.drawPath(path,paint);
    
            //仅应用圆角特效的路径
            canvas.translate(0,300);
            CornerPathEffect cornerPathEffect = new CornerPathEffect(100);
            paint.setPathEffect(cornerPathEffect);
            canvas.drawPath(path,paint);
    
            //仅应用虚线特效的路径
            canvas.translate(0,300);
            DashPathEffect dashPathEffect = new DashPathEffect(new float[]{2,5,10,10},0);
            paint.setPathEffect(dashPathEffect);
            canvas.drawPath(path,paint);
    
            //利用ComposePathEffect先应用圆角特效,再应用虚线特效
            canvas.translate(0,300);
            ComposePathEffect composePathEffect = new ComposePathEffect(dashPathEffect,cornerPathEffect);
            paint.setPathEffect(composePathEffect);
            canvas.drawPath(path,paint);
    
            //利用SumPathEffect,分别将圆角特效应用于原始路径,然后将生成的两条特效路径合并
            canvas.translate(0,300);
            paint.setStyle(Paint.Style.STROKE);
            SumPathEffect sumPathEffect = new SumPathEffect(cornerPathEffect,dashPathEffect);
            paint.setPathEffect(sumPathEffect);
            canvas.drawPath(path,paint);
    
        }

    运行结果:
    这里写图片描述

    setAntiAlias(boolean aa) 设置画笔是否抗锯齿

    这里写图片描述
    左边是没有设置抗锯齿,右边设置了抗锯齿,边界明显变模糊了。

    void setDither(boolean dither) 设定是否使用图像抖动处理

    会使绘制出来的图片颜色更加平滑和饱满、图像更加清晰。

    我们先看下没有设置防抖动的绘制出来的图
    这里写图片描述

    然后我们看下设置了防抖动的绘制出来的图
    这里写图片描述

    void reset() 清空画笔复位。

    获取与设置alpha值、颜色、ARGB等

    void setARGB(int a, int r, int g, int b)

    int getAlpha()

    void setAlpha(int a)

    int getColor()

    void setColor(int color)

    setXfermode(Xfermode xfermode)设置图形重叠时的处理方式

    如合并,取交集或并集,经常用来制作橡皮的擦除效果

    不同模式下的结果如图:
    这里写图片描述

    例子1:使用PorterDuff.Mode.SRC_IN做一个圆形头像

    public class RoundImageView extends View {
    
        private Paint mBitMapPaint;
        private Bitmap mBitMapSRC;
    
        public RoundImageView(Context context) {
            this(context, null);
        }
    
        public RoundImageView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            //去掉硬件加速
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
            //画笔
            mBitMapPaint = new Paint();
            mBitMapPaint.setAntiAlias(true);
            //Src图片
            mBitMapSRC = BitmapFactory.decodeResource(getResources(), R.drawable.xyjy6);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            //首先绘制一个半径150的圆
            mBitMapPaint.setColor(Color.RED);
            mBitMapPaint.setStyle(Paint.Style.FILL);
            canvas.drawCircle(mBitMapSRC.getWidth() / 2 , mBitMapSRC.getHeight() / 2 , 150, mBitMapPaint);
            //设置画笔模式SRC_IN
            mBitMapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            //绘制Src图片
            canvas.drawBitmap(mBitMapSRC, 0, 0, mBitMapPaint);
    
            mBitMapPaint.setXfermode(null);
    
        }
    }

    这里写图片描述

    例子2:刮刮卡

    public class ScratchCard extends View {
        private static final String TAG = "ScratchCard";
        private final Bitmap mBitMapDst;
        private final Paint mPaint;
        private final  int paintWidth = 30;
        private final Path mPath;
    
        public ScratchCard(Context context) {
            this(context, null);
        }
    
        public ScratchCard(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            mPaint = new Paint();
            mBitMapDst = BitmapFactory.decodeResource(getResources(), R.drawable.guaguaka);
            mPath = new Path();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            //先绘制刮刮卡背景图片
            canvas.drawBitmap(mBitMapDst, 0, 0, mPaint);
            //保存图层
            int layerId = canvas.saveLayer(0, 0, mBitMapDst.getWidth(), mBitMapDst.getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);
            //透明图层
            //首先绘制一个矩形灰色区域
            mPaint.setColor(Color.GRAY);
            mPaint.setStyle(Paint.Style.FILL);
            canvas.drawRect(0, 0, mBitMapDst.getWidth(), mBitMapDst.getHeight(), mPaint);
            //设置叠加模式XOR
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
            //绘制刮开的path路径
            mPaint.setColor(Color.BLUE);
            mPaint.setStrokeWidth(paintWidth);
            mPaint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(mPath, mPaint);
    
            mPaint.setXfermode(null);
    
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    //移动路径
                    mPath.moveTo(event.getX(), event.getY());
                    return true;
                case MotionEvent.ACTION_MOVE:
                    //连线
                    mPath.lineTo(event.getX(), event.getY());
                    postInvalidate();
                    return true;
                case MotionEvent.ACTION_UP:
                    //连线
                    mPath.lineTo(event.getX(), event.getY());
                    postInvalidate();
                    return false;
            }
            return super.onTouchEvent(event);
        }
    }

    这里写图片描述

    例子3:倒影

    
    public class InvertedImage extends View {
        private final Paint mPaint;
        private final Bitmap mBitMapDST, mBitMapSrc;
        private final Bitmap mBitMapRevert;
    
        public InvertedImage(Context context) {
            this(context, null);
        }
    
        public InvertedImage(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
            mPaint = new Paint();
            mBitMapDST = BitmapFactory.decodeResource(getResources(), R.drawable.xyjy6,null);
            mBitMapSrc = BitmapFactory.decodeResource(getResources(),R.drawable.invert_shade,null);
    
            Matrix matrix = new Matrix();
            matrix.setScale(1F, -1F);
            // 生成倒影图
            mBitMapRevert = Bitmap.createBitmap(mBitMapDST, 0, 0, mBitMapDST.getWidth(), mBitMapDST.getHeight(), matrix, true);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            //先画图片
            canvas.drawBitmap(mBitMapDST, 0, 0, mPaint);
    
            //保存图层
            int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint);
    
            //在新的图层进行绘制
            //画布移动
            canvas.translate(0, mBitMapDST.getHeight());
    
            //画倒图Dst
            canvas.drawBitmap(mBitMapRevert, 0, 0, mPaint);
            //DST_IN模式
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
            //画Src图
            canvas.drawBitmap(mBitMapSrc, 0, 0, mPaint);
    
            mPaint.setXfermode(null);
    
            //回到原图层
            canvas.restoreToCount(layerId);
    
    
        }
    }

    这里写图片描述

    例子4:心电图

    public class HeartMapView extends View {
    
        private final Paint mBitMapPaint;
        private final Bitmap mBitMapDST;
        private float distance;
        private static final String TAG = "HeartMapView";
        public HeartMapView(Context context) {
            super(context);
            setLayerType(LAYER_TYPE_SOFTWARE, null);
            mBitMapPaint = new Paint();
    
            mBitMapDST = BitmapFactory.decodeResource(getResources(), R.drawable.heartmap);
    
            startAnimation();
        }
    
        private void startAnimation() {
            ValueAnimator animator = ValueAnimator.ofFloat(0, mBitMapDST.getWidth());
            animator.setDuration(6000);
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.setInterpolator(new LinearInterpolator());
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                   distance = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animator.start();
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawRect(distance, 0, mBitMapDST.getWidth(), mBitMapDST.getHeight(), mBitMapPaint);
            mBitMapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));//相交区域透明
            canvas.drawBitmap(mBitMapDST, 0, 0, mBitMapPaint);
            mBitMapPaint.setXfermode(null);
        }
    }

    这里写图片描述

    setMaskFilter(MaskFilter maskfilter)可以用不同的MaskFilter实现滤镜的效果

    如滤化,立体等
    继承关系:
    这里写图片描述

    BlurMaskFilter 模糊

    例子:

        private void BlurMaskFilter(Canvas canvas) {
            Paint mPaint = new Paint();
    
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xyjy2);
            RectF rectF = new RectF(100,100,bitmap.getWidth() + 100,bitmap.getHeight() + 100);
            /**
             * Create a blur maskfilter.
             *
             * @param radius 阴影的半径
             * @param style  NORMOL -- 整个图像都被模糊掉
             *               SOLID -- 图像边界外产生一层与Paint颜色一致阴影效果,不影响图像的本身
             *               OUTER -- 图像边界外产生一层阴影,并且将图像变成透明效果
             *               INNER -- 在图像内部边沿产生模糊效果
             * @return
             */
            mPaint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL));
            canvas.drawBitmap(bitmap,null, rectF,mPaint);
        }

    BlurMaskFilter.Blur.NORMAL
    这里写图片描述
    BlurMaskFilter.Blur.SOLID
    这里写图片描述
    BlurMaskFilter.Blur.OUTER
    这里写图片描述
    BlurMaskFilter.Blur.INNER
    这里写图片描述

    EmbossMaskFilter 浮雕

    例子:

        private void EmbossMaskFilter(Canvas canvas) {
            Paint mPaint = new Paint();
            mPaint.setColor(Color.RED);
    
            RectF rectF = new RectF(100, 100, 300, 300);
            /**
             * Create an emboss maskfilter
             *
             * @param direction  指定光源的位置,长度为xxx的数组标量[x,y,z]
             * @param ambient    环境光的因子 (0~1),越接近0,环境光越暗
             * @param specular   镜面反射系数 越接近0,镜面反射越强
             * @param blurRadius 模糊半径 值越大,模糊效果越明显
             */
            mPaint.setMaskFilter(new EmbossMaskFilter(new float[]{1,1,1},0.1f,1,10));
            canvas.drawRect(rectF, mPaint);
        }

    这里写图片描述

    setColorFilter(ColorFilter colorfilter)设置颜色过滤器

    可以在绘制颜色时实现不用颜色的变换效果
    继承关系:
    这里写图片描述

    ColorMatrixColorFilter

    颜色矩阵表示:
    这里写图片描述
    这里写图片描述

    例子:
    
            // 平移运算---加法
    //        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
    //                1,0,0,0,100,
    //                0,1,0,0,0,
    //                0,0,1,0,0,
    //                0,0,0,1,0,
    //        });
    
    
            // 反相效果 -- 底片效果
    //       ColorMatrix colorMartrix = new ColorMatrix(new float[]{
    //                -1,0,0,0,255,
    //                0,-1,0,0,255,
    //                0,0,-1,0,255,
    //                0,0,0,1,0,
    //        });
    
    
    
            // 缩放运算---乘法 -- 颜色增强
    //        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
    //                1.5f, 0,0,0,0,
    //                0,1.5f,0,0,0,
    //                0,0,1.5f,0,0,
    //                0,0,0,1.5f,0,
    //        });
    
            // 黑白照片
            // 去色原理:只要把R G B 三通道的色彩信息设置成一样,那么图像就会变成灰色,
            // 同时为了保证图像亮度不变,同一个通道里的R+G+B =1
    
    //        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
    //                1f, 0,0,0,0,
    //                1f, 0,0,0,0,
    //                1f, 0,0,0,0,
    //                0,0,0,1,0,
    //        });
    //        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
    //                0.213f, 0.715f,0.072f,0,0,
    //                0.213f, 0.715f,0.072f,0,0,
    //                0.213f, 0.715f,0.072f,0,0,
    //                0,0,0,1,0,
    //        });
    
            // 发色效果---(比如红色和绿色交换)
    //        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
    //                0,1,0,0,0,
    //                1, 0,0,0,0,
    //                0,0,1,0,0,
    //                0,0,0,1,0,
    //        });
    
            // 复古效果
    //        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
    //                1/2f,1/2f,1/2f,0,0,
    //                1/3f, 1/3f,1/3f,0,0,
    //                1/4f,1/4f,1/4f,0,0,
    //                0,0,0,1,0,
    //        });
    
            // 颜色通道过滤
            ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                    1, 0,0,0,0,
                    0,0,0,0,0,
                    0,0,0,0,0,
                    0,0,0,1,0,
            });
    
    
            RectF rectF2 = new RectF(100, 100, bitmap.getWidth() + 100, bitmap.getHeight() + 100);
            paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));
            canvas.drawBitmap(bitmap,null, rectF2,paint);
    平移运算—加法:

    这里写图片描述

    反相效果 – 底片效果:

    这里写图片描述

    缩放运算—乘法 – 颜色增强

    这里写图片描述

    黑白照片

    这里写图片描述

    发色效果—(比如红色和绿色交换)

    这里写图片描述

    复古效果

    这里写图片描述

    颜色通道过滤

    这里写图片描述

    setShader(Shader shader)设置图像效果

    使用Shader可以绘制出各种渐变效果
    先看一下Shader的子类
    这里写图片描述

    BitmapShader 可以用来画重复、拉伸或镜像的位图

    例子1
        private void BitmapShader(Canvas canvas) {
            /**
             * TileMode.CLAMP 拉伸最后一个像素去铺满剩下的地方
             * TileMode.MIRROR 通过镜像翻转铺满剩下的地方。
             * TileMode.REPEAT 重复图片平铺整个画面(电脑设置壁纸)
             */
            BitmapShader bitMapShader = new BitmapShader(mBitMap, Shader.TileMode.MIRROR,
                     Shader.TileMode.MIRROR);
            mPaint.setShader(bitMapShader);
            mPaint.setAntiAlias(true);
    
    //        canvas.drawCircle(mHeight / 2,mHeight / 2, mHeight / 2 ,mPaint);
    //        canvas.drawOval(new RectF(0 , 0, mWidth, mHeight),mPaint);
    
            canvas.drawRect(new Rect(0,0 , getWidth(), getHeight()),mPaint);
        }

    Shader.TileMode.MIRROR:
    这里写图片描述

    Shader.TileMode.CLAMP:
    这里写图片描述

    Shader.TileMode.REPEAT:
    这里写图片描述

    例子2:
    public class ZoomImageView extends View {
        //放大倍数
        private static final int FACTOR = 2;
        //放大镜的半径
        private static final int RADIUS  = 100;
        // 原图
        private Bitmap mBitmap;
        // 放大后的图
        private Bitmap mBitmapScale;
        // 制作的圆形的图片(放大的局部),盖在Canvas上面
        private ShapeDrawable mShapeDrawable;
    
        private Matrix mMatrix;
    
        public ZoomImageView(Context context) {
            this(context, null);
        }
    
        public ZoomImageView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xyjy3);
            mBitmapScale = mBitmap;
            //放大后的整个图片
            mBitmapScale = Bitmap.createScaledBitmap(mBitmapScale, mBitmapScale.getWidth() * FACTOR,
                    mBitmapScale.getHeight() * FACTOR, true);
            BitmapShader bitmapShader = new BitmapShader(mBitmapScale, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            mShapeDrawable = new ShapeDrawable(new OvalShape());
            mShapeDrawable.getPaint().setShader(bitmapShader);
            //切出矩形区域,用来画圆
            mShapeDrawable.setBounds(0, 0, RADIUS * 2, RADIUS * 2);
    
            mMatrix = new Matrix();
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //1.画原图
            canvas.drawBitmap(mBitmap, 0, 0, null);
            //2.画放大镜的图
            mShapeDrawable.draw(canvas);
        }
    
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int x = (int) event.getX();
            int y = (int) event.getY();
    
            if(x > mBitmap.getWidth() - RADIUS) x = mBitmap.getWidth() - RADIUS;
            if(y > mBitmap.getHeight() - RADIUS) y = mBitmap.getHeight() - RADIUS;
            // 将放大的图片往相反的方向挪动
            mMatrix.setTranslate(RADIUS - x * FACTOR, RADIUS - y *FACTOR);
            mShapeDrawable.getPaint().getShader().setLocalMatrix(mMatrix);
            // 切出手势区域点位置的圆
            mShapeDrawable.setBounds(x-RADIUS,y - RADIUS, x + RADIUS, y + RADIUS);
            invalidate();
            return true;
        }
    }

    这里写图片描述

    LinearGradient 线性渐变

    例子1:
        private void LinearGradient(Canvas canvas) {
            /**线性渐变
             * x0, y0, 起始点
             *  x1, y1, 结束点
             * int[]  mColors, 中间依次要出现的几个颜色
             * float[] positions,数组大小跟colors数组一样大,中间依次摆放的几个颜色分别放置在那个位置上(参考比例从左往右)
             *    tile
             */
            LinearGradient linearGradient = new LinearGradient(50, 50, 200, 200, mColors, null, Shader.TileMode.REPEAT);
            mPaint.setShader(linearGradient);
            canvas.drawRect(0, 0, 400, 400, mPaint);
        }

    Shader.TileMode.MIRROR:
    这里写图片描述
    Shader.TileMode.REPEAT:
    这里写图片描述
    Shader.TileMode.CLAMP:
    这里写图片描述

    例子2:
        private void ShapeDrawable(Canvas canvas) {
            //通过shapeDrawable也可以实现
            BitmapShader bitMapShader = new BitmapShader(mBitMap, Shader.TileMode.MIRROR,
                    Shader.TileMode.MIRROR);
            ShapeDrawable shapeDrawble = new ShapeDrawable(new OvalShape());//画椭圆
            shapeDrawble.setShape(new ArcShape(180, 180));//画扇形
            shapeDrawble.getPaint().setShader(bitMapShader);
            shapeDrawble.setBounds(0,0,mWidth,mWidth);
            shapeDrawble.draw(canvas);
        }

    这里写图片描述

    注意:

    对于Shader.TileMode的三种状态,只有画布比图片大时,才有效果.
    利用ShapeDrawable可以对图片进行各种剪裁,比如圆形头像,椭圆头像等等。

    RadialGradient 圆形渐变填充

    例子1
        private void RadialGradient(Canvas canvas) {
            RadialGradient mRadialGradient = new RadialGradient(getWidth()/2, getHeight()/2, 50, mColors, null, Shader.TileMode.MIRROR);
            mPaint.setShader(mRadialGradient);
            canvas.drawCircle(getWidth()/2, getHeight()/2, 100, mPaint);
    //        canvas.drawRect(getWidth()/2 - 100, getHeight()/2 - 100, getWidth()/2 + 100, getHeight()/2 + 100, mPaint);
        }

    这里写图片描述

    例子2 水波纹扩散效果
    public class RippleView extends Button {
        // 点击位置
        private int mX, mY;
    
        private ObjectAnimator mAnimator;
        // 默认半径
        private int DEFAULT_RADIUS = 50;
    
        private int mCurRadius = 0;
    
        private RadialGradient mRadialGradient;
    
        private Paint mPaint;
    
        public RippleView(Context context) {
            super(context);
            init();
        }
    
        public RippleView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        private void init() {
            // 禁用硬件加速
            setLayerType(LAYER_TYPE_SOFTWARE,null);
            mPaint = new Paint();
        }
    
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            if (mX != event.getX() || mY != mY) {
                mX = (int) event.getX();
                mY = (int) event.getY();
    
                setRadius(DEFAULT_RADIUS);
            }
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    return true;
    
                case MotionEvent.ACTION_UP:
                {
                    if (mAnimator != null && mAnimator.isRunning()) {
                        mAnimator.cancel();
                    }
    
                    if (mAnimator == null) {
                        mAnimator = ObjectAnimator.ofInt(this,"radius",DEFAULT_RADIUS, getWidth());
                    }
    
                    mAnimator.setInterpolator(new AccelerateInterpolator());
                    mAnimator.addListener(new Animator.AnimatorListener() {
                        @Override
                        public void onAnimationStart(Animator animation) {
    
                        }
    
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            setRadius(0);
                        }
    
                        @Override
                        public void onAnimationCancel(Animator animation) {
    
                        }
    
                        @Override
                        public void onAnimationRepeat(Animator animation) {
    
                        }
                    });
                    mAnimator.setDuration(1000);
                    mAnimator.start();
                }
            }
    
            return super.onTouchEvent(event);
        }
    
        public void setRadius(final int radius) {
            mCurRadius = radius;
            if (mCurRadius > 0) {
                mRadialGradient = new RadialGradient(mX, mY, mCurRadius, 0x00FFFFFF, 0xFF58FAAC, Shader.TileMode.CLAMP);
                mPaint.setShader(mRadialGradient);
            }
            postInvalidate();
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            canvas.drawCircle(mX, mY, mCurRadius, mPaint);
        }
    }

    SweepGradient 梯度/扫描渲染

    可以做雷达扫描等

    雷达扫描例子
    
    public class RadarView extends View {
        private final String TAG = "RadarView";
    
        private static final int MSG_WHAT = 1;
    
        private static final int DELAY_TIME = 20;
    
        //设置默认宽高,雷达一般都是圆形,所以我们下面取宽高会去Math.min(宽,高)
        private final int DEFAULT_WIDTH = 200;
    
        private final int DEFAULT_HEIGHT = 200;
        //雷达的半径
        private int mRadarRadius;
        //雷达画笔
        private Paint mRadarPaint;
        //雷达底色画笔
        private Paint mRadarBg;
        //雷达圆圈的个数,默认4个
        private int mCircleNum = 4;
        //雷达线条的颜色,默认为白色
        private int mCircleColor = Color.WHITE;
        //雷达圆圈背景色
        private int mRadarBgColor = Color.BLACK;
        //paintShader
        private Shader mRadarShader;
    
        //雷达扫描时候的起始和终止颜色
        private int mStartColor = 0x0000ff00;
    
        private int mMiddleColor = 0xd6ff0000;
    
        private int mEndColor = 0xaa00ff00;
    
    
        private Matrix mMatrix;
    
        //旋转的角度
        private int mRotate = 0;
    
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
    
                mRotate += 3;
                postInvalidate();
    
                mMatrix.reset();
                mMatrix.preRotate(mRotate, 0, 0);
                mHandler.sendEmptyMessageDelayed(MSG_WHAT, DELAY_TIME);
            }
        };
    
        public RadarView(Context context) {
            this(context, null);
        }
    
        public RadarView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public RadarView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs);
    
    
            mRadarBg = new Paint(Paint.ANTI_ALIAS_FLAG);     //设置抗锯齿
            mRadarBg.setColor(mRadarBgColor);                  //画笔颜色
            mRadarBg.setStyle(Paint.Style.FILL);           //画实心圆
    
            mRadarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);     //设置抗锯齿
            mRadarPaint.setColor(mCircleColor);                  //画笔颜色
            mRadarPaint.setStyle(Paint.Style.STROKE);           //设置空心的画笔,只画圆边
            mRadarPaint.setStrokeWidth(2);                      //画笔宽度
    
            mRadarShader = new SweepGradient(0, 0, mStartColor, mEndColor);
            mRadarShader = new SweepGradient(0, 0, new int[]{mStartColor, mEndColor}, null);
    
            mMatrix = new Matrix();
        }
    
    
        //初始化,拓展可设置参数供布局使用
        private void init(Context context, AttributeSet attrs) {
    //        if (attrs != null) {
    //            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RadarView);
    //            mStartColor = ta.getColor(R.styleable.RadarView_startColor, mStartColor);
    //            mEndColor = ta.getColor(R.styleable.RadarView_endColor, mEndColor);
    //            mRadarBgColor = ta.getColor(R.styleable.RadarView_backgroundColor, mRadarBgColor);
    //            mCircleColor = ta.getColor(R.styleable.RadarView_lineColor, mCircleColor);
    //            mCircleNum = ta.getInteger(R.styleable.RadarView_circleNum, mCircleNum);
    //            ta.recycle();
    //        }
        }
    
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mRadarRadius = Math.min(w / 2, h / 2);
    
            //Log.d(TAG, "onSizeChanged");
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int width = measureSize(1, DEFAULT_WIDTH, widthMeasureSpec);
            int height = measureSize(0, DEFAULT_HEIGHT, heightMeasureSpec);
    
            //取最大的 宽|高
            int measureSize = Math.min(width, height);
    //        setMeasuredDimension(measureSize, measureSize);
            setMeasuredDimension(200, 200);
        }
    
    
        /**
         * 测绘measure
         *
         * @param specType    1为宽, 其他为高
         * @param contentSize 默认值
         */
        private int measureSize(int specType, int contentSize, int measureSpec) {
            int result;
            //获取测量的模式和Size
            int specMode = MeasureSpec.getMode(measureSpec);
            int specSize = MeasureSpec.getSize(measureSpec);
    
            if (specMode == MeasureSpec.EXACTLY) {
                result = Math.max(contentSize, specSize);
            } else {
                result = contentSize;
    
                if (specType == 1) {
                    // 根据传人方式计算宽
                    result += (getPaddingLeft() + getPaddingRight());
                } else {
                    // 根据传人方式计算高
                    result += (getPaddingTop() + getPaddingBottom());
                }
            }
    
            return result;
    
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            Log.d(TAG, "onDraw   " + mRotate);
    
            mRadarBg.setShader(null);
    
            //将画板移动到屏幕的中心点
            canvas.translate(mRadarRadius, getHeight()/2);
            //绘制底色,让雷达的线看起来更清晰
            canvas.drawCircle(0, 0, mRadarRadius, mRadarBg);
            //画圆圈
            for (int i = 1; i <= mCircleNum; i++) {
                canvas.drawCircle(0, 0, (float) (i * 1.0 / mCircleNum * mRadarRadius), mRadarPaint);
            }
            //绘制雷达基线 x轴
            canvas.drawLine(-mRadarRadius, 0, mRadarRadius, 0, mRadarPaint);
            //绘制雷达基线 y轴
            canvas.drawLine(0, mRadarRadius, 0, -mRadarRadius, mRadarPaint);
    
    //        canvas.rotate(mRotate,0,0);
            //设置颜色渐变从透明到不透明
            mRadarBg.setShader(mRadarShader);
            mRadarShader.setLocalMatrix(mMatrix);
    //        canvas.concat(mMatrix);
            canvas.drawCircle(0, 0, mRadarRadius, mRadarBg);
        }
    
    
        public void startScan() {
            mHandler.removeMessages(MSG_WHAT);
            mHandler.sendEmptyMessage(MSG_WHAT);
        }
    
        public void stopScan() {
            mHandler.removeMessages(MSG_WHAT);
        }
    }

    这里写图片描述

    ComposeShader 组合渲染

    setShadowLayer(float radius ,float dx,float dy,int color)在图形下面设置阴影层,产生阴影效果

    radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色

    负责设置获取文字相关

    float getFontSpacing()获取字符行间距

    float getLetterSpacing()获取字符间距

    float setLetterSpacing()设置字符间距

    final boolean isUnderlineText()是否有下划线

    void setUnderlineText(boolean underlineText)设置下划线

    final boolean isStrikeThruText()获取是否有文本删除线

    void setStrikeThruText(boolean strikeThruText)设置文本删除线

    float getTextSize()获取文字大小

    void setTextSize(float textSize)设置文字大小

    注意:Paint.setTextSize传入的单位是px,TextView.setTextSize传入的单位是sp,注意使用时不同分辨率处理问题。

    Typeface getTypeface()获取字体类型

    Typeface setTypeface()设置字体类型

    Android˙中默认有四种字体样式:BOLD(加粗)、BOLD_ITALIC(加粗并倾斜)、ITALIC(倾斜)、NORMAL(正常),我们也可以通过Typeface类来自定义个性化字体。

    float getTextSkewX()获取文字倾斜

    void setTextSkewX(float skewx)设置文字倾斜

    参数没有具体范围,官方推荐值为-0.25,值为负则右倾,为正则左倾,默认值为0

    Paint.Align getTextAlign()获取文本对齐方式

    voie setTextAlign(Paint.Align align)设置文本对齐方式

    Align有CENTER、LEFT、RIGHT,也就是文字绘制是居中、左对齐还是右对齐的。

    setSubpixelText(boolean subpixelText)

    固定的几个范围:320*480,480*800,720*1280,1080*1920等等;那么如何在同样的分辨率的显示器中增强显示清晰度呢?
    亚像素的概念就油然而生了,亚像素就是把两个相邻的两个像素之间的距离再细分,再插入一些像素,这些通过程序加入的像素就是亚像素。在两个像素间插入的像素个数是通过程序计算出来的,一般是插入两个、三个或四个。
    所以打开亚像素显示,是可以在增强文本显示清晰度的,但由于插入亚像素是通过程序计算而来的,所以会耗费一定的计算机性能。

    breakText

    • int breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth)
      比如文本阅读器的翻页效果,我们需要在翻页的时候动态折断或生成一行字符串,这就派上用场了~

    getTextBounds获取文本的宽高,通过boudns的Rect拿到整型

    • void getTextBounds(char[] text, int index, int count, Rect bounds)
    • void getTextBounds(String text, int start, int end, Rect bounds)

    measureText粗略获取文本的宽度,和上面的getTextBounds比较类似,返回浮点数

    • float measureText(String text)
    • float measureText(CharSequence text, int start, int end)
    • float measureText(String text, int start, int end)
    • float measureText(char[] text, int index, int count)

    getTextWidths精确计算文字宽度,与上面两个类似。

    • int getTextWidths(String text, int start, int end, float[] widths) - - int getTextWidths(String text, float[] widths)
    • int getTextWidths(CharSequence text, int start, int end, float[] widths)
    • int getTextWidths(char[] text, int index, int count, float[] widths)

    FontMetrics,FontMetricsInt

    先上一张图:
    这里写图片描述
    图中横线
    - 绿色线表示baseline
    - 黑色线表示top
    - FontMetrics.top = topY - baselineY < 0
    - 黄色线表示descent
    - FontMetrics.descent = descentY - baselineY > 0
    - 红色线表示bottom
    - FontMetrics.bottom = bottomY - baselineY > 0
    图中竖线
    - 红色长度表示center距离top的距离:A
    - 蓝色长度表示center距离bottom的距离:B
    - 绿色长度表示center距离basiline的距离:C

    求baselineY坐标:

         计算baseline的Y坐标:
         1.
         图中横线:
         绿色线表示baseline
         黑色线表示top         FontMetrics.top = topY - baselineY < 0
         黄色线表示descent     FontMetrics.descent = descentY - baselineY > 0
         红色线表示bottom      FontMetrics.bottom = bottomY - baselineY > 0
    
    
         2.
         图中竖线:
         红色长度表示center距离top的距离:A
         蓝色长度表示center距离bottom的距离:B
         绿色长度表示center距离basiline的距离:C
         中心点坐标为:centX, centY
         3.计算过程
         由图可知:A = B = (bottomY - topY) / 2;
         bottomY = baselineY + FontMetrics.bottom;
         topY = baselineY + FontMetrics.top;
         => A = B = (FontMetrics.bottom - FontMetrics.top)/2;
         由图可知:C = B - FontMetrics.bottom;
         又由于: C = baselineY - center;
         => baselineY - centerY = B - FontMetrics.bottom
         => baselineY = B - FontMetrics.bottom + centerY
         => baselineY = (FontMetrics.bottom - FontMetrics.top)/2 - FontMetrics.bottom + centerY
         4.结论
         baselineY = centerY - (FontMetrics.bottom + FontMetrics.top)/2

    绘制上面的各种线:

        private void drawTextLines(Canvas canvas) {
            String text = "画笔文字Texti";
            int centerX = getWidth() / 2;
            int centerY = getHeight() / 2;
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setTextSize(150);
            paint.setColor(Color.GRAY);
    
            Rect rect = new Rect();
            paint.getTextBounds(text, 0, text.length(), rect);
    
            Paint.FontMetricsInt fm = paint.getFontMetricsInt();
            //计算baseline的y坐标
            int baseLineY = (int) (centerY - (fm.bottom + fm.top) / 2f);
            //计算文字最左边x坐标
            float textLeftX = centerX - paint.measureText(text) / 2f;
            //绘制文字
            canvas.drawText(text, textLeftX, baseLineY, paint);
    
    
            paint.setStrokeWidth(3);
            //绘制屏幕中心线
            paint.setColor(Color.BLUE);
            canvas.drawLine(textLeftX, centerY, getWidth() - textLeftX, centerY, paint);
            //绘制baseline
            paint.setColor(Color.GREEN);
            canvas.drawLine(textLeftX, baseLineY, getWidth() - textLeftX, baseLineY, paint);
            //绘制bottom
            paint.setColor(Color.RED);
            canvas.drawLine(textLeftX, baseLineY + fm.bottom, getWidth() - textLeftX, baseLineY + fm.bottom, paint);
            //绘制top
            paint.setColor(Color.BLACK);
            canvas.drawLine(textLeftX, baseLineY + fm.top, getWidth() - textLeftX, baseLineY + fm.top, paint);
            //绘制descent
            paint.setColor(Color.YELLOW);
            canvas.drawLine(textLeftX, baseLineY + fm.descent, getWidth() - textLeftX, baseLineY + fm.descent, paint);
    
            int DS = 50;
            //绘制A
            paint.setColor(Color.RED);
            canvas.drawLine(getWidth() - textLeftX, centerY, getWidth() - textLeftX, baseLineY + fm.top, paint);
            //绘制B
            paint.setColor(Color.BLUE);
            canvas.drawLine(getWidth() - textLeftX - DS, centerY, getWidth() - textLeftX - DS, baseLineY + fm.bottom, paint);
            //绘制C
            paint.setColor(Color.GREEN);
            canvas.drawLine(getWidth() - textLeftX - DS * 2, centerY, getWidth() - textLeftX - DS * 2, baseLineY, paint);
        }

    运行结果:
    这里写图片描述

    例子:圆形进度条

    public class CircleProgressBar extends View {
        private float max;//进度条最大值
        private int roundColor;//初始圆环的颜色
        private int roundProgressColor;//进度条增加时的圆环颜色
        private int textColor;//文字颜色
        private float textSize;//文字大小
        private float roundWidth;//圆环宽度
        private boolean textShow;//是否显示文字进度
        private float progress;//进度值
        private Paint paint;//画笔
        public static final int STROKE = 0;
        public static final int FILL = 1;
        private int centerX, centerY;
        private static final String TAG = "CircleProgressBar";
        public CircleProgressBar(Context context) {
            this(context, null);
        }
    
        public CircleProgressBar(Context context, AttributeSet attrs){
            super(context, attrs);
            paint = new Paint();
    
            max = 100f;
            roundColor = Color.GRAY;
            roundProgressColor = Color.GREEN;
            textColor = Color.BLUE;
            textSize = 55;
            roundWidth = 10;
            textShow = true;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            switch (widthMode){
                case MeasureSpec.EXACTLY:
                    Log.i(TAG, "onMeasure: exactly");
                    setMeasuredDimension(widthSize, heightSize);
                    break;
                case MeasureSpec.AT_MOST:
                case MeasureSpec.UNSPECIFIED:
                    Log.i(TAG, "onMeasure: at_most");
                    setMeasuredDimension(200, 200);
                    break;
            }
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            centerX = w / 2;
            centerY = h / 2;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //画圆环背景
            float radius = centerX < centerY ? centerX - roundWidth / 2 : centerY - roundWidth / 2;
            paint.setColor(roundColor);
            paint.setStyle(Paint.Style.FILL_AND_STROKE);
            paint.setStrokeWidth(roundWidth);
            paint.setAntiAlias(true);
            canvas.drawCircle(centerX, centerY, radius, paint);
    
            //画圆弧
            RectF oval = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
            paint.setColor(roundProgressColor);
            paint.setStrokeWidth(roundWidth);
            paint.setStyle(Paint.Style.FILL_AND_STROKE);
            canvas.drawArc(oval, 0, 360 * progress / max, true, paint);
    
            //画进度百分比
            paint.setColor(textColor);
            paint.setStrokeWidth(0);
            paint.setTextSize(textSize);
            paint.setTypeface(Typeface.DEFAULT_BOLD);
    
            int percent = (int) (progress / max * 100);
            String strPercent = percent + "%";
            Paint.FontMetricsInt fm = paint.getFontMetricsInt();
            if(percent != 0){
                canvas.drawText(strPercent, centerX - paint.measureText(strPercent) / 2,
                        centerY - (fm.bottom + fm.top)/2, paint
                );
            }
    
    
            if(progress > max){
                progress = max;
            }
            if(progress < max){
                progress += 0.1;
                invalidate();
                if(progress >= max){
                    progress = 0;
                }
            }
    
        }
    }

    这里写图片描述

    展开全文
  • JAVA中的paint()方法和paintComponent(), paintBorder(), paintChildren()改怎么用?我看很多介绍都说不要直接重写paint( )方法。现在要在JPanel 上绘图,是用某个类继承JPanel再重写paint方法还是怎么?
  • Java paint()个人理解

    千次阅读 2018-08-10 17:16:04
    这些天给同学讲了不少次JUI的 paint()方法和画笔,就目前而言已经比当初自己写的时候理解的多了不少了,虽然有点花时间,但好处还是有的。(习惯把Graphics g对象叫做画笔)  以前想要在某个容器上用画笔绘制东西来...

      这些天给同学讲了不少次JUI的 paint()方法和画笔,就目前而言已经比当初自己写的时候理解的多了不少了,虽然有点花时间,但好处还是有的。(习惯把Graphics g对象叫做画笔)
      以前想要在某个容器上用画笔绘制东西来做游戏,直接给主类继承JPanel,然后只是把paint()+repaint()当作线程来使,感觉就这么背下来了。然后当我再看这个paint方法的时候,隐约记得有个方法叫做获取对象的画笔,又看到里面传入了一根画笔参数,有点不对劲。当我尝试在别人写的一个继承JFrame类中的paint方法内,调用JPanel的画笔的时候,先用getGraphics获取到JPanel的画笔,然后我唯一能想到需要传递画笔的地方就是在paint方法里需要super调用一下父类的paint方法,大概就是这里把画笔传递过去然后画在JPanel上的吧?唔。。结果什么都没出来,看起来不是从这里传递的。目前为止还有一个疑点,就是我总是在用的这个paint方法究竟是谁调用的,在哪调用的。既然能够super到父类,肯定是父类中有这个方法。那意思就是我继承什么容器,调用的就是谁的paint方法了呗,是谁的paint方法那不就是在谁身上画了呗。那在当前对象身上画东西,在哪调用的呢?在哪传递的画笔呢?我赌了一把,在JFrame构造方法里显式调用了一下this.paint(),然后把我获取到的JPanel画笔传了进去,果然画出来东西了。这样来的话,意思就是在我之前写的方法中,有某个方法偷偷调用了this.paint(g),并且把当前对象的画笔传了进去吧,唯一能让我想到让东西显示出来的方法就是setVisible了,翻了几层父类关系,好像是在Component类中看到了repaint()方法,借此,我目前的理解就到这里了吧。
      除此之外,就我们平时使用的JContainer下的JFrame或者是JPanel而言,add方法可以为其加上自己的组件,之前我并没有在意过,组件究竟是怎么被加上去的。直到前两天有人问我,组件是加在JFrame之上的,而画笔也是把内容画在JFrame上。这之间的图层关系总是搞不懂,为什么画出来的东西会盖住之前加的组件呢?唯一的解释就是,组件看起来是被加上去的,实际上则是被JContainer里的paint()方法画在容器上的。所以一开始先加的组件,在paint()方法自动执行的时候,调用了super.paint(g)会被先画出来,然后再继续画自己想要的东西,就会盖住之前的组件了。这样的解释也正好能够迎合为什么组件内都会有个paintComponent方法,这个方法估计就是容器调用组件用来绘制自己的方法吧。而组件之间的绘制方法也有差距,类如JLabel本身无法获取焦点,如果paint()里不调用super.paint()似乎会出现无法正常显示的状况,有的人说我说的这种情况不对,不过我昨天所见识到的确实是这个样子。但是和JLabel相对的类似JButton的功能性的,总是能够在显示出来的时候获取到焦点,抑或者是鼠标从上面经过,会触发一些显示效果,都能触发他们的绘制方法,然后正常显示出来。但是继承了父类的paint之后,就都能正常显示了。
      懒得翻源码,瞎猜真有意思,就怕误人子弟啊,大家随便看看就行。

    展开全文
  • Android Paint的使用详解

    万次阅读 多人点赞 2016-06-22 18:02:15
    自定义控件具有很强的灵活性,可以根据你的想法画出各种各样的图案,在Android中如果是自定义控件的话,Paint这个类用的还是较多的,这一篇就来简单介绍Paint这个类的使用,先来看一下这个类的注释/** * The Paint ...

    尊重原创,转载请标明出处    http://blog.csdn.net/abcdef314159

    自定义控件具有很强的灵活性,可以根据你的想法画出各种各样的图案,在Android中如果是自定义控件的话,Paint这个类用的还是较多的,这一篇就来简单介绍Paint这个类的使用,先来看一下这个类的注释

    /**
     * The Paint class holds the style and color information about how to draw
     * geometries, text and bitmaps.
     */
    这个类可以画几何图形,文本和bitmap。由于这个类的native方法和@hide方法比较多,这里就挑一些在工作中可能常用到的方法来讲解。先来看一下Paint的style,共有3种

    Paint.Style.FILL:填充内部
    Paint.Style.FILL_AND_STROKE  :填充内部和描边
    Paint.Style.STROKE  :描边

    我们看一下效果


    FILL_AND_STROKE和FILL区别不是很大。在看一下Cap,也有3种类型,主要是线条的末端,为了直观,下面三个线条我设置的比较粗,我们看一下效果


    我们看一下,其中两条竖线是三条线条的坐标的起始点和终止点,区别很明显。再来看看Join,也是有3种类型,我们看一下


    这个是画的矩形,连接的时候用到的,效果很明显,就不在解释。再看下一个Align,也是有3种类型,看名字大概也能猜的出来,不过还是要来验证一下


    OK,Paint的几种类型已经演示完了,下面主要来看一下他的方法。

    //重置Paint。
    reset()

    //设置一些标志,比如抗锯齿,下划线等等。

    setFlags(int flags)

    //设置抗锯齿,如果不设置,加载位图的时候可能会出现锯齿状的边界,如果设置,边界就会变的稍微有点模糊,锯齿就看不到了。

    setAntiAlias(boolean aa)

    //设置是否抖动,如果不设置感觉就会有一些僵硬的线条,如果设置图像就会看的更柔和一些,

    setDither(boolean dither)

    //这个是文本缓存,设置线性文本,如果设置为true就不需要缓存,

    setLinearText(boolean linearText)

    //设置亚像素,是对文本的一种优化设置,可以让文字看起来更加清晰明显,可以参考一下PC端的控制面板-外观和个性化-调整ClearType文本

    setSubpixelText(boolean subpixelText)

    //设置文本的下划线

    setUnderlineText(boolean underlineText)

    //设置文本的删除线

    setStrikeThruText(boolean strikeThruText)

    //设置文本粗体

    setFakeBoldText(boolean fakeBoldText)

    //对位图进行滤波处理,如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示 

    setFilterBitmap(boolean filter)

    //下面这几个就不用说了,上面已经演示过

    setStyle(Style style),setStrokeCap(Cap cap),setStrokeJoin(Join join),setTextAlign(Align align),

    //设置画笔颜色

    setColor(int color)

    //设置画笔的透明度[0-255],0是完全透明,255是完全不透明

    setAlpha(int a)

    //设置画笔颜色,argb形式alpha,red,green,blue每个范围都是[0-255],

    setARGB(int a, int r, int g, int b)

    //画笔样式为空心时,设置空心画笔的宽度

    setStrokeWidth(float width)

    //当style为Stroke或StrokeAndFill时设置连接处的倾斜度,这个值必须大于0,看一下演示结果

    setStrokeMiter(float miter)

    左上角的没有设置setStrokeMiter,右上角setStrokeMiter(2.3f),左下角setStrokeMiter(1.7f),右下角setStrokeMiter(0f)


    //这个没整明白具体干什么用的

    getFillPath(Path src, Path dst)

    //设置着色器,用来给图像着色的,绘制出各种渐变效果,有BitmapShader,ComposeShader,LinearGradient,RadialGradient,SweepGradient几种,这个以后再单独讲

    setShader(Shader shader)

    //设置画笔颜色过滤器,有ColorMatrixColorFilter,LightingColorFilter,PorterDuffColorFilter几种,这个以后再单独分析

    setColorFilter(ColorFilter filter)

    //设置图形重叠时的显示方式,下面来演示一下

    setXfermode(Xfermode xfermode)

    下面是我运行目录D:\Android\adt-bundle-windows\sdk\samples\android-20\legacy\ApiDemos\src\com\example\android\apis\graphics\Xfermodes类的结果


    总共有16种重叠模式,而Mode类中显示的总共有18种,下面是我自己写的一个,只有绿色和红色两种图片(没有黑色),先画的是绿色,后画的是红色,和上面有很大差距,不知道什么原因,有时间得好好研究一下


    //设置绘制路径的效果,有ComposePathEffect,CornerPathEffect,DashPathEffect,DiscretePathEffect,PathDashPathEffect,SumPathEffect几种,以后在单独分析

    setPathEffect(PathEffect effect)

    //对图像进行一定的处理,实现滤镜的效果,如滤化,立体等,有BlurMaskFilter,EmbossMaskFilter几种

    setMaskFilter(MaskFilter maskfilter)

    //设置字体样式,可以是Typeface设置的样式,也可以通过Typeface的createFromAsset(AssetManager mgr, String path)方法加载样式

    setTypeface(Typeface typeface)

    //设置阴影效果,radius为阴影角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色 ,看一下演示效果,其中第一个是没有阴影的,第二个设置了黑色的阴影

    setShadowLayer(float radius, float dx, float dy, int shadowColor)


    //设置地理位置,比如显示中文,日文,韩文等,默认的显示Locale.getDefault()即可,

    setTextLocale(Locale locale)

    //设置优雅的文字高度,这个设置可能会对FontMetrics产生影响

    setElegantTextHeight(boolean elegant)

    //设置字体大小

    setTextSize(float textSize)

    //设置字体的水平方向的缩放因子,默认值为1,大于1时会沿X轴水平放大,小于1时会沿X轴水平缩小

    setTextScaleX(float scaleX)

    //设置文本在水平方向上的倾斜,默认值为0,推荐的值为-0.25,

    setTextSkewX(float skewX)

    //设置行的间距,默认值是0,负值行间距会收缩

    setLetterSpacing(float letterSpacing)

    //设置字体样式,可以设置CSS样式

    setFontFeatureSettings(String settings)

    //这个Paint的静态内部类,主要用于字体的高度,以后再分析

    FontMetrics

    //下面几个就是测量字体的长度了

    measureText(char[] text, int index, int count),measureText(String text, int start, int end),measureText(String text),measureText(CharSequence text, int start, int end)

    //下面这几个就是剪切显示,就是大于maxWidth的时候只截取指定长度的显示

    breakText(char[] text, int index, int count,float maxWidth, float[] measuredWidth),breakText(CharSequence text, int start, int end,boolean measureForwards,  floatmaxWidth, float[] measuredWidth),breakText(String text, boolean measureForwards,float maxWidth, float[] measuredWidth)

    //提取指定范围内的字符串,保存到widths中,

    getTextWidths(char[] text, int index, int count,float[] widths),getTextWidths(CharSequence text, int start, int end, float[] widths),getTextWidths(String text, int start, int end, float[] widths),getTextWidths(String text, float[] widths)

    //获取文本绘制的路径,提取到Path中,

    getTextPath(char[] text, int index, int count, float x, float y, Path path),getTextPath(String text, int start, int end, float x, float y, Path path)

    //得到文本的边界,上下左右,提取到bounds中,可以通过这计算文本的宽和高

    getTextBounds(String text, int start, int end, Rect bounds) ,getTextBounds(char[] text, int index, int count, Rect bounds)

    OK,剩下的一些就是@hide或是native,或者是get方法,这里就不在一一叙述。


    展开全文
  • Paint基本用法

    千次阅读 2017-03-06 10:03:17
    这篇只要记录Paint(画笔)一些基本用法 setARGB(设置画笔颜色和透明度) paint.setARGB(88,255,0,0); setARGB(int a, int r, int g, int b)取值都是0~255 setAlpha (int a)设置画笔透明度,取值0~255 ...
  • android paint类函数讲解(一)

    千次阅读 2018-05-24 10:23:44
    android paint类函数讲解(一)
  • Paint类介绍

    千次阅读 2014-05-22 17:45:30
    package eoe.Demo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color;...import android.graphics.Paint; import android.util.Log; import android.view.KeyEvent;
  • Android Paint.Style.?

    千次阅读 2018-02-21 11:51:37
    Paint.Style.FILL设置只绘制图形内容 Paint.Style.STROKE设置只绘制图形的边 Paint.Style.FILL_AND_STROKE设置都绘制 代码如下: mPaint = new Paint(); mPaint.setStrokeWidth(mWidth); mPaint.setColor...
  • 在自定义View中,这两个Paint.setAntiAlias()和Paint.setDither()方法用的很多,都只有一个boolean值,作用大家未必清楚,今天抽了点时间研究下,终于搞清楚了,希望给大家点帮助!Paint.setAntiAlias()该方法作用是...
  • 前言:厚积方能薄发 ...经过前几篇,我们基本把paint和canvas的基本用法就看完了,今天我们来个大汇总,列举一个paint的所有函数,然后一个一个的过。经过这几篇,你将能学会paint中所有处理函数的用法。 一...
  • Paint X for Mac破解教程

    万次阅读 2019-02-15 11:40:46
    Paint X for Mac(时尚绘图工具) 还在寻找一款专业的绘图工具吗?Paint X for Mac破解版以绘制、着色、编辑图片为主。可以像使用数位板一样使用Paint X制作简单的图片、创意项目、或者将文本和设计添加到您的其他...
  • Paint X for Mac(绘图软件) v4.5.3破解版

    千次阅读 2019-02-15 20:20:56
    Paint X for Mac破解版是一款时尚而简洁的绘图应用程序,以绘制、着色、编辑图片著称。您可以像使用数位板一样使用 Paint X 来制作简单的图片、创意项目、或者将文本和设计添加到您的其他图片中,例如使用数码相机...
  • 了这样几个东西:Paint.Style,Paint.Cap,Paint.Join等,这些都是Paint中的一些枚举值,相关 方法我们可以通过设置这些枚举值来设置特定效果比如:Style:画笔样式,Join图形结合方式等, 本节我们走进Paint的...
  • 图像化界面paint,repaint方法的总结

    千次阅读 多人点赞 2018-11-16 16:37:35
    JAVA 画图中出现的paint()函数 问题:小弟刚学JAVA,有一个问题。以下是一段JAVA代码,它弹出了一个窗口,并在窗口上使用paint()画出矩形、椭圆、扇面等图形。但鉴于paint()并不在main()中执行,所以它会一次画完。...
  • WM_paint详解

    2014-08-18 19:37:37
     ... 系统会在多个不同的时机发送WM_PAINT消息:当第一次创建一个窗口时,当改变窗口的大小时,当把窗口从另一个窗口背后移出时,当最大化或最小化窗口时,等等,这些动作都是由系统管理的,应
  • 深度分析WM_PAINT和WM_ERASEBKGND消息

    千次阅读 2015-11-25 17:10:00
    做windows开发这么久了,一直以来对WM_PAINT和WM_ERASEBKGND消息总是感觉理解的不准确,每次要自绘一个窗口都因为知其然不知其所以然,偶然发现一篇文章,详细透彻地分了这个两个消息的用途和设计初衷,这篇文章也是...
  • Paint 画笔的一些属性

    千次阅读 2016-10-20 11:54:45
    就是画笔,用于设置绘制风格,如:线宽(笔触粗细),颜色,透明度和填充风格等 直接使用无参构造方法就可以创建Paint实例: Paint paint = new Paint( ); 我们可以通过下述方法来设置Paint(画笔)的相关属性,另外,关于这个...
  • Android图像处理——Paint之ColorFilter

    万次阅读 2015-04-22 12:07:05
    平时在Android开发中,一般不太可能频繁使用到Paint——画笔。但是在某些特殊的情况下,例如 自定义控件(继承View)的时候,有时候就需要请出画笔在画布(Canvas,将下篇文章中讲述Canvas)上像“画”出我们想要的...
  • Android图像处理——Paint之Xfermode

    万次阅读 2015-04-24 09:30:57
    上篇博客中,我将我对Paint的ColorFilter相关的几个子类以及用法做了总结,其中最常用的ColorMatrixColorFilter值得我们多学习学习,通过定义一个color值的4*5的矩阵,来设置Paint的各种各样的变色效果。此外,还有...
1 2 3 4 5 ... 20
收藏数 140,276
精华内容 56,110
关键字:

paint