Android绘图

来源:互联网 发布:淘宝如何宝贝上架。 编辑:程序博客网 时间:2024/06/08 16:18

一、Canvas类Android.graphics.Canvas
先来看官网的一句话吧 The Canvas class holds the “draw” calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint (to describe the colors and styles for the drawing).
Canvas类就像一块画布,可以在上面画画,如果我们想画的话,需要四个基本组件
1、Bitmap ,位图 :包含像素
2、canvas ,画板
3、a drawing primitive ,原始图(e.g. Rect, Path, text, Bitmap)
4、Paint: 画笔 :提供了颜色和样式
这里写图片描述

public class DrawView extends View {    public DrawView(Context context) {        super(context);    }    public DrawView(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //创建画笔        Paint p = new Paint();        p.setColor(Color.RED);        p.setTextSize(50); //设置字体大小        /**         * 画圆         */        canvas.drawText("画圆", 10, 100, p);        canvas.drawCircle(200, 90, 15, p);        /**         * 画线         */        canvas.drawText("画线", 10, 200, p);        p.setColor(Color.BLUE);        canvas.drawLine(300, 200, 600, 200, p);  //只需要两个点的坐标        /**         * 画矩形         */        canvas.drawText("画矩形", 10, 400, p);//        p.setStyle(Paint.Style.FILL);        canvas.drawRect(200, 300, 500, 400, p);  //这个矩形是按边来画的   left:左边到X轴的距离(x坐标),top:上边到Y轴的距离(y的纵"zong"坐标),right:(右边到X的距离(X坐标),bottom:底边到Y轴的距离(Y坐标)        canvas.drawRect(600, 300, 1000, 500, p);        /**         * 画弧形         */        canvas.drawText("画弧形", 10, 700, p);        canvas.drawRect(200, 600, 600, 800, p);        p.setColor(Color.YELLOW);        RectF rectF = new RectF(200, 600, 600, 800);  //这个弧形就是以矩形的重心为原点,对角线的的一半为半径,以顺时针画        canvas.drawArc(rectF, 0, 160, true, p);   //useCenter 为true就覆盖所有画的区域        /**         * 三角形         */        p.setColor(Color.RED);        canvas.drawText("画三角形", 10, 900, p);        p.setStyle(Paint.Style.STROKE);//设置空心        //绘制三角形,也可以绘制任意多边形        Path path = new Path();        path.moveTo(300, 900); //第一个点为起点        path.lineTo(800, 100); //注意这里是lineto        path.lineTo(300, 970);        path.close();   //封闭        canvas.drawPath(path, p);        //画圆角矩形        p.setStyle(Paint.Style.FILL);        p.setColor(Color.LTGRAY);        p.setAntiAlias(true); //设置画笔的锯齿效果        canvas.drawText("画圆角矩形",10,1000,p);        RectF rectF1= new RectF(200,1000,500,1100);        canvas.drawRoundRect(rectF1,50,200,p);  //第二个参数和第三个x\y方向上的半径,不是很理解    }}

这里写的也挺详细的 http://blog.csdn.net/rhljiayou/article/details/7212620
二 接着看下经典之图 (很多博客第一个和我的不同)
这里写图片描述
ApiDemos导入各种报错,浪费了不少时间,干脆把代码拎出来,“点我进图”可以看到

1、这么多图是啥意思呢? 其实就花了两个图,
先画个圆(黄色)
再画个矩形(蓝色)
两个叠加通过属性判断要显示哪部分,最后就可以构成我们需要的各种图 形了,感觉和红绿蓝三原色似的。

2、这里面不得不提到 PorterDuff.Mode16种模式
从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值:

1.PorterDuff.Mode.CLEAR 所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC 显示上层绘制图片
3.PorterDuff.Mode.DST 显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER 正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER 上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN 取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN 取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT 取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT 取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP 取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP 取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR 异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN 两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN 取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY 取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN 两图层全部区域,交集部分变为透明色
3、ApiDemos 示例

public class Xfermodes extends Activity {    public static final Xfermode[] sModes = {            new PorterDuffXfermode(PorterDuff.Mode.CLEAR),            new PorterDuffXfermode(PorterDuff.Mode.SRC),            new PorterDuffXfermode(PorterDuff.Mode.DST),            new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),            new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),            new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),            new PorterDuffXfermode(PorterDuff.Mode.DST_IN),            new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),            new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),            new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),            new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),            new PorterDuffXfermode(PorterDuff.Mode.XOR),            new PorterDuffXfermode(PorterDuff.Mode.DARKEN),            new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),            new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),            new PorterDuffXfermode(PorterDuff.Mode.SCREEN)    };    // create a bitmap with a circle, used for the "dst" image  画一个圆    static Bitmap makeDst(int w, int h) {        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);        Canvas c = new Canvas(bm);        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);        p.setColor(0xFFFFCC44);        c.drawOval(new RectF(0, 0, w*3/4, h*3/4), p);        return bm;    }    // create a bitmap with a rect, used for the "src" image     画一个矩形    static Bitmap makeSrc(int w, int h) {        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);        Canvas c = new Canvas(bm);        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);        p.setColor(0xFF66AAFF);        c.drawRect(w/3, h/3, w*19/20, h*19/20, p);        return bm;    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(new SampleView(this));    }    private static class SampleView extends View {        private static final int W = 200;        private static final int H = 200;        private static final int ROW_MAX = 4;   // number of samples per row        private Bitmap mSrcB,mOvalB;        private Shader mBG;     // background checker-board pattern        private static final String[] sLabels = {                "Clear", "Src", "Dst", "SrcOver",                "DstOver", "SrcIn", "DstIn", "SrcOut",                "DstOut", "SrcATop", "DstATop", "Xor",                "Darken", "Lighten", "Multiply", "Screen"        };        public SampleView(Context context) {            super(context);            mSrcB = makeSrc(W, H);            mOvalB = makeDst(W, H);            // make a ckeckerboard pattern            Bitmap bm = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC,                            0xFFCCCCCC, 0xFFFFFFFF }, 2, 2,                    Bitmap.Config.RGB_565);            mBG = new BitmapShader(bm,                    Shader.TileMode.REPEAT,                    Shader.TileMode.REPEAT);            Matrix m = new Matrix(); //矩阵            m.setScale(6, 6);            mBG.setLocalMatrix(m);        }        @Override        protected void onDraw(Canvas canvas) {            canvas.drawColor(Color.WHITE);            Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);            labelP.setTextSize(30);            labelP.setTextAlign(Paint.Align.CENTER);            Paint paint = new Paint();            paint.setFilterBitmap(false);            canvas.translate(15, 35);            int x = 0;            int y = 0;            for (int i = 0; i < sModes.length; i++) {                // draw the border                paint.setStyle(Paint.Style.STROKE);                paint.setShader(null);                canvas.drawRect(x - 0.5f, y - 0.5f,                        x + W + 0.5f, y + H + 0.5f, paint);  //绘制正方形的外边框,长宽就是W 、 H                // draw the checker-board pattern                paint.setStyle(Paint.Style.FILL);                paint.setShader(mBG);                canvas.drawRect(x, y, x + W, y + H, paint);  //内边框                // draw the src/dst example into our offscreen bitmap                int sc = canvas.saveLayer(x, y, x + W, y + H, null,                        Canvas.MATRIX_SAVE_FLAG |                                Canvas.CLIP_SAVE_FLAG |                                Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |                                Canvas.FULL_COLOR_LAYER_SAVE_FLAG |                                Canvas.CLIP_TO_LAYER_SAVE_FLAG);                canvas.translate(x, y);     //设置矩阵的偏移量                canvas.drawBitmap(mOvalB, 0, 0, paint);     //先绘制圆                paint.setXfermode(sModes[i]);                canvas.drawBitmap(mSrcB, 0, 0, paint);  //再绘制矩形                paint.setXfermode(null);                canvas.restoreToCount(sc);                // draw the label                canvas.drawText(sLabels[i],                        x + W/2, y - labelP.getTextSize()/2, labelP);   //写字                x += W + 10;                // wrap around when we've drawn enough for one row                if ((i % ROW_MAX) == ROW_MAX - 1) {                    x = 0;                    y += H + 30;                }            }        }    }}

4、单个进行测试

   /** * Created by Administrator on 2016/8/28. * 对每一个属性单个进行测试,  !!!!!有一个问题   onDraw() 偶尔不执行 !!!!! */public class XfermodeView extends View {    //源图和目标图宽高    int width = 200, height = 200;    Bitmap rectBitmap, cirBitmap;    int screenW, screenH;    public XfermodeView(Context context) {       // super(context);        //init(context);        //把上面的改成        this(context,null);  //发现改成这样每次都会走了    }    public XfermodeView(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);        setWillNotDraw(false);    }    private void init(Context context) {        WindowManager windowManager = (WindowManager) context.getApplicationContext()                .getSystemService(Context.WINDOW_SERVICE);        DisplayMetrics metrics = new DisplayMetrics();        windowManager.getDefaultDisplay().getMetrics(metrics);        screenW = metrics.widthPixels;        screenH = metrics.heightPixels;    }    // create a bitmap with a circle, used for the "dst" image  画一个圆    static Bitmap makeDst(int w, int h) {        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);        Canvas c = new Canvas(bm);        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);        p.setColor(0xFFFFCC44);        c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p);        return bm;    }    // create a bitmap with a rect, used for the "src" image     画一个矩形    static Bitmap makeSrc(int w, int h) {        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);        Canvas c = new Canvas(bm);        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);        p.setColor(0xFF66AAFF);        c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p);        return bm;    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //创建原图和目标图        rectBitmap = makeSrc(width, height);        cirBitmap = makeDst(width, height);        Paint paint = new Paint();        paint.setFilterBitmap(false);        paint.setStyle(Paint.Style.FILL);        //绘制“src”蓝色矩形原图        canvas.drawBitmap(rectBitmap, (screenW / 8 - width / 4), (screenH / 12 - height / 4), paint);        //绘制“dst”黄色圆形原图        canvas.drawBitmap(cirBitmap, screenW / 2, screenH / 12, paint);//创建一个图层,在图层上演示图形混合后的效果        int sc = canvas.saveLayer(0, 0, screenW, screenH, null, Canvas.MATRIX_SAVE_FLAG |                Canvas.CLIP_SAVE_FLAG |                Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |                Canvas.FULL_COLOR_LAYER_SAVE_FLAG |                Canvas.CLIP_TO_LAYER_SAVE_FLAG);//        先绘制圆形        canvas.drawBitmap(cirBitmap, screenW / 4, screenH / 3, paint);        //设置Paint的Xfermode        paint.setXfermode(Xfermodes.sModes[4]);  //这里修改显示模式        //绘制矩形        canvas.drawBitmap(rectBitmap, screenW / 4, screenH / 3, paint);        paint.setXfermode(null);//         还原画布        canvas.restoreToCount(sc);    }}

Reference :http://blog.csdn.net/allen315410/article/details/45077165

三、接下来跟着大神来画图了
1、先绘bitmap,然后绘制形状,显示底部

      /** * Created by Administrator on 2016/8/29. */public class RoundImageViewByXfermode extends ImageView {    private int mBorderRadius; //圆角的大小    private Paint mPaint;    /**     * 图片的类型,圆形or圆角     */    private int type;    public static final int TYPE_CIRCLE = 0;    public static final int TYPE_ROUND = 1;    private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);    private WeakReference<Bitmap> mWeakBitmap;    private Bitmap mMaskBitmap;    public RoundImageViewByXfermode(Context context) {        this(context, null);        mPaint = new Paint();        mPaint.setAntiAlias(true);    }    public RoundImageViewByXfermode(Context context, AttributeSet attrs) {        super(context, attrs);        mPaint = new Paint();        mPaint.setAntiAlias(true);        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageViewByXfermode);        //角度默认10dp        mBorderRadius = a.getDimensionPixelSize(R.styleable.RoundImageViewByXfermode_borderRadius, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()));        type = a.getInt(R.styleable.RoundImageViewByXfermode_type, TYPE_CIRCLE); //默认圆角        a.recycle();    }    @Override    public void invalidate() {        mMaskBitmap = null;        if (mMaskBitmap != null) {            mMaskBitmap.recycle();            mMaskBitmap = null;        }        super.invalidate();    }    @Override    protected void onDraw(Canvas canvas) {//        super.onDraw(canvas);  // 这个要注释否则就会没效果        //从缓存中取出bitmap        Bitmap bitmap = mWeakBitmap == null ? null : mWeakBitmap.get();        if (null == bitmap || bitmap.isRecycled()) {            //拿到Drawable            Drawable drawable = getDrawable();            //获取Drawable的宽和高            int dWidth = drawable.getIntrinsicWidth();            int dHeight = drawable.getIntrinsicHeight();            if (drawable != null) {                //创建Bitmap                bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);                float scale = 1.0f;                //创建画布                Canvas drawCanvas = new Canvas(bitmap);                //按照bitmap的宽高,以及view的宽高,计算缩放比例;因为设置的src宽高比例可能和imageview的宽高比例不同,这里我们不希望图片失真;                if (type == TYPE_ROUND) {                    // 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值;                    scale = Math.max(getWidth() * 1.0f / dWidth, getHeight() * 1.0f / dHeight);                }                //根据缩放比例,设置bounds,相当于缩放图片                drawable.setBounds(0, 0, (int) (scale * dWidth), (int) (scale * dHeight));                drawable.draw(drawCanvas);                if (mMaskBitmap == null || mMaskBitmap.isRecycled())                    mMaskBitmap = getBitmap();                //Draw Bitmap                mPaint.reset();                mPaint.setFilterBitmap(false);                mPaint.setXfermode(mXfermode);  //  取两层绘制交集。显示下层。                //绘制圆角矩形                drawCanvas.drawBitmap(mMaskBitmap, 0, 0, mPaint);                mPaint.setXfermode(null);                //将准备好的bitmap绘制出来                canvas.drawBitmap(bitmap, 0, 0, null);                mWeakBitmap = new WeakReference<Bitmap>(bitmap);  //bitmap缓存起来,避免每次调用onDraw,分配内存            }        }        //如果bitmap还存在,则直接绘制即可        if (bitmap != null) {            mPaint.setXfermode(null);            canvas.drawBitmap(bitmap, 0.0f, 0.0f, mPaint);            return;        }    }    public Bitmap getBitmap() {        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),                Bitmap.Config.ARGB_8888);        Canvas canvas = new Canvas(bitmap);        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);        paint.setColor(Color.BLACK);        if (type == TYPE_ROUND) {            canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()),                    mBorderRadius, mBorderRadius, paint);        }        return bitmap;    }}

运行的时候编译器碰到一个很坑的问题
android studio Error:java.lang.OutOfMemoryError: GC overhead limit exceeded
解决方法是
这里写图片描述

REFERENCE :http://blog.csdn.net/lmj623565791/article/details/42094215

[代码]

二、BitmapShader 这个也能画出圆角矩形的效果

  Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.china, null);        Bitmap target = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());        RectF rect = new RectF(0, 0, target.getWidth(), target.getHeight());        BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);        Paint paint = new Paint();        paint.setShader(shader);        //绘制一个圆角矩形        Canvas canvas = new Canvas(target);        canvas.drawRoundRect(rect, 40, 40, paint);        imageView1.setImageBitmap(target);

参考:
http://gavinliu.cn/2016/04/12/Android-%E5%AE%9E%E7%8E%B0%E5%9B%BE%E7%89%87%E5%9C%86%E8%A7%92%E6%98%BE%E7%A4%BA%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E5%BC%8F/
http://blog.csdn.net/allen315410/article/details/45077165

http://blog.csdn.net/guolin_blog/article/details/16330267

0 0
原创粉丝点击