首页 > 代码库 > Android 繪圖白板元件,有畫筆和板擦的功能 (转)

Android 繪圖白板元件,有畫筆和板擦的功能 (转)

package com.example.drawboard;

import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class DrawBoardView extends View {

    //定義防止線條有鋸齒的常數
    private static final boolean GESTURE_RENDERING_ANTIALIAS = true;
    private static final boolean DITHER_FLAG = true;

    // 底圖 bitmap
    private Bitmap mBackgroundBitmap = null;
    // View 的整個長寬範圍
    private Rect mWholeRect;

    private Bitmap mBitmap = null;    // 圖層繪圖
    private Canvas mCanvas = null;    // 圖層畫布
    private Paint mDefaultPaint = new Paint();    // 空白畫筆

    private boolean mCapturing = true;    // 是否擷取狀態

    //定義繪圖的基本參數:線的 width, color
    private float mPaintWidth = 5f;
    private int mPaintColor = Color.RED;

    private int mPenMode = 1;    //1:為畫筆, 0:為板擦
    private Paint mPaint;

    private Path mPath;

    private List<Path> mDrawList = new ArrayList<Path>();
    private List<Paint> mPaintsList = new ArrayList<Paint>();
    private List<Rect> mRectsList = new ArrayList<Rect>();
    private int mTotalAction = 0;    // 記錄動作的次數

    private float mCurveStartX, mCurveStartY;    // 按下的點
    private float mX, mY;                        // 移動的點
    private float mCurveEndX, mCurveEndY;        // 放開的點
 
    private final Rect mInvalidRect = new Rect();
    private int mInvalidateExtraBorder = 10;


    // 建構子
    public DrawBoardView(Context context) {
        super(context);
        init(context);
    }

    // 建構子
    public DrawBoardView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    // 建構子
    public DrawBoardView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    // 初始化
    private void init(Context context) {
        setWillNotDraw(false);
    }


    private void setPaint(Paint thePaint) {
        if (mPenMode != 0) {
            thePaint.setStrokeWidth(mPaintWidth);
            thePaint.setColor(mPaintColor);
            thePaint.setStyle(Paint.Style.STROKE);
            thePaint.setStrokeJoin(Paint.Join.ROUND);
            thePaint.setStrokeCap(Paint.Cap.ROUND);
            thePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
            thePaint.setDither(DITHER_FLAG);
            thePaint.setXfermode(null);
        } else { // 橡皮檫模式,先以黑色顯示範圍
            thePaint.setStrokeWidth(mPaintWidth);
            thePaint.setColor(Color.BLACK);
            thePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
            thePaint.setDither(DITHER_FLAG);
            thePaint.setXfermode(null);
        }
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        this.mWholeRect = new Rect(0, 0, w, h);

        mBitmap = null;
        mCanvas = null;
        mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);

        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mBackgroundBitmap != null) mCanvas.drawBitmap(mBackgroundBitmap, null, this.mWholeRect, null);

        for (int i = 0; i < mTotalAction; i++) {
            mCanvas.drawPath(mDrawList.get(i), mPaintsList.get(i));
        }

        if (mPath != null && mPaint != null) mCanvas.drawPath(mPath, mPaint);

        canvas.drawBitmap(mBitmap, 0, 0, mDefaultPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mCapturing = true;
            mPaint = new Paint();
            setPaint(mPaint);

            mPath = new Path();

            touchDown(event);
            invalidate();

            return true;

        case MotionEvent.ACTION_MOVE:
            if (mCapturing) {
                Rect rect = touchMove(event);
                if (rect != null) {
                    invalidate(rect);
                }
            }

            return true;

        case MotionEvent.ACTION_UP:
            touchUp(event);
            invalidate();

            mCapturing = false;

            // 先清除已復原的動作
            int totalAction = mDrawList.size();
            while (totalAction > mTotalAction) {
                totalAction -= 1;
                mPaintsList.remove(totalAction);
                mRectsList.remove(totalAction);
                mDrawList.remove(totalAction);
            }

            // 再加入新的動作
            mTotalAction += 1;

            if (mPenMode == 0) {
                mBitmap = null;
                mCanvas = null;
                mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
                mCanvas = new Canvas(mBitmap);

                // 橡皮擦屬性
                mPaint.setColor(Color.TRANSPARENT);
                mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            }
            mPaintsList.add(mPaint);

            mDrawList.add(mPath);

            mPaint = null;
            mPath = null;

            return true;
        }

        return false;
    }

    private void touchDown(MotionEvent event) {
           float x = event.getX();
           float y = event.getY();

           mCurveStartX = x;
           mCurveStartY = y;
           mX = x;
           mY = y;
           mCurveEndX = x;
           mCurveEndY = y;

           mPath.moveTo(x, y);

           final int border = mInvalidateExtraBorder;
           mInvalidRect.set((int) x - border, (int) y - border, (int) x + border, (int) y + border);
    }

    private Rect touchMove(MotionEvent event) {
           Rect areaToRefresh = null;

           final float x = event.getX();
           final float y = event.getY();

           final float previousX = mX;
           final float previousY = mY;

           areaToRefresh = mInvalidRect;

           // start with the curve end
           final int border = mInvalidateExtraBorder;
           areaToRefresh.set((int) mCurveEndX - border, (int) mCurveEndY - border,
                   (int) mCurveEndX + border, (int) mCurveEndY + border);

           float cX = mCurveEndX = (x + previousX) / 2;
           float cY = mCurveEndY = (y + previousY) / 2;

           mPath.quadTo(previousX, previousY, cX, cY);

           // union with the control point of the new curve
           areaToRefresh.union((int) previousX - border, (int) previousY - border,
                   (int) previousX + border, (int) previousY + border);

           // union with the end point of the new curve
           areaToRefresh.union((int) cX - border, (int) cY - border, (int) cX
                   + border, (int) cY + border);

           mX = x;
           mY = y;

           return areaToRefresh;
    }

    private void touchUp(MotionEvent event) {
           float x = event.getX();
           float y = event.getY();

           mCurveEndX = x;
           mCurveEndY = y;
    }


    /**
     * 復原上一動作
     * return: false 表不能再undo; true 表能繼續undo
     */
    public boolean undo() {
           int totalAction = mDrawList.size();
           if (mTotalAction > 0) {
               mTotalAction -= 1;

               mBitmap = null;
               mCanvas = null;
               mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
               mCanvas = new Canvas(mBitmap);

               invalidate();
           }

           if (totalAction == 0 || mTotalAction <= 0) {
               return false;
           } else {
               return true;
           }
    }


    /**
     * 取消復原動作
     * return: false 表不能再 reUndo; true 表能繼續 reUndo
     */
    public boolean reUndo() {
           int totalAction = mDrawList.size();
           if (mTotalAction < totalAction) {
               mTotalAction += 1;

               mBitmap = null;
               mCanvas = null;
               mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
               mCanvas = new Canvas(mBitmap);

               invalidate();
           }

           if (totalAction == 0 || mTotalAction >= totalAction) {
               return false;
           } else {
               return true;
           }
    }


    /**
     * 檢查可復原動作的狀態
     * return: 0 表不能再 undo,也不能再 reUndo;1 表不能再 undo,但可再 reUndo;2 表可再 undo,但不能再 reUndo;3 表可再 undo,也可再 reUndo;
     */
    public int checkUndoStatus() {
           int totalAction = mDrawList.size();
           int result = 0;

           if (totalAction == 0) {    //沒有任何動作資訊
               result = 0;
           } else if (mTotalAction <= 0) {    //有動作資訊,但已「復原」至最前端
               result = 1;
           } else if (mTotalAction >= totalAction) {    //有動作資訊,但已「取消復原」至最後端
               result = 2;
           } else {
               result = 3;
           }

           return result;
    }


    /**
     * 清除整個 View 的畫面
     */
    public void clear() {
           mBackgroundBitmap = null;

           mDrawList.removeAll(mDrawList);
           mPaintsList.removeAll(mPaintsList);
           mRectsList.removeAll(mRectsList);
           mTotalAction = 0;

           mBitmap = null;
           mCanvas = null;
           mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
           mCanvas = new Canvas(mBitmap);

           invalidate();
    }


    /**
     * 設定整個 View 的畫面圖示
     */
    public void setWholeViewBitmap(Bitmap bitmap) {
        mBackgroundBitmap = bitmap;
        invalidate();
    } 


    /**
     * 設定為畫筆或板擦
     * @param penMode: 1 為畫筆, 0 為板擦
     */
    public void setPenMode(int penMode) {
        if (penMode == 0) {
            this.mPenMode = 0;
        } else {
            this.mPenMode = 1;
        }
    }

    /**
     * 取得是畫筆或板擦
     * @return: 1 為畫筆, 0 為板擦
     */
    public int getPenMode() {
        return this.mPenMode;
    }


    /**
     * 設定畫筆或板擦的寬度
     * @param width
     */
    public void setPaintStrokeWidth(float width) {
        this.mPaintWidth = width;
    }

    /**
     * 取得畫筆或板擦的寬度
     */
    public float getPaintStrokeWidth() {
        return this.mPaintWidth;
    }


    /**
     * 設定畫筆的顏色
     * @param width
     */
    public void setPaintColor(int color) {
        this.mPaintColor = color;
    }

    /**
     * 取得畫筆的顏色
     */
    public int getPaintColor() {
        return this.mPaintColor;
    }

}

Android 的繪圖白板元件(View)。 可當作一般的 View 元件使用。 setWholeViewBitmap(Bitmap bitmap):設定整個 View 的畫面圖示 setPenMode(int penMode):設定為畫筆或板擦 setPaintStrokeWidth(float width):設定畫筆或板擦的寬度 setPaintColor(int color):設定畫筆的顏色,话不多说自己看吧~可以直接复制代码就可以用。

Android 繪圖白板元件,有畫筆和板擦的功能 (转)