精华内容
下载资源
问答
  • Paint

    千次阅读 2015-12-31 15:12:43
    API—Paint | Android 开发者 Paint即画笔,用于设置绘制风格,如:线宽(笔触粗细),颜色,透明度和填充风格等, 大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。 嵌套类 Paint.Align ,设置字符位置,...

    Paint即画笔,用于设置绘制风格,如:线宽(笔触粗细),颜色,透明度和填充风格等,
    大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。

    1.图形绘制

    setARGB(int a,int r,int g,int b)设置绘制的颜色,a代表透明度,r,g,b代表颜色值这个不多说了,还有两个类似的方法,将设置alpha和rgb分割开来了。注意的是这里的a值是0~255的范围,不是小数。
    setAlpha(int a)设置绘制图形的透明度
    setColor(int color)设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。
    setAntiAlias(boolean aa)设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
    setDither(boolean dither)设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
    setFilterBitmap(boolean filter)如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示速度,本设置项依赖于ditherxfermode的设置
    setMaskFilter(MaskFilter maskfilter)设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等MaskFilter 介绍
    setColorFilter(ColorFilter colorfilter)设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果这个方法也值得试验一下:MaskFilter是对一个Paintalpha通道的转换,而ColorFilter则是对每一个RGB通道应用转换。所有由ColorFilter所派生的类在执行它们的转换时,都会忽略alpha通道。这个貌似比较麻烦,改天再说
    setPathEffect(PathEffect effect)设置绘制路径的效果,如点画线等又是一个很好玩的方法:到目前为止,所有的效应都会影响到Paint填充图像的方式;PathEffect是用来控制绘制轮廓(线条)的方式。PathEffect对于绘制Path基本图形特别有用,但是它们也可以应用到任何Paint中从而影响线条绘制的方式。使用PathEffect,可以改变一个形状的边角的外观并且控制轮廓的外表。Android包含了多个PathEffect,包括:1)CornerPathEffect 可以使用圆角来代替尖锐的角从而对基本图形的形状尖锐的边角进行平滑。2)DashPathEffect 可以使用DashPathEffect来创建一个虚线的轮廓(短横线/小圆点),而不是使用实线。你还可以指定任意的虚/实线段的重复模式。3) DiscretePathEffectDashPathEffect相似,但是添加了随机性。当绘制它的时候,需要指定每一段的长度和与原始路径的偏离度。4)PathDashPathEffect 这种效果可以定义一个新的形状(路径)并将其用作原始路径的轮廓标记。下面的效果可以在一个Paint中组合使用多个PathEffect。1)SumPathEffect 顺序地在一条路径中添加两种效果,这样每一种效果都可以应用到原始路径中,而且两种结果可以结合起来。2)ComposePathEffect 将两种效果组合起来应用,先使用第一种效果,然后在这种效果的基础上应用第二种效果。对象形状的PathEffect的改变会影响到形状的区域。这就能够保证应用到相同形状的填充效果将会绘制到新的边界中。使用setPathEffect方法可以把PathEffect应用到Paint对象中,如下所示:1 paint.setPathEffect(new CornerPathEffect(10));其他效果懒得测试了,这个在模拟器上跑的时候效果也不明显,但是真机上跑的时候的确圆滑了许多,看上去很舒服
    setShader(Shader shader)设置图像效果,使用Shader可以绘制出各种渐变效果
    setShadowLayer(float radius ,float dx,float dy,int color)在图形下面设置阴影层,产生阴影效果radius为阴影的角度,dxdy为阴影在x轴和y轴上的距离,color为阴影的颜色
    setStyle(Paint.Style style)设置画笔的样式,为FILL,FILL_OR_STROKE,或STROKE
    setStrokeCap(Paint.Cap cap)当画笔样式为STROKEFILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式Cap.ROUND,或方形样式Cap.SQUARE
    setSrokeJoin(Paint.Join join)设置绘制时各图形的结合方式,如平滑效果等
    setStrokeWidth(float width)当画笔样式为STROKEFILL_OR_STROKE时,设置笔刷的粗细度 ,单位为px
    setXfermode(Xfermode xfermode)设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果Xfermode 介绍

    2.文字绘制

    setFakeBoldText(boolean fakeBoldText)模拟实现粗体文字,设置在小字体上效果会非常差
    setSubpixelText(boolean subpixelText)设置该项为true,将有助于文本在LCD屏幕上的显示效果
    setTextAlign(Paint.Align align)设置绘制文字的对齐方向
    setTextScaleX(float scaleX)设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果
    setTextSize(float textSize)设置绘制文字的字号大小,单位为px
    setTextSkewX(float skewX)设置斜体文字,skewX为倾斜弧度
    setTypeface(Typeface typeface)设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等
    setUnderlineText(boolean underlineText)设置带有下划线的文字效果
    setStrikeThruText(boolean strikeThruText)设置带有删除线的效果

    嵌套类

    1. Paint.Align ,设置字符位置,字符以坐标(x,y)为源点。
    2. Paint.Cap,线段断点形状(默认Paint.Cap.BUTT):
    3. Paint.FontMetrics,字体属性及测量。
      如需详细了解,请参考:
      Paint—FontMetrics - qq_20198405的博客 - 博客频道 - CSDN.NET
    4. Paint.FontMetricsInt
    5. Paint.Join,设置结合处的样子。
    6. Paint.Style,设置空心(默认Paint.Style.FILL);

    常量

    标记说明
    ANTI_ALIAS_FLAG抗锯齿的标志
    DEV_KERN_TEXT_FLAG
    DITHER_FLAG使位图进行有利的抖动的位掩码标志
    FAKE_BOLD_TEXT_FLAG文本仿粗体的标志
    FILTER_BITMAP_FLAG使位图过滤的位掩码标志
    HINTING_OFF
    HINTING_ON
    LINEAR_TEXT_FLAG
    STRIKE_THRU_TEXT_FLAG文本删除线的标志
    SUBPIXEL_TEXT_FLAG
    UNDERLINE_TEXT_FLAG文字的下划线的标志

    构造方法

    Paint的构造方法有两种:

    Paint()Paint(int flags)Paint(Paint paint)

    setXXX()方法族:

    • set(Paint src):
      为当前画笔设置一个画笔,说白了就是把另一个画笔的属性设置Copy给我们的画笔。
    • setARGB(int a, int r, int g, int b):
      设置绘制的颜色,a代表透明度,r,g,b代表颜色值。
    • setAlpha(int a):
      设置绘制图形的透明度,设置范围是[0..255]。
    • setAntiAlias(boolean aa):
      消除锯齿(默认不消除锯齿)。
      不消除锯齿:
      这里写图片描述
      消除锯齿:
      这里写图片描述
    • setColor(int color):
      设置画笔颜色。
    • setColorFilter(ColorFilter filter):
      设置颜色过滤,这个方法需要我们传入一个ColorFilter参数同样也会返回一个ColorFilter实例。 如需详细了解,请参考:
      Paint—ColorFilter - qq_20198405的博客 - 博客频道 - CSDN.NET

    • setDither(boolean dither):
      设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
      这玩意用来设置我们在绘制图像时的抗抖动,也称为递色,那什么叫抗抖动呢?在Android中我确实不好拿出一个明显的例子,我就在PS里模拟说明一下:
      这里写图片描述
      大家看到的这张七彩渐变图是一张RGB565模式下图片,即便图片不是很大我们依然可以很清晰地看到在两种颜色交接的地方有一些色块之类的东西感觉很不柔和,因为在RGB模式下只能显示2^16=65535种色彩,因此很多丰富的色彩变化无法呈现,而Android呢为我们提供了抗抖动这么一个方法,它会将相邻像素之间颜色值进行一种“中和”以呈现一个更细腻的过渡色:
      这里写图片描述
      放大来看,其在很多相邻像素之间插入了一个“中间值”:
      这里写图片描述
      抗抖动不是Android的专利,是图形图像领域的一种解决位图精度的技术。

    • setFakeBoldText(boolean fakeBoldText):
      设置文本仿粗体。注意设置在小字体上效果会非常差。
    • setFilterBitmap(boolean filter):
      如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示速度,本设置项依赖于dither和xfermode的设置。
    • setFlags(int flags):
      设置标志,还是对paint进行样式的设置。比如
     // 实例化画笔并打开抗锯齿
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    • setHinting(int mode):
      设置画笔的隐藏模式。可以是 HINTING_OFF or HINTING_ON之一。
    • setLinearText(boolean linearText):
      设置是否打开线性文本标识,这玩意对大多数人来说都很奇怪不知道这玩意什么意思。想要明白这东西你要先知道文本在Android中是如何进行存储和计算的。在Android中文本的绘制需要使用一个bitmap作为单个字符的缓存,既然是缓存必定要使用一定的空间,我们可以通过setLinearText (true)告诉Android我们不需要这样的文本缓存。
    • setMaskFilter(MaskFilter maskfilter):
      这个方法可以用来对图像进行一定的处理,实现滤镜的效果,如滤化,立体等。 如需详细了解,请参考:
      Paint—MaskFilter(面具) - qq_20198405的博客 - 博客频道 - CSDN.NET

    • setPathEffect(PathEffect effect):设置绘制路径时的路径效果(ComposePathEffect, CornerPathEffect, DashPathEffect, DiscretePathEffect, PathDashPathEffect, SumPathEffect),如点画线等 。 如需详细了解,请参考:
      Paint—PathEffect(路径效果) - qq_20198405的博客 - 博客频道 - CSDN.NET

    • setRasterizer(Rasterizer rasterizer):
      设置光栅,光栅这东西涉及太多太多物理知识。该方法同样不支持HW在API 21中被遗弃了,所以不推荐使用。
    • setShader(Shader shader):
      设置画笔的填充效果(BitmapShader, ComposeShader, LinearGradient, RadialGradient, SweepGradient),使用Shader可以绘制出各种渐变效果。如需详细了解,请参考:
      Paint—Shader - qq_20198405的博客 - 博客频道 - CSDN.NET
    • setShadowLayer(float radius, float dx, float dy, int color):
      radius表示阴影的扩散半径;dx和dy表示阴影平面上的偏移值;shadowColor就不说了阴影颜色。
      注意: 这个方法不支持硬件加速,所以我们要测试时必须先关闭硬件加速。
    • setStrikeThruText(boolean strikeThruText):
      设置文本删除线。
    • setStrokeCap(Paint.Cap cap):
      设置线段断点形状(默认Paint.Cap.BUTT)
      Paint.Cap.BUTT : 不多不少
      这里写图片描述
      Paint.Cap.ROUND : 多了一个圆头
      这里写图片描述
      Paint.Cap.SQUARE:多了一个方头
      这里写图片描述
    • setStrokeJoin(Paint.Join join):
      设置画笔转弯处的连接风格(BEVEL-直线、MITER -锐角、ROUND-圆弧 )。
    • setStrokeMiter(float miter):
      设置画笔倾斜度。
    • setStrokeWidth(float width):
      当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度。
    • setStyle(Paint.Style style):
      设置空心(默认Paint.Style.FILL)
      Paint.Style.FILL :填充内部
      这里写图片描述
      Paint.Style.STROKE :仅描边
      这里写图片描述
      Paint.Style.FILL_AND_STROKE :填充内部和描边
      这里写图片描述
      再来一张更详细的图:
      这里写图片描述
    • setSubpixelText(boolean subpixelText):
      设置自像素。如果该项为true,将有助于文本在LCD屏幕上的显示效果。
    • setTextAlign(Paint.Align align):
      设置字符位置,字符以坐标(x,y)为源点。

    center表示字符在水平方向上以x中心向左右两边延伸,在垂直方向以y为起点向下延伸;
    left表示字符在水平方向上以x为起点向右延伸,在垂直方向上以y为起点向下延伸;
    right表示字符在水平方向上以x为起点向左延伸,在垂直方向上以y为起点向下延伸。
    这里写图片描述

    • setTextLocale(Locale locale):
      设置地理位置,这里如果你要使用,直接传入Locale.getDefault()即可。它用来设置文本的区域比如中文、日文等。
    • setTextScaleX(float scaleX):
      设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果。
    • setTextSize(float textSize):
      设置绘制文字的字号大小。
    • setTextSkewX(float skewX):
      设置斜体文字,skewX为倾斜弧度。这个倾斜值没有具体的范围,但是官方推崇的值为-0.25可以得到比较好的倾斜文本效果,值为负右倾值为正左倾,默认值为0。
    • setTypeface(Typeface typeface):
      设置字体类型和样式,上面我们也使用过,Android中字体有四种样式:BOLD(加粗),BOLD_ITALIC(加粗并倾斜),ITALIC(倾斜),NORMAL(正常);而其为我们提供的字体有五种:DEFAULT,DEFAULT_BOLD,MONOSPACE,SANS_SERIFSERIF,这些什么类型啊、字体啊之类的都很简单大家自己去试试就知道就不多说了。 如需详细了解,请参考:
      Paint—Typeface - qq_20198405的博客 - 博客频道 - CSDN.NET
    • setUnderlineText(boolean underlineText):
      设置文字的下划线。
    • setXfermode(Xfermode xfermode):
      设置图像的混合模式,详细使用方式请参考:
      Paint—PorterDuffXfermode - qq_20198405的博客 - 博客频道 - CSDN.NET
      Paint—Xfermode、 PixelXorXfermode - qq_20198405的博客 - 博客频道 - CSDN.NET

    getXXX()方法族:

    • getAlpha()
    • getColor()
    • getColorFilter()
    • getFillPath(Path src, Path dst)
    • getFlags()
    • getFontMetrics(Paint.FontMetrics metrics):
      这个和我们之前用到的getFontMetrics()相比多了个参数,getFontMetrics()返回的是FontMetrics对象,而getFontMetrics(Paint.FontMetrics metrics)返回的是文本的行间距,如果metrics的值不为空则返回FontMetrics对象的值。
    • getFontMetrics():得到一个FontMetrics对象,返回对象中的参数都是float。
    • getFontMetricsInt():返回对象中的参数都是int。
    • getFontMetricsInt(Paint.FontMetricsInt fmi)
    • getFontSpacing():返回字符行间距。
    • getHinting()
    • getMaskFilter()
    • getPathEffect()
    • getRasterizer()
    • getShader()
    • getStrokeCap()
    • getStrokeJoin()
    • getStrokeMiter()
    • getStrokeWidth()
    • getStyle()
    • getTextAlign()
    • getTextBounds(char[] text, int index, int count, Rect bounds)
    • getTextBounds(String text, int start, int end, Rect bounds)
    • getTextLocale()
    • getTextPath(String text, int start, int end, float x, float y, Path path)
    • getTextPath(char[] text, int index, int count, float x, float y, Path path)
    • getTextScaleX()
    • getTextSize()
    • getTextSkewX()
    • getTextWidths(String text, float[] widths)
    • getTextWidths(CharSequence text, int start, int end, float[] widths)
    • getTextWidths(String text, int start, int end, float[] widths)
    • getTextWidths(char[] text, int index, int count, float[] widths)
    • getTypeface()
    • getXfermode()

    isXXX()方法族:

    • isAntiAlias()
    • isDither()
    • isFakeBoldText()
    • isFilterBitmap()
    • isLinearText()
    • isStrikeThruText()
    • isSubpixelText()
    • isUnderlineText()

    其他方法:

    • ascent():返回上坡度的值。
    • descent():返回下坡度的值。
    • clearShadowLayer()

    • breakText(CharSequence text, int start, int end, boolean
      measureForwards, float maxWidth, float[] measuredWidth)

    • breakText(String text, boolean measureForwards, float maxWidth,
      float[] measuredWidth)
    • breakText(char[] text, int index, int count, float maxWidth, float[]
      measuredWidth)

      • 这三个方法让我们设置一个最大宽度,在不超过这个宽度的范围内返回实际测量值否则停止测量。
    text 表示我们的字符串;
    start 表示从第几个字符串开始测量;
    end 表示从测量到第几个字符串为止;
    measureForwards 表示向前还是向后测量;
    maxWidth 表示一个给定的最大宽度在这个宽度内能测量出几个字符;
    measuredWidth 为一个可选项,可以为空,不为空时返回真实的测量值

    这些方法在一些结合文本处理的应用里比较常用,比如文本阅读器的翻页效果,我们需要在翻页的时候动态折断或生成一行字符串,这就派上用场了~

    • measureText(String text)
    • measureText(CharSequence text, int start, int end)
    • measureText(String text, int start, int end)
    • measureText(char[] text, int index, int count)
      • 测量文本宽度,上面我们已经使用过了,这四个方法都是一样的只是参数稍有不同罢了。
    • reset()::恢复画笔到默认配置。

    源码下载
    ApiDemo下载
    博客中用到的网格插件

    引用:
    Android画图Path的使用 - tt_mc - 博客园
    (转)【Android】Paint的效果研究 - wpf814533631 - ITeye技术网站
    自定义控件其实很简单1/4 - AigeStudio - 博客频道 - CSDN.NET
    android paint cap join 理解 图示 - Android移动开发技术文章_手机开发 - 红黑联盟
    android Graphics(一):概述及基本几何图形绘制 - harvic - 博客频道 - CSDN.NET
    Android笔记二十八.Android绘图深度解析-android-爱编程
    用TextPaint来绘制文字 - developer_Kale - 博客园

    其他:
    详解Paint的各种set方法 - 推酷

    展开全文
  • My_Paint:复制到Paint en ReactJS
  • XP Paint是Windows XP的MS Paint的基于Web的版本。它是JS Paint的一个分支,具有以下区别: 它自包含在单个.html文件中(大小约为1 MB)。 脱机完全可用。 它从JS Paint中删除了许多实际Windows XP MS Paint中没有...
  • 在线MS Paint是经典的Windows应用程序,可用作在线图像/照片编辑器,绘图和绘画工具 在线MS Paint-图像编辑器和Paint Tool是经典和最受欢迎的Microsoft桌面绘图和绘画应用程序MS Paint的在线版本。 您可以在此扩展上...
  • Car Paint Shaders Asset

    2018-02-26 09:29:06
    Car Paint Shaders Asset unity Car Paint Shaders Asset unity
  • paint进阶

    千次阅读 2016-05-11 15:34:37
    概述paint的基本绘制方法已经在前面的基本图形绘制中讲解了,这里做的是进阶讲解,讲解paint的一些进阶方法。例如:setStrokeCap,setStrokeJoin,setPathEffect等。PathDashPathEffect,DiscretePathEffect,...

    概述

    paint的基本绘制方法已经在前面的基本图形绘制中讲解了,这里做的是进阶讲解,讲解paint的一些进阶方法。例如:setStrokeCap,setStrokeJoin,setPathEffect等。

    1. setStrokeCap(Paint.Cap cap)

    cap是帽子的意思,这里的意思是设置线帽子,什么是线帽呢,就是一个线段结束后的额外部分。先来看一张图:

    这里写图片描述

    这里明显看出第二和第三段线段比第一段要长,这是因为设置的线帽不同导致的。

    他们传入的参数分别是:

    BUTT    (0),//无线帽
    ROUND   (1),//圆形线帽
    SQUARE  (2);//方形线帽

    代码如下:

    Paint paint = new Paint();
    paint.setColor(Color.BLUE);
    paint.setStrokeWidth(50);
    
    paint.setStrokeCap(Paint.Cap.BUTT);
    canvas.drawLine(100, 100, 800, 100, paint);
    
    paint.setStrokeCap(Paint.Cap.ROUND);
    canvas.drawLine(100, 300, 800, 300, paint);
    
    paint.setStrokeCap(Paint.Cap.SQUARE);
    canvas.drawLine(100, 500, 800, 500, paint);

    代码比较好理解,不再讲解。

    2.setStrokeJoin(Paint.Join join)

    从join处可以知道,这里设置的是线段的连接处的样式,那么Join有哪些呢,如下:

    MITER   (0),//锐角连接
    ROUND   (1),//圆弧连接
    BEVEL   (2);//斜接(把锐角替换成斜边)

    看一张图:

    这里写图片描述

    3个线段所代表的意义和上面的列举的参数顺序相同。可以清晰看出区别。

    代码如下:

    Paint paint = new Paint();
    paint.setStyle(Paint.Style.STROKE);
    paint.setColor(Color.BLUE);
    paint.setStrokeWidth(50);
    
    Path path = new Path();
    
    path.moveTo(100, 100);
    path.rLineTo(800, 0);
    path.rLineTo(0, 200);
    paint.setStrokeJoin(Paint.Join.MITER);
    canvas.drawPath(path, paint);
    
    paint.setStrokeJoin(Paint.Join.ROUND);
    path.moveTo(100, 500);
    path.rLineTo(800, 0);
    path.rLineTo(0, 200);
    canvas.drawPath(path, paint);
    
    paint.setStrokeJoin(Paint.Join.BEVEL);
    path.moveTo(100, 1000);
    path.rLineTo(800, 0);
    path.rLineTo(0, 200);
    canvas.drawPath(path, paint);

    3. setPathEffect(PathEffect effect)

    effect代表效果,这里明显是要设置路径的效果。那么我们先看看PathEffect有哪些子类呢

    这里写图片描述

    如图,子类有如上6种,那么逐个来解析他们对绘制的影响。

    (1)CornerPathEffect

    从名字可以看出,这个类主要作用于拐角,我们使用并看一下效果图:

    这里写图片描述

    下面的线条使用了这个效果,上面的是原始效果,可以看到,线条拐角处被处理成了圆弧。看下代码:

    path.moveTo(100, 100);
    path.rLineTo(500, 500);
    path.rLineTo(500, -500);
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 500);
    path.rLineTo(500, 500);
    path.rLineTo(500, -500);
    paint.setPathEffect(new CornerPathEffect(100));
    canvas.drawPath(path, paint);

    主要的在于

    paint.setPathEffect(new CornerPathEffect(100));
    

    看看构造函数

    public CornerPathEffect(float radius)
    

    参数radius代表了半径,这里的半径就是塞进拐角处圆形的半径,即是用多大半径的圆弧来替换这个拐角。

    (2)DashPathEffect

    dash line就是虚线的意思,所以这里可以看出,这个类主要是产生虚线效果。
    效果图如下:

    这里写图片描述

    图中第一个线段是默认线段,没有使用效果,第二个和第三个使用了,可以看到,他们是虚线。那么二三主要的不同在于他们的相位差,可以看到二三线段的起始位置上,有所不同。先看看该类的构造函数:

    public DashPathEffect(float intervals[], float phase)
    

    其中intervals是间隔,他是一个数组,其中数值必须为偶数,2个为一对,必须成对出现,一对中的第一个代表了线段长度(为0则绘制),第二个代表了空白长度(为0则不留空白)这里可以看出来其实线段2中是由两对数值组成的值如下:

    float[] intervals = {100,20,200,50};
    

    参数中phase代表了相位,线段2为0,代表不移动,线段3为300,移动了300像素。

    代码如下:

    float[] intervals = {100,20,200,50};
    
    path.moveTo(100, 100);
    path.rLineTo(500, 500);
    path.rLineTo(500, -500);
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 500);
    path.rLineTo(500, 500);
    path.rLineTo(500, -500);
    paint.setPathEffect(new DashPathEffect(intervals, 0));
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 900);
    path.rLineTo(500, 500);
    path.rLineTo(500, -500);
    paint.setPathEffect(new DashPathEffect(intervals, 300));
    canvas.drawPath(path, paint);
    (3)DiscretePathEffect

    discrete意思为离散,这里可能不太好理解,因此直接上图:

    这里写图片描述

    线条看起来很凌乱,其实离散就是干这个。先看看构造函数:

    public DiscretePathEffect(float segmentLength, float deviation)
    

    这里有两个参数,第一个segmentLength字面上看就是段长,deviation代表偏差值。
    参数一:指定了原始线段被切分成多长的线段,比如原始线段长度为100.段长设置为20,那么就被切成了5段。

    参数二:指定了切割后的小线段于原始位置的偏离距离。

    现在看下代码:

    path.moveTo(100, 100);
    path.rLineTo(500, 500);
    path.rLineTo(500, -500);
    paint.setPathEffect(new DiscretePathEffect(5,5));
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 500);
    path.rLineTo(500, 500);
    path.rLineTo(500, -500);
    paint.setPathEffect(new DiscretePathEffect(20,5));
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 900);
    path.rLineTo(500, 500);
    path.rLineTo(500, -500);
    paint.setPathEffect(new DiscretePathEffect(5, 20));
    canvas.drawPath(path, paint);
    (4)PathDashPathEffect

    印章效果,这里先看下效果图:

    这里写图片描述

    第一个线条没有做处理,后面三个使用了这个效果。

    看下构造函数:

    public PathDashPathEffect(Path shape, float advance, float phase,Style style)
    

    shape:代表了绘制的形状,这里是一个三角形
    advace:绘制位移,上一次绘制这个三角形,和下一次绘制三角形起点之间的位移
    phase:相位,于之前讲解的相同
    style:风格,这里后面三条线就是因为这个参数引起的不同

    Style是一个枚举,值如下

    TRANSLATE(0),   //平移
    ROTATE(1),      //旋转
    MORPH(2);       //变形

    这个参数主要控制了线条在转折时候的风格,这里列举的风格和图上的顺序一直。

    代码如下:

    pathDash.moveTo(20, 0);
    pathDash.rLineTo(20,20);
    pathDash.rLineTo(-40,0);
    pathDash.close();
    
    path.moveTo(100, 100);
    path.rLineTo(500, 200);
    path.rLineTo(500, -200);
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 300);
    path.rLineTo(500, 200);
    path.rLineTo(500, -200);
    paint.setPathEffect(new PathDashPathEffect(pathDash,35,0, PathDashPathEffect.Style.TRANSLATE));
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 500);
    path.rLineTo(500, 200);
    path.rLineTo(500, -200);
    paint.setPathEffect(new PathDashPathEffect(pathDash,35,0, PathDashPathEffect.Style.ROTATE));
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 700);
    path.rLineTo(500, 200);
    path.rLineTo(500, -200);
    paint.setPathEffect(new PathDashPathEffect(pathDash,35,0, PathDashPathEffect.Style.MORPH));
    canvas.drawPath(path, paint);
    (5)ComposePathEffect和SumPathEffect

    compose组合,sum总和,在这里有什么区别呢,同样的先来看图:

    这里写图片描述

    线段2是compose,线段3是sum,看图就已经非常明显,sum只是简单的叠加效果,而compose是组合效果。

    代码如下:

    Path path = new Path();
    float[] intervals = {100, 20};
    DashPathEffect dashPathEffect = new DashPathEffect(intervals, 0);
    CornerPathEffect cornerPathEffect = new CornerPathEffect(200);
    
    path.moveTo(100, 100);
    path.rLineTo(500, 200);
    path.rLineTo(500, -200);
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 300);
    path.rLineTo(500, 200);
    path.rLineTo(500, -200);
    paint.setPathEffect(new ComposePathEffect(dashPathEffect, cornerPathEffect));
    canvas.drawPath(path, paint);
    
    path.reset();
    path.moveTo(100, 500);
    path.rLineTo(500, 200);
    path.rLineTo(500, -200);
    paint.setPathEffect(new SumPathEffect(dashPathEffect, cornerPathEffect));
    canvas.drawPath(path, paint);

    4. setSubpixelText(boolean subpixelText)

    这个方法用来开启次像素,让字体更加平滑。次像素是软件通过计算得出的一种像素,是用来缓冲真实像素的边界的。

    这里写图片描述

    下面开启了,上面没开启,看起来差别不大。

    展开全文
  • Paint.NET+CodeLab.zip

    2019-06-19 11:07:18
    包含的文件有paint.net.4.1.6.install.exe和InstallCodeLab402_For_Paint.NET_v4.1.6+.exe。 Paint.NET为一个简洁版的windows下的画图软件,是简化版本的PS软件。 CodeLab则为Paint.NET的一个插件,通过它可以使用C#...
  • paint.net3.36源码.zip

    2020-12-03 08:24:56
    paint.net3.36源码 vs2017完美运行 亲测可用
  • Android代码-Tux Paint

    2019-08-06 02:29:19
    Tux Paint-Android This is Tux Paint on Android. Background Tux Paint has been ported from SDL1 to SDL2. Thus Tux Paint-Android will try to port current Tux Paint to Android platform. At the start this...
  • paint.net 源码

    热门讨论 2013-06-25 16:15:58
    此为paint.net-3.36的源码,修改了其在VS2010下不能编译的问题,有 需要的可以下载。如有疑问请联系QQ:78499261.
  • MFC draw paint gdi

    2013-03-05 08:51:53
    MFC draw paint gdi 很好用 MFC draw paint gdi MFC draw paint gdi
  • canvas、paint绘图

    2016-09-13 09:59:43
    android中canvas、paint绘图,主要用于学习canvas、paint绘图
  • paint.net3.36

    2013-08-16 21:49:43
    paint.net 3.36 debug编译注意添加命令行参数/skipRepairAttempt 在readme有写,虽然编译会报三个错,我也不知道怎么消除,但是可以启动
  • Paint 全面解析

    千次阅读 2017-06-20 14:40:44
    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;
                }
            }
    
        }
    }

    这里写图片描述

    展开全文
  • 好吧,此应用程序可以增强MS Paint的性能,并且只需单击几下鼠标按钮,并且仅文本来自MS Paint,即可让MS Paint高亮显示,编译和执行代码。 现在,它比Word,Notepad和Eclipse等实用得多。 产品特点 在过去的一年中...
  • WM_PAINT 消息

    2016-08-06 13:38:52
    对 MSDN 上 WM_PAINT 消息的详细翻译。 隶属于 Platform SDK Windows GDI 绘图消息。 后续会更新别消息-对MSDN的翻译。
  • android Paint

    千次阅读 2018-08-10 11:30:14
    Paint的style,共有3种 Paint.Style.FILL:填充内部 Paint.Style.FILL_AND_STROKE :填充内部和描边 Paint.Style.STROKE :描边 Paint的Cap,也有3种类型 Paint的Join,也有3种类型 Paint的Align,也有三...

    1.这个类可以画几何图形,文本和bitmap。

    Paint的style,共有3种

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

    Paint的Cap,也有3种类型

    这里写图片描述

    Paint的Join,也有3种类型

    这里写图片描述

    Paint的Align,也有三种类型

    这里写图片描述

    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)

    这里写图片描述

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

    setShader(Shader shader)

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

    setColorFilter(ColorFilter filter)

    //设置图形重叠时的显示方式

    setXfermode(Xfermode xfermode)

    //设置绘制路径的效果,有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方法

    千次阅读 2016-08-04 08:26:26
    在云课堂里面看到这么个小游戏项目,着手自己做的时候,却出现了问题,理由是我怎么也无法调用出paint()方法,后来经过网友与室友的帮助下,我逐渐理解了paint()方法的“调用”。 package liu.shen.util; ...
  • paint初始化地时候是这么设置的: paint.setStyle(Paint.Style.STROKE); 别的地方也没有对paint继续style的设置 但是在drawPath的过程中被设置成Fill 这种状况很不确定(部分机子会出现) 不知道是为什么 求解
  • 在自定义View中,这两个Paint.setAntiAlias()和Paint.setDither()方法用的很多,都只有一个boolean值,作用大家未必清楚,今天抽了点时间研究下,终于搞清楚了,希望给大家点帮助!Paint.setAntiAlias()该方法作用是...
  • Paint基本用法

    千次阅读 2017-06-01 10:29:55
    Paint基本使用: Paint基本的方法主要可以抽象成两大类:   1.1 负责设置获取图形绘制、路径相关的 1.setStyle(Paint.Style style)  设置画笔样式,取值有 Paint.Style.FILL :填充内部 Paint.Style.FILL_...
  • 使用paint动态画圆弧

    2015-12-17 18:00:43
    使用paint方法画圆弧,以及逐步改变百分比,以及代码的详解
  • Paint的用法

    千次阅读 2017-04-06 16:52:06
    转自:http://blog.csdn.net/duguang77/article/details/40716921 (一)获取Paint [java] ...Paint paint = new Paint();  (二)Paint的API [java] view plain copy
  • Easy_Paint_Tool_SAI教程Easy_Paint_Tool_SAI教程Easy_Paint_Tool_SAI教程Easy_Paint_Tool_SAI教程
  • FANUC Paint Robots工业机器人样本pdf,FANUC Paint Robots工业机器人样本
  • paint是事件onpaint方法onpaint方法是调用paint事件的,用哪一个,效果是一样,就看那一个方便了内部是这样实现的:
  • Paint类解析

    千次阅读 2016-09-09 12:07:08
    在自定义组件中,Paint类是一个很重要的类,主要包含颜色、文本、图形样式、位图模式、滤镜等几个方面。Paint类的相关方法如下: 1、颜色是指绘图时使用的颜色,在 Android 中颜色可以指定透明度,使用 16 进制来...
  • 优动漫PAINT也就是我们常说的clip studio paint(CSP)的中文版本,它是一款功能强大的漫画、插画绘制软件,所有动漫和漫画插件使用帮助你更加便捷的创作有质量的二次元素材,是各位喜欢动漫创作不可或缺的制作软件...
  • Java 重写paint绘图

    千次阅读 2019-06-09 16:20:39
    这个方法需要注意的地方不多,也就是重写时,先调用 super.paint(g) 方法 paint方法不需要编写代码调用,只需要重写。 其他看jdk帮助中就行了。 public void paint(Graphics g) { super.paint(g);// 调用父类的paint...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 172,253
精华内容 68,901
关键字:

paint