欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android绘图之Paint的使用方法详解

程序员文章站 2022-07-11 17:48:57
前言 大家都知道在android中,自定义控件是一个非常重要的知识点,而自定义控件对android开发者是一个难点,考验开发人员对view原理的理解,对于继承view的自...

前言

大家都知道在android中,自定义控件是一个非常重要的知识点,而自定义控件对android开发者是一个难点,考验开发人员对view原理的理解,对于继承view的自定义控件,一般都需要重写ondraw方法,而且往往需要开发人员能够掌握paint这个类。

简介

the paint class holds the style and color information about how to draw geometries, text and bitmaps.

paint:该类保存了绘制几何图形、文本和位图的样式和颜色信息。也就是说我们可以使用paint保存的样式和颜色,来绘制图形、文本和bitmap,这就是paint的强大之处。接下来我们使用paint来绘图,并且看看该类有哪些样式和颜色。

paint的使用

使用paint之前需要初始化

mpaint = new paint();

设置笔(paint)的颜色和alpha值:

mpaint.setcolor(color.blue);
mpaint.setalpha(255);

注意:alpha的范围是[0..255],而不是[0..1],是一个int值。

设置画笔的样式:通过mpaint.setstyle()来设置样式。

 public enum style {
 /**
  * geometry and text drawn with this style will be filled, ignoring all
  * stroke-related settings in the paint.
  */
 fill  (0),
 /**
  * geometry and text drawn with this style will be stroked, respecting
  * the stroke-related fields on the paint.
  */
 stroke  (1),
 /**
  * geometry and text drawn with this style will be both filled and
  * stroked at the same time, respecting the stroke-related fields on
  * the paint. this mode can give unexpected results if the geometry
  * is oriented counter-clockwise. this restriction does not apply to
  * either fill or stroke.
  */
 fill_and_stroke (2);

 style(int nativeint) {
  this.nativeint = nativeint;
 }
 final int nativeint;
 }

总共有三种画笔的样式

fill:填充内容;

stroke:描边;

fill_and_stroke:填充内容并描边。

设置画笔的宽度

mpaint.setstrokewidth(50);

设置画笔的线帽

通过mpaint.setstrokecap来设置线帽,总共有三种线帽

 /**
 * the cap specifies the treatment for the beginning and ending of
 * stroked lines and paths. the default is butt.
 */
 public enum cap {
 /**
  * the stroke ends with the path, and does not project beyond it.
  */
 butt (0),
 /**
  * the stroke projects out as a semicircle, with the center at the
  * end of the path.
  */
 round (1),
 /**
  * the stroke projects out as a square, with the center at the end
  * of the path.
  */
 square (2);

 private cap(int nativeint) {
  this.nativeint = nativeint;
 }
 final int nativeint;
 }

butt:没有线帽,默认模式

round:圆形

square:方形

三种线帽对比:

 @override
 protected void ondraw(canvas canvas) {
 super.ondraw(canvas);
 mpaint.setcolor(color.blue);
 mpaint.setalpha(255);

 //设置画笔的样式
 mpaint.setstyle(paint.style.fill_and_stroke);
 //画笔的宽度
 mpaint.setstrokewidth(50);
 mpaint.setstrokecap(paint.cap.square);//方形
 mpaint.setstrokejoin(paint.join.bevel);//直线

 path path = new path();
 path.moveto(100, 100);
 path.lineto(300, 100);
 canvas.drawpath(path, mpaint);

 mpaint.reset();//重置
 mpaint.setcolor(color.red);
 mpaint.setstyle(paint.style.fill_and_stroke);
 mpaint.setstrokewidth(50);
 mpaint.setstrokecap(paint.cap.round);//圆形
 mpaint.setstrokejoin(paint.join.bevel);//直线

 path path1 = new path();
 path1.moveto(100, 200);
 path1.lineto(300, 200);
 canvas.drawpath(path1, mpaint);

 mpaint.reset();//重置
 mpaint.setcolor(color.green);
 mpaint.setstyle(paint.style.fill_and_stroke);
 mpaint.setstrokewidth(50);
 mpaint.setstrokecap(paint.cap.butt);//没有
 mpaint.setstrokejoin(paint.join.bevel);//直线

 path path2 = new path();
 path2.moveto(100, 300);
 path2.lineto(300, 300);
 canvas.drawpath(path2, mpaint);

 }

上面代码中有个重置画笔,这时候需要重新设置画笔。

Android绘图之Paint的使用方法详解
线帽对比

设置join

使用setstrokejoin方法来设置join,join有三种类型:

bevel:直线

round:圆角

miter:锐角

 @override
 protected void ondraw(canvas canvas) {
 super.ondraw(canvas);
 mpaint.setcolor(color.blue);
 mpaint.setalpha(255);
 mpaint.setstyle(paint.style.stroke);//设置画笔的样式
 mpaint.setstrokewidth(50);//画笔的宽度
 mpaint.setstrokecap(paint.cap.butt);//线帽
 mpaint.setstrokejoin(paint.join.bevel);

 path path = new path();
 path.moveto(100, 100);
 path.lineto(300, 100);
 path.lineto(100, 300);
 path.close();
 canvas.drawpath(path, mpaint);

 mpaint.reset();//重置
 mpaint.setcolor(color.red);
 mpaint.setstyle(paint.style.fill_and_stroke);
 mpaint.setstrokewidth(50);
 mpaint.setstrokecap(paint.cap.butt);//圆形
 mpaint.setstrokejoin(paint.join.round);//圆弧

 path path1 = new path();
 path1.moveto(100, 400);
 path1.lineto(300, 400);
 path1.lineto(100, 700);
 path1.close();
 canvas.drawpath(path1, mpaint);

 mpaint.reset();//重置
 mpaint.setcolor(color.green);
 mpaint.setstyle(paint.style.fill_and_stroke);
 mpaint.setstrokewidth(50);
 mpaint.setstrokecap(paint.cap.butt);//没有
 mpaint.setstrokejoin(paint.join.miter);//锐角

 path path2 = new path();
 path2.moveto(100, 800);
 path2.lineto(300, 800);
 path2.lineto(100, 1100);
 path2.close();
 canvas.drawpath(path2, mpaint);

 }

Android绘图之Paint的使用方法详解

join对比

以上就是join三种类型对比。

设置防锯齿

mpaint.setantialias(true);

如果设置防锯齿,会损失一定的性能

抖动处理

使用mpaint.setdither()方法,设置是否使用图像抖动处理。会使绘制的图片等颜色更加的清晰以及饱满,也是损失性能。

使用path绘制图形

Android绘图之Paint的使用方法详解
path绘制图形

点组成线,线组成面,这样path可以绘制各种各样的图形,可以说是无所不能的了,但是path也提供了很多方法,来绘制图形。

文本绘制

上文中,介绍了paint画笔,和绘制了一些图形。但是介绍paint的时候,我们知道它可以绘制图形,文本和bitmap,所以paint是非常强大的了,我们看下paint是如何绘制文本的。

设置字符之间的间距

setletterspacing

设置文本删除线

mpaint.setstrikethrutext(true);

是否设置下划线

mpaint.setunderlinetext(true);

设置文本大小

mpaint.settextsize(textsize);

设置字体类型

mpaint.settypeface(typeface.bold);
// style
public static final int normal = 0;//常规
public static final int bold = 1;//粗体
public static final int italic = 2; //斜体
public static final int bold_italic = 3;//粗斜体

字体类型有以上四种类型可以设置。

加载自定义字体

typeface.create(familyname, style)

文字倾斜

mpaint.settextskewx(-0.25f);

文字倾斜默认为0,官方推荐的-0.25f是斜体

文本对齐方式

mpaint.settextalign(align.left)

有三种:

public enum align {
  /**
   * the text is drawn to the right of the x,y origin
   */
  left (0),//左对齐
  /**
   * the text is drawn centered horizontally on the x,y origin
   */
  center (1),//居中
  /**
   * the text is drawn to the left of the x,y origin
   */
  right (2);//右对齐

  private align(int nativeint) {
   this.nativeint = nativeint;
  }
  final int nativeint;
 }

计算制定长度的字符串

int breadtext = mpaint.breaktext(text, measureforwards, maxwidth, measuredwidth)

注意:字符长度、字符个数、显示的时候是真实的长度

rect bounds获取文本的矩形区域(宽高)
mpaint.gettextbounds(text, index, count, bounds)
mpaint.gettextbounds(text, start, end, bounds)
  
//获取文本的宽度,和上面类似,但是是一个比较粗略的结果
float measuretext = mpaint.measuretext(str);
//获取文本的宽度,和上面类似,但是是比较精准的。
float[] measuredwidth = new float[10];

//measuredwidth得到每一个字符的宽度;textwidths字符数
int textwidths = mpaint.gettextwidths(str, measuredwidth);
mpaint.gettextwidths(text, start, end, widths)

使用drawtext绘制文本

public class paintview extends view {

 private paint mpaint;
 private string text = "你是我世界之光,我心另一半";

 public paintview(context context) {
  this(context,null);
 }

 public paintview(context context, @nullable attributeset attrs) {
  this(context, attrs,0);
 }

 public paintview(context context, @nullable attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  init(context, attrs, defstyleattr);
 }

 private void init(context context, attributeset attrs, int defstyleattr) {
  mpaint = new paint();
 }


 @override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  mpaint.setcolor(color.blue);
  mpaint.setstyle(paint.style.stroke);//设置画笔的样式
  mpaint.setstrokecap(paint.cap.butt);//线帽
  mpaint.setstrokejoin(paint.join.bevel);

  int top = 100;
  int baselinex = 0;
  mpaint.settextsize(50);
  mpaint.settextalign(paint.align.left);

  canvas.drawline(0, top, 2000, top, mpaint);


  //文本metrics
  paint.fontmetrics fontmetrics = mpaint.getfontmetrics();
  float baseliney = top - fontmetrics.top;
  canvas.drawtext(text, baselinex, baseliney, mpaint);

 }
}

Android绘图之Paint的使用方法详解

绘制文本

绘制文本时,还有一个很重要的知识点就是基线的确定

drawtext 基线的确定

在自定义控件的时候,有时候会用到drawtext 方法.

先把自定义textview的贴出来

@override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);

  int x = getpaddingleft();

  //dy 代表的是:高度的一半到 baseline的距离
  paint.fontmetricsint fontmetrics = paint.getfontmetricsint();
  // top 是一个负值 bottom 是一个正值 top,bttom的值代表是 bottom是baseline到文字底部的距离(正值)
  // 必须要清楚的,可以自己打印就好
  int dy = (fontmetrics.bottom - fontmetrics.top)/2 - fontmetrics.bottom;
  int baseline = getheight()/2 + dy;

  canvas.drawtext(costom_text,x,baseline,paint);
 }
/**
  * draw the text, with origin at (x,y), using the specified paint. the
  * origin is interpreted based on the align setting in the paint.
  *
  * @param text the text to be drawn
  * @param x  the x-coordinate of the origin of the text being drawn
  * @param y  the y-coordinate of the baseline of the text being drawn
  * @param paint the paint used for the text (e.g. color, size, style)
  */
 public void drawtext(@nonnull string text, float x, float y, @nonnull paint paint) {
  native_drawtext(mnativecanvaswrapper, text, 0, text.length(), x, y, paint.mbidiflags,
    paint.getnativeinstance(), paint.mnativetypeface);
 }

x,y 分别表示 基线的开始坐标,并不是 文字左上角的坐标,因为文字的绘制是以基线为基础的

Android绘图之Paint的使用方法详解

图中的 五角星 所在的线 就是基线 baseline,那么如何确定基线的x,y坐标呢?

首写我们先确定一下x坐标 :int x = getpaddingleft(); 也就是文字距左边的距离

y坐标:

1、我们先计算一下文字高度的一半到 baseline的距离。

int dy = (fontmetrics.bottom - fontmetrics.top)/2 - fontmetrics.bottom;

2、之后我们再使用控件高度的一般,加上文字高度的一半到 baseline的距离,就是基线的y坐标

int baseline = getheight()/2 + dy;

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。