Android中view绘制常用知识

Paint

画笔,保存了绘制几何图形、文本和位图的样式和颜色信息

常用API

常用API主要如颜色,效果和文本相关等
mPaint = new Paint(); //初始化
mPaint.setColor(Color.RED);// 设置颜色
mPaint.setARGB(255, 255, 255, 0); // 设置 Paint对象颜色,范围为0~255
mPaint.setAlpha(200); // 设置alpha不透明度,范围为0~255
mPaint.setAntiAlias(true); // 抗锯齿
mPaint.setStyle(Paint.Style.FILL); //描边效果
mPaint.setStrokeWidth(4);//描边宽度
mPaint.setStrokeCap(Paint.Cap.ROUND); //圆角效果
mPaint.setStrokeJoin(Paint.Join.MITER);//拐角风格
mPaint.setShader(new SweepGradient(200, 200, Color.BLUE, Color.RED)); //设置环形渲染器
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); //设置图层混合模式
mPaint.setColorFilter(new LightingColorFilter(0x00ffff, 0x000000)); //设置颜色过滤器
mPaint.setFilterBitmap(true); //设置双线性过滤
mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));//设置画笔遮罩滤镜 ,传入度数和样式
mPaint.setTextScaleX(2);// 设置文本缩放倍数
mPaint.setTextSize(38);// 设置字体大小
mPaint.setTextAlign(Paint.Align.LEFT);//对其方式
mPaint.setUnderlineText(true);// 设置下划线
mPaint.setAntiAlias(true); 
设置抗锯齿会使图像边缘更清晰一些,锯齿痕迹不会那么明显
setStyle (Paint.Style style) 设置填充样式
Paint.Style 类型:

Paint.Style.FILL_AND_STROKE 填充且描边 
Paint.Style.STROKE 描边 
Paint.Style.FILL 填充
setShadowLayer(float radius, float dx, float dy, int shadowColor) 设置阴影 不支持硬件加速
表示的含义:
radius : 表示阴影的倾斜度 
dx : 水平位移 
dy : 垂直位移 
shadowColor : 阴影颜色
 setShader(Shader shader)参数着色器对象,一般使用Shader的几个子类:

        /**
        * 1.线性渲染,LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[], @Nullable float positions[], @NonNull TileMode tile)
        * (x0,y0):渐变起始点坐标
        * (x1,y1):渐变结束点坐标
        * color0:渐变开始点颜色,16进制的颜色表示,必须要带有透明度
        * color1:渐变结束颜色
        * colors:渐变数组
        * positions:位置数组,position的取值范围[0,1],作用是指定某个位置的颜色值,如果传null,渐变就线性变化。
        * tile:用于指定控件区域大于指定的渐变区域时,空白区域的颜色填充方法
        */
       mShader = new LinearGradient(0, 0, 500, 500, new int[]{Color.RED, Color.BLUE, 
               Color.GREEN}, new float[]{0.f,0.7f,1}, Shader.TileMode.REPEAT);
       mPaint.setShader(mShader);
       canvas.drawRect(0,0,1000,1000, mPaint);

//         * 环形渲染,RadialGradient(float centerX, float centerY, float radius, @ColorInt int colors[], @Nullable float stops[], TileMode tileMode)
        //         * centerX ,centerY:shader的中心坐标,开始渐变的坐标
        //         * radius:渐变的半径
        //         * centerColor,edgeColor:中心点渐变颜色,边界的渐变颜色
        //         * colors:渐变颜色数组
        //         * stoops:渐变位置数组,类似扫描渐变的positions数组,取值[0,1],中心点为0,半径到达位置为1.0f
        //         * tileMode:shader未覆盖以外的填充模式。
        //        
       mShader = new RadialGradient(250, 250, 250, new int[]{Color.GREEN, Color.YELLOW, Color.RED}, null, Shader.TileMode.CLAMP);
       mPaint.setShader(mShader);
       canvas.drawCircle(250, 250, 250, mPaint);

//        /**
//         * 扫描渲染,SweepGradient(float cx, float cy, @ColorInt int color0,int color1)
//         * cx,cy 渐变中心坐标
//         * color0,color1:渐变开始结束颜色
//         * colors,positions:类似LinearGradient,用于多颜色渐变,positions为null时,根据颜色线性渐变
//         */
       mShader = new SweepGradient(250, 250, Color.RED, Color.GREEN);
       mPaint.setShader(mShader);
       canvas.drawCircle(250, 250, 250, mPaint);


        /**
        * 扫描渲染,SweepGradient(float cx, float cy, @ColorInt int color0,int color1)
        * cx,cy 渐变中心坐标
        * color0,color1:渐变开始结束颜色
        * colors,positions:类似LinearGradient,用于多颜色渐变,positions为null时,根据颜色线性渐变
      */
       mShader = new SweepGradient(250, 250, Color.RED, Color.GREEN);
       mPaint.setShader(mShader);
       canvas.drawCircle(250, 250, 250, mPaint);

/**
        * 组合渲染,
        * ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, Xfermode mode)
        * ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, PorterDuff.Mode mode)
        * shaderA,shaderB:要混合的两种shader
        * Xfermode mode: 组合两种shader颜色的模式
        * PorterDuff.Mode mode: 组合两种shader颜色的模式
        */
       BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
       LinearGradient linearGradient = new LinearGradient(0, 0, 1000, 1600, new int[]{Color.RED, Color.GREEN, Color.BLUE}, null, Shader.TileMode.CLAMP);
       mShader = new ComposeShader(bitmapShader, linearGradient, PorterDuff.Mode.MULTIPLY);
       mPaint.setShader(mShader);
       canvas.drawCircle(250, 250, 250, mPaint);
setColorFilter(ColorFilter colorFilter)设置颜色过滤,一般使用ColorFilter三个子类:原理主要I是设置矩阵的问题。
LightingColorFilter:光照效果
PorterDuffColorFilter:指定一个颜色和一种PorterDuff.Mode与绘制对象进行合成
ColorDatrixColorFilter:使用一个ColorMatrix来对颜色进行处理

CanVas

画布,是一种绘制时的规则,规定绘制内容时的规则或者内容

  1. 绘制内容是根据画布的规定绘制在屏幕上的
  2. 画布只是绘制时的规则,但内容实际上是绘制在屏幕上的

Canvas对象 & 获取的方法有4个:

// 方法1
// 利用空构造方法直接创建对象
Canvas canvas = new Canvas();

// 方法2
// 通过传入装载画布Bitmap对象创建Canvas对象
// CBitmap上存储所有绘制在Canvas的信息
Canvas canvas = new Canvas(bitmap)

// 方法3
// 通过重写View.onDraw()创建Canvas对象
// 在该方法里可以获得这个View对应的Canvas对象

   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //在这里获取Canvas对象
    }

// 方法4
// 在SurfaceView里画图时创建Canvas对象

        SurfaceView surfaceView = new SurfaceView(this);
        // 从SurfaceView的surfaceHolder里锁定获取Canvas
        SurfaceHolder surfaceHolder = surfaceView.getHolder();
        //获取Canvas
        Canvas c = surfaceHolder.lockCanvas();
        
        // ...(进行Canvas操作)
        // Canvas操作结束之后解锁并执行Canvas
        surfaceHolder.unlockCanvasAndPost(c);

SurfaceView里有一条线程是专门用于画图,所以方法4的画图性能最好,并适用于高质量的、刷新频率高的图形
而方法3刷新频率低于方法4,但系统花销小,节省资源

绘制颜色

Canvas具体使用时是在复写的onDraw()里:
@Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
  
    // 对Canvas进行一系列设置
    //  如画圆、画直线等等
   canvas.drawColor(Color.BLUE); 
    // ...
    }
}
 // 绘制蓝色
   canvas.drawColor(Color.BLUE); 

绘制点(drawPoint)

在某个坐标处绘制点


// 特别注意:需要用到画笔Paint
// 所以之前记得创建画笔
// 为了区分,这里使用了两个不同颜色的画笔

// 描绘一个点
// 在坐标(200,200)处
canvas.drawPoint(300, 300, mPaint1);    

// 绘制一组点,坐标位置由float数组指定
// 此处画了3个点,位置分别是:(600,500)、(600,600)、(600,700)
canvas.drawPoints(new float[]{         
                600,500,
                600,600,
                600,700
        },mPaint2);

绘制直线(drawLine)

两点(初始点 & 结束点)确定一条直线

// 画一条直线
// 在坐标(100,200),(700,200)之间绘制一条直线
   canvas.drawLine(100,200,700,200,mPaint1);

// 绘制一组线
// 在坐标(400,500),(500,500)之间绘制直线1
// 在坐标(400,600),(500,600)之间绘制直线2
        canvas.drawLines(new float[]{
                400,500,500,500,
                400,600,500,600
        },mPaint2);
    }

绘制矩形(drawRect)

矩形的对角线顶点确定一个矩形,一般是采用左上角和右下角的两个点的坐标。

// 关于绘制矩形,Canvas提供了三种重载方法

       // 方法1:直接传入两个顶点的坐标
       // 两个顶点坐标分别是:(100,100),(800,400)
        canvas.drawRect(100,100,800,400,mPaint);

        // 方法2:将两个顶点坐标封装为RectRectF
        Rect rect = new Rect(100,100,800,400);
        canvas.drawRect(rect,mPaint);

        // 方法3:将两个顶点坐标封装为RectF
        RectF rectF = new RectF(100,100,800,400);
        canvas.drawRect(rectF,mPaint);

        // 特别注意:Rect类和RectF类的区别
        // 精度不同:Rect = int & RectF = float

        // 三种方法画出来的效果是一样的。

绘制圆角矩形

原理:矩形的对角线顶点确定一个矩形

 // 方法1:直接传入两个顶点的坐标
       // API21时才可使用
       // 第5、6个参数:rx、ry是圆角的参数,下面会详细描述
       canvas.drawRoundRect(100,100,800,400,30,30,mPaint);
      
        // 方法2:使用RectF类
        RectF rectF = new RectF(100,100,800,400);
        canvas.drawRoundRect(rectF,30,30,mPaint);

绘制椭圆

原理:矩形的对角线顶点确定矩形,根据传入矩形的长宽作为长轴和短轴画椭圆

 // 方法1:使用RectF类
        RectF rectF = new RectF(100,100,800,400);
        canvas.drawOval(rectF,mPaint);

        // 方法2:直接传入与矩形相关的参数
        canvas.drawOval(100,100,800,400,mPaint);

        // 为了方便表示,画一个和椭圆一样参数的矩形
         canvas.drawRect(100,100,800,400,mPaint);

绘制圆

// 参数说明:
// 1、2:圆心坐标
// 3:半径
// 4:画笔

// 绘制一个圆心坐标在(500,500),半径为400 的圆。
    canvas.drawCircle(500,500,400,mPaint);  

绘制文字

绘制文字分为三种应用场景:
情况1:指定文本开始的位置

1. 即指定文本基线位置
2. 基线x默认在字符串左侧,基线y默认在字符串下方

情况2:指定每个文字的位置
情况3:指定路径,并根据路径绘制文字

情况1:指定文本开始的位置

// 参数text:要绘制的文本
// 参数x,y:指定文本开始的位置(坐标)

// 参数paint:设置的画笔属性
    public void drawText (String text, float x, float y, Paint paint)

// 实例
canvas.drawText("abcdefg",300,400,mPaint1);

// 仅绘制文本的一部分
// 参数start,end:指定绘制文本的位置
// 位置以下标标识,由0开始
    public void drawText (String text, int start, int end, float x, float y, Paint paint)
    public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)

// 对于字符数组char[]
// 截取文本使用起始位置(index)和长度(count)
    public void drawText (char[] text, int index, int count, float x, float y, Paint paint)

// 实例:绘制从位置1-3的文本
canvas.drawText("abcdefg",1,4,300,400,mPaint1);

        // 字符数组情况
        // 字符数组(要绘制的内容)
        char[] chars = "abcdefg".toCharArray();

        // 参数为 (字符数组 起始坐标 截取长度 基线x 基线y 画笔)
        canvas.drawText(chars,1,3,200,500,textPaint);
        // 效果同上

Android中view绘制常用知识_第1张图片
情况2:分别指定文本的位置

// 参数text:绘制的文本
// 参数pos:数组类型,存放每个字符的位置(坐标)
// 注意:必须指定所有字符位置
 public void drawPosText (String text, float[] pos, Paint paint)

// 对于字符数组char[],可以截取部分文本进行绘制
// 截取文本使用起始位置(index)和长度(count)
    public void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)

// 特别注意:
// 1. 在字符数量较多时,使用会导致卡顿
// 2. 不支持emoji等特殊字符,不支持字形组合与分解

  // 实例
  canvas.drawPosText("abcde", new float[]{
                100, 100,    // 第一个字符位置
                200, 200,    // 第二个字符位置
                300, 300,    // ...
                400, 400,
                500, 500
        }, mPaint1);
// 数组情况(绘制部分文本)
       char[] chars = "abcdefg".toCharArray();
        canvas.drawPosText(chars, 1, 3, new float[]{
                300, 300,    // 指定的第一个字符位置
                400, 400,    // 指定的第二个字符位置
                500, 500,    // 指定的第三个字符位置
        }, mPaint1);

Android中view绘制常用知识_第2张图片
情况3:指定路径,并根据路径绘制文字

// 在路径(540,750,640,450,840,600)写上"在Path上写的字:Carson_Ho"字样
        // 1.创建路径对象
        Path path = new Path();
        // 2. 设置路径轨迹
        path.cubicTo(540, 750, 640, 450, 840, 600);
         // 3. 画路径
        canvas.drawPath(path,mPaint2);
        // 4. 画出在路径上的字
        canvas.drawTextOnPath("在Path上写的字:Carson_Ho", path, 50, 0, mPaint2);
      

Android中view绘制常用知识_第3张图片

使用的api

//普通设置
paint.setAntiAlias(true); //指定是否使用抗锯齿功能 如果使用会使绘图速度变慢 默认false
setStyle(Paint.Style.FILL);//绘图样式 对于设文字和几何图形都有效
setTextAlign(Align.LEFT);//设置文字对齐方式 取值:align.CENTER、align.LEFT或align.RIGHT 默认align.LEFT
paint.setTextSize(12);//设置文字大小

//样式设置
paint.setFakeBoldText(true);//设置是否为粗体文字
paint.setUnderlineText(true);//设置下划线
paint.setTextSkewX((float) -0.25);//设置字体水平倾斜度 普通斜体字是-0.25
paint.setStrikeThruText(true);//设置带有删除线效果

setTypeface(Typeface typeface)

Typeface 是用来设置字体样式的,通过paint.setTypeface()来指定。可以指定系统中的字体样式,也可以指定自定义的样式文件中获取。 要构建Typeface时,可以指定所用样式的正常体、斜体、粗体等,如果指定样式中,没有相关文字的样式就会用系统默认的样式来显示,一般默认是宋体
参数类型是枚举类型,枚举值如下:

  1. Typeface.NORMAL //正常体
  2. Typeface.BOLD //粗体
  3. Typeface.ITALIC //斜体
  4. Typeface.BOLD_ITALIC //粗斜体

自定义字体

createFromAsset(AssetManager mgr, String path) //Asset中获取
createFromFile(File path) //文件路径获取
createFromFile(String path) //外部路径获取

绘制图片

绘制图片分为:绘制矢量图(drawPicture)和 绘制位图(drawBitmap)

绘制矢量图(drawPicture)

作用:绘制矢量图的内容,即绘制存储在矢量图里某个时刻Canvas绘制内容的操作
矢量图(Picture)的作用:存储(录制)某个时刻Canvas绘制内容的操作
应用场景:绘制之前绘制过的内容

  1. 相比于再次调用各种绘图API,使用Picture能节省操作 & 时间
  2. 如果不手动调用,录制的内容不会显示在屏幕上,只是存储起来
// 获取宽度
Picture.getWidth ();
// 获取高度
Picture.getHeight ()
// 开始录制 
// 即将Canvas中所有的绘制内容存储到Picture中
// 返回一个Canvas
Picture.beginRecording(int width, int height)
// 结束录制
Picture.endRecording ()
// 将Picture里的内容绘制到Canvas中
Picture.draw (Canvas canvas)
// 还有两种方法可以将Picture里的内容绘制到Canvas中
// 方法2:Canvas.drawPicture()
// 方法3:将Picture包装成为PictureDrawable,使用PictureDrawable的draw方法绘制。
使用步骤
// 步骤1:创建Picture对象
Picture mPicture = new Picture();

// 步骤2:开始录制 
mPicture.beginRecording(int width, int height);

// 步骤3:绘制内容 or 操作Canvas
canvas.drawCircle(500,500,400,mPaint);
...(一系列操作)

// 步骤4:结束录制
mPicture.endRecording ();

步骤5:某个时刻将存储在Picture的绘制内容绘制出来
mPicture.draw (Canvas canvas);

实例介绍
将坐标系移动到(450,650);绘制一个圆,将上述Canvas操作录制下来,并在某个时刻重新绘制出来
步骤1:创建Picture对象

Picture mPicture = new Picture();

步骤2:开始录制

Canvas recordingCanvas = mPicture.beginRecording(500, 500);

// 注:要创建Canvas对象来接收beginRecording()返回的Canvas对象

步骤3:绘制内容 or 操作Canvas

 // 位移
        // 将坐标系的原点移动到(450,650)
        recordingCanvas.translate(450,650);

        // 记得先创建一个画笔
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.FILL);

        // 绘制一个圆
        // 圆心为(0,0),半径为100
       recordingCanvas.drawCircle(0,0,100,paint);

步骤4:结束录制

mPicture.endRecording();

步骤5:将存储在Picture的绘制内容绘制出来

有三种方法:
Picture.draw (Canvas canvas)
Canvas.drawPicture()
PictureDrawable.draw()
将Picture包装成为PictureDrawable

Android中view绘制常用知识_第4张图片
方法1:Picture提供的draw()

// 在复写的onDraw()里
  @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);

        // 将录制的内容显示在当前画布里
        mPicture.draw(canvas);

// 注:此方法绘制后可能会影响Canvas状态,不建议使用
 }

Android中view绘制常用知识_第5张图片
方法2:Canvas提供的drawPicture()

// 提供了三种方法
// 方法1
public void drawPicture (Picture picture)
// 方法2
// Rect dst代表显示的区域
// 若区域小于图形,绘制的内容根据选区进行缩放
public void drawPicture (Picture picture, Rect dst)

// 方法3
public void drawPicture (Picture picture, RectF dst)

@Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);

        // 实例1:将录制的内容显示(区域刚好布满图形)
        canvas.drawPicture(mPicture, new RectF(0, 0, mPicture.getWidth(), mPicture.getHeight()));

        // 实例2:将录制的内容显示在当前画布上(区域小于图形)
        canvas.drawPicture(mPicture, new RectF(0, 0, mPicture.getWidth(), 200));

Android中view绘制常用知识_第6张图片

方法3:使用PictureDrawable的draw方法绘制
将Picture包装成为PictureDrawable

 @Override
    protected void onDraw(Canvas canvas){

        super.onDraw(canvas);

        // 将录制的内容显示出来

        // 将Picture包装成为Drawable
        PictureDrawable drawable = new PictureDrawable(mPicture);

        // 设置在画布上的绘制区域(类似drawPicture (Picture picture, Rect dst)的Rect dst参数)
        // 每次都从Picture的左上角开始绘制
        // 并非根据该区域进行缩放,也不是剪裁Picture。

        // 实例1:将录制的内容显示(区域刚好布满图形)
        drawable.setBounds(0, 0,mPicture.getWidth(), mPicture.getHeight());

        // 绘制
        drawable.draw(canvas);


        // 实例2:将录制的内容显示在当前画布上(区域小于图形)
        drawable.setBounds(0, 0,250, mPicture.getHeight());

Android中view绘制常用知识_第7张图片

绘制位图(drawBitmap)

作用:将已有的图片转换为位图(Bitmap),最后再绘制到Canvas上
位图,即平时我们使用的图片资源

获取Bitmap对象的方式

要绘制Bitmap,就要先获取一个Bitmap对象,具体获取方式如下:
Android中view绘制常用知识_第8张图片

绘制位图(Bitmap)是读取已有的图片转换为Bitmap,最后再绘制到Canvas。

第1种方式:排除
第2种方式:虽然满足需求,但一般不推荐使用

第三种通过BitmapFactory获取Bitmap

// 共3个位置:资源文件、内存卡、网络

// 位置1:资源文件(drawable/mipmap/raw)
        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),R.raw.bitmap);

// 位置2:资源文件(assets)
        Bitmap bitmap=null;
        try {
            InputStream is = mContext.getAssets().open("bitmap.png");
            bitmap = BitmapFactory.decodeStream(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

// 位置3:内存卡文件
    Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/bitmap.png");

// 位置4:网络文件:
// 省略了获取网络输入流的代码
        Bitmap bitmap = BitmapFactory.decodeStream(is);
        is.close();

绘制Bitmap

绘制Bitmap共有四种方法

// 方法1
    public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)
 // 方法2
    public void drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
// 方法3
    public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
// 方法4
    public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
// 下面详细说
//方法一
public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)

// 后两个参数matrix, paint是在绘制时对图片进行一些改变
// 后面会专门说matrix
  
// 如果只是将图片内容绘制出来只需将传入新建的matrix, paint对象即可:
  canvas.drawBitmap(bitmap,new Matrix(),new Paint());
// 记得选取一种获取Bitmap的方式
// 注:图片左上角位置默认为坐标原点。

//方法2

// 参数 left、top指定了图片左上角的坐标(距离坐标原点的距离):
public void drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
 canvas.drawBitmap(bitmap,300,400,new Paint());
//方法三
 public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
// 参数(src,dst) = 两个矩形区域
// Rect src:指定需要绘制图片的区域(即要绘制图片的哪一部分)
// Rect dst 或RectF dst:指定图片在屏幕上显示(绘制)的区域
// 下面我将用实例来说明

// 实例
 // 指定图片绘制区域
        // 仅绘制图片的二分之一
        Rect src = new Rect(0,0,bitmap.getWidth()/2,bitmap.getHeight());
        // 指定图片在屏幕上显示的区域
        Rect dst = new Rect(100,100,250,250);
        // 绘制图片
        canvas.drawBitmap(bitmap,src,dst,null);

paint详细:
https://www.gcssloop.com/customview/paint-base
path
https://blog.csdn.net/u012551350/article/details/51245793
字体
https://blog.csdn.net/u012551350/article/details/51330308
原型
https://www.jianshu.com/p/762b490403c3

你可能感兴趣的:(Android)