IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]Android实战技巧之二十九:画布Canvas

    lincyang发表于 2015-05-07 13:29:15
    love 0

    Android Framework提供了一些2D画图的API,android.graphics包就是其中之一。
    为了画一些东西,需要4个元素(或称组件)协同来完成:
    * 位图:Bitmap来保持(hold)那些像素
    * 画布:Canvas来响应画画(draw)的调用(并将其写入bitmap)
    * 画笔:paint描述画画的颜色和样式等
    * “颜料“:drawing primitive,比如矩形、路径、文字、位图等其他元素

    而这其中Canvas是比较重要的一环,今天就来演示Canvas的基本使用方法。

    一、基本的draw方法

    android.graphics.Canvas类提供了很多“画“的方法,让这块画布具有了丰富多彩的画画能力。比如:画点、线、矩形、椭圆、圆、文字等等。下面的例子演示了这些方法的使用。
    先来建一个类,继承自View。让画布铺在View上而显示出来(这也是自定义UI组件的路子)。
    重载onDraw方法,让这些画画的步骤在onDraw中完成。
    源码如下:

    package com.lazytech.canvasdemo;
    public class PaintBoard extends View {
    
        public PaintBoard(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            //paint a circle
            Paint paint = new Paint();
            paint.setColor(Color.BLUE);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(10);
            canvas.drawCircle(120, 80, 60, paint);
    
            //paint string
            paint = new Paint();
            paint.setColor(Color.YELLOW);
            paint.setTextSize(20);
            canvas.drawText("My name is Linc!",245,140,paint);
    
            //draw line
            paint = new Paint();
            paint.setColor(Color.BLACK);
            canvas.drawLine(245,145,500,145,paint);
        }
    }

    只要在Activity的布局文件中加上这个view就可以了。如下:

        <com.lazytech.canvasdemo.PaintBoard
            android:id="@+id/paint_board"
            android:layout_width="match_parent"
            android:layout_below="@id/text"
            android:layout_height="200dp"
            android:background="@android:color/holo_green_light"
            />

    二、一个画板

    有了上面的基础,我们就可以发挥一下,写一个画板的demo。随着手指的滑动,屏幕上留下了你艺术的痕迹。那么这个画板要如何实现呢?
    有几个点要抓住:
    * 捕捉你手指的滑动轨迹。重载onTouchEvent方法来实现。
    * 实时更新你的画图。用invalidate方法来通知onDraw重绘。
    * 保存我们的作品。将bitmap保存成文件。

    有了上述要点整理,我们开始工作吧。首先还是建一个画板类PaintBoard2继承自View。三个重要元素作为类成员并在构造函数中做初始化。

    public class PaintBoard2 extends View {
        private Paint mPaint = null;
        private Bitmap mBitmap = null;
        private Canvas mBitmapCanvas = null;
            public PaintBoard2(Context context, AttributeSet attrs) {
            super(context, attrs);
            mBitmap = Bitmap.createBitmap(500,200, Bitmap.Config.ARGB_8888);
            mBitmapCanvas = new Canvas(mBitmap);
            mBitmapCanvas.drawColor(Color.GRAY);
            mPaint = new Paint();
            mPaint.setColor(Color.RED);
            mPaint.setStrokeWidth(6);
        }

    随着手指滑动去画线:

        private float startX;
        private float startY ;
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    startX = event.getX();
                    startY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float stopX = event.getX();
                    float stopY = event.getY();
                    Log.e(TAG,"onTouchEvent-ACTION_MOVE\nstartX is "+startX+
                    " startY is "+startY+" stopX is "+stopX+ " stopY is "+stopY);
                    mBitmapCanvas.drawLine(startX, startY, stopX, stopY, mPaint);
                    startX = event.getX();
                    startY = event.getY();
                    invalidate();//call onDraw()
                    break;
            }
            return true;
        }

    在onDraw时画bitmap:

        @Override
        protected void onDraw(Canvas canvas) {
            if(mBitmap != null) {
                canvas.drawBitmap(mBitmap, 0, 0, mPaint);
            }
        }

    提供一个将bitmap存入OutputStream的方法供保存位图做准备。

        public void saveBitmap(OutputStream stream) {
            if (mBitmap != null) {
                mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
            }
        }

    它是如何在Activity中调用的呢?
    activity的layout:

        <com.lazytech.canvasdemo.PaintBoard2
            android:id="@+id/paint_board2"
            android:layout_below="@id/paint_board"
            android:layout_width="match_parent"
            android:layout_height="200dp" />
        

    定义PaintBoard2作为Activity的成员,并在onCreate初始化:

    private PaintBoard2 paintBoard2;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            paintBoard2 = (PaintBoard2)findViewById(R.id.paint_board2);
        }

    点击保存按钮的处理:

        public void OnSaveClicked(View view) {
            try {
                File file = new File(Environment.getExternalStorageDirectory(),
                        System.currentTimeMillis() + ".jpg");
                OutputStream stream = new FileOutputStream(file);
                paintBoard2.saveBitmap(stream);
                stream.close();
                // send broadcast to Media to update data
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
                intent.setData(Uri.fromFile(Environment
                        .getExternalStorageDirectory()));
                sendBroadcast(intent);
    
                Toast.makeText(this, "save success", Toast.LENGTH_SHORT).show();
            } catch (Exception e) {
                Toast.makeText(this, "save failed", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }

    截图风采:
    这里写图片描述

    完成源码参考我的开源demo项目:
    https://code.csdn.net/lincyang/androidwidgetdemo

    参考:
    http://www.cnblogs.com/menlsh/archive/2012/11/18/2776003.html
    http://www.cnblogs.com/wuyou/p/3658691.html



沪ICP备19023445号-2号
友情链接