CustomView4.md

Android自定义View(四)

目录:

绘制图片

drawPicture(矢量图)

使用Picture前请关闭硬件加速,以免引起不必要的问题!请参考Android的硬件加速及可能导致的问题

关闭方法: 在AndroidManifest.xml的加上android:hardwareAccelerated="false"。

官方对Picture的描述: A Picture records drawing calls (via the canvas returned by beginRecording) and can then play them back into Canvas (via draw(Canvas) or drawPicture(Picture)).For most content (e.g. text, lines, rectangles), drawing a sequence from a picture can be faster than the equivalent API calls, since the picture performs its playback without incurring any method-call overhead. Note: Prior to API level 23 a picture cannot be replayed on a hardware accelerated canvas. 有道翻译:一个图片记录调用(通过画布返回的开始记录),然后可以回放到画布(通过绘制(画布)或drawPicture(图片))。对于大多数内容(例如,文本、线条、矩形),从图片中绘制序列比等效的API调用要快,因为图片执行它的播放而不产生任何方法调用开销。 注意:在API级别23之前,不能在硬件加速画布上重新播放图片。

Picture的公共方法和描述

公共方法 描述
beginRecording(int width, int height) 开始录制 (返回一个Canvas,在Canvas中所有的绘制都会存储在Picture中)
createFromStream(InputStream stream) 通过输入流创建一个Picture,该方法在API级别18中被弃用。推荐的替代方法是不使用writeToStream,而是把图片画成一个位图,你可以把它作为原始的或压缩的像素来保存。
draw(Canvas canvas) 将Picture中内容绘制到Canvas中
endRecording() 结束录制
getHeight() 获取高度
getWidth() 获取宽度
requiresHardwareAcceleration() 指示Picture是否包含只在绘制到硬件加速画布时才工作的记录命令。
writeToStream(OutputStream stream) 将Picture中内容写出到输出流中,该方法在API级别18中被弃用。推荐的方法是将图片绘制到位图中,您可以将其作为原始的或压缩的像素保存。

录制的内容是不会直接显示在屏幕上的,需要使用下面几种方法把它显示出来:

(1)Picture提供的draw方法

(2)Canvas提供的drawPicture方法

(3)PictureDrawable的draw方法

简单示例:

package com.lcfu1.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.drawable.PictureDrawable;
import android.util.AttributeSet;
import android.view.View;

public class canvas extends View {
    // 1.创建一个画笔
    private Paint mPaint = new Paint();
    private Picture mPicture = new Picture();

    public canvas(Context context) {
        super(context);
    }

    public canvas(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        //调用录制方法
        recording();
    }

    //初始化画笔
    private void init() {
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(2);
    }

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

        //使用Picture提供的draw方法绘制
        //mPicture.draw(canvas);

        //使用Canvas提供的drawPicture方法绘制
        //canvas.drawPicture(mPicture);

        //将Picture包装成为PictureDrawable,使用PictureDrawable的draw方法绘制
        PictureDrawable drawable=new PictureDrawable(mPicture);
        //这里要设置绘制区域,不然显示不出来
        drawable.setBounds(0,0,400,400);
        drawable.draw(canvas);
    }

    //录制方法
    private void recording() {
        Canvas canvas = mPicture.beginRecording(400, 400);// 开始录制 (接收返回值Canvas)
        canvas.drawColor(Color.GRAY);
        canvas.translate(200,200);//位移
        canvas.drawCircle(0,0,100,mPaint);//绘制圆
        mPicture.endRecording();
    }
}

layout中:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.lcfu1.view.canvas
        android:layout_width="200dp"
        android:layout_height="200dp" />
</LinearLayout>

效果如下:

image.png

drawBitmap(位图)

drawBitmap的常用方法如下:

// 第一种,绘制图片内容,默认从坐标原点开始
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)

// 第二种,指定与坐标原点的距离,这里要注意的是坐标原点,如果canvas有位移、旋转等操作,坐标原点会发生相应变化
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint)

// 第三种,Rect src指定绘制图片的区,Rect dst 或RectF dst指定图片在屏幕上显示(绘制)的区域
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)

简单示例如下:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by lcf on 2018/4/21 0021.
 */

public class picture extends View {
    Bitmap mBitmap;

    public picture(Context context) {
        super(context);
    }

    public picture(final Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        //从mipmap获取Bitmap
        mBitmap= BitmapFactory.decodeResource(context.getResources(),R.mipmap.ic_launcher);

        //从assets获取Bitmap
//        try {
//            InputStream inputStream =context.getAssets().open("lcfu1.jpg");
//            mBitmap = BitmapFactory.decodeStream(inputStream);
//            inputStream.close();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }

    }

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

        //绘制图片内容,默认从坐标原点开始
        //canvas.drawBitmap(mBitmap, new Matrix(),new Paint());

        //指定与坐标原点的距离,这里要注意的是坐标原点,如果canvas有位移、旋转等操作,坐标原点会发生相应变化
        //canvas.drawBitmap(mBitmap,100,100,new Paint());

        Rect src = new Rect(0,0,mBitmap.getWidth(),mBitmap.getHeight()/2);// 指定图片绘制区域
        Rect dst = new Rect(0,0,mBitmap.getWidth(),mBitmap.getHeight()/2);//指定图片在屏幕上显示的区域,也就是给个固定区域来填满显示
        canvas.drawBitmap(mBitmap,src,dst,new Paint());// 绘制图片
    }
}

效果如下:

image.png

上面例子是通过BitmapFactory从资源文件中获取Bitmap的,获取Bitmap的三种方式如下:

BitmapFactory获取Bitmap的方法:

        //从mipmap获取Bitmap
        //mBitmap= BitmapFactory.decodeResource(context.getResources(),R.mipmap.ic_launcher);

        //从assets获取Bitmap
        try {
            InputStream is =context.getAssets().open("lcfu1.jpg");
            mBitmap = BitmapFactory.decodeStream(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
mBitmap= BitmapFactory.decodeFile("sdcard/lcfu1.jpg");
// 需要获取网络输入流的代码
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
inputStream.close();

注:从内存卡或网络上获取的方法我还没实现,有待解决!!

参考