之前在博客园写的文章,今天转到此处。

原文链接http://www.cnblogs.com/yc0714/p/4654023.html

前一阵子做了一个项目,里面有用到画板,在手机上画图,类似一个电子白板,画出曲线,圆,矩形。。 后来查了资料,看了些大神的博客

单独优化出了一个小程序,在原来基础上新增了橡皮檫功能,画出的图形可以是曲线,直线,矩形,正方形,圆,椭圆,也可以筛选相册图片显示到画板,

画图的同时更改画笔的颜色

基本思路是在画板上确认两个点,一个起点,一个终点,根据选择的图形样式,拖动的时候有预览图形,松开时图形定下来显示到画板上。

曲线是用贝塞尔曲线,其余基本图形由两个点确定位置大小,canvas提供的方法就能很快画出来。

一. 一个Canvas对象有四大基本要素:

1.一个用来保存像素的Bitmap

2.一个Canvas在Bitmap上进行绘制操作

3.绘制的东西

4.绘制的画笔Paint

提供的方法有:

  canvas.drawArc (扇形)

  canvas.drawCircle(圆)

  canvas.drawOval(椭圆)

  canvas.drawLine(线)

  canvas.drawPoint(点)

  canvas.drawRect(矩形)

  canvas.drawRoundRect(圆角矩形)

  canvas.drawVertices(顶点)

  cnavas.drawPath(路径)

  canvas.drawBitmap (位图)

  canvas.drawPicture (图片)

  canvas.drawText(文本)

二.Paint(画笔)类

  要绘制图形,首先得调整画笔,按照自己的开发需要设置画笔的相关属性。Pain类的常用属性设置方法如下:

  setAntiAlias(); 设置画笔的锯齿效果

  setColor(); 设置画笔的颜色

  setARGB(); 设置画笔的A、R、G、B值

  setAlpha(); 设置画笔的Alpha值

  setTextSize(); 设置字体的尺寸

  setStyle(); 设置画笔的风格(空心或实心)

  setStrokeWidth(); 设置空心边框的宽度

  getColor(); 获取画笔的颜色

  setDither(); 获取跟清晰的图像采样

  setStrokeJoin(); 接合处为圆弧

  setStrokeCap(); 画笔样式圆形

三.自定义View的基本实现方法

  首先,我们需要自定义一个类,比如ControlView,继承于View类,也可以继承ViewGroup,因为ViewGroup是继承于View的,然后,复写View类的onDraw()函数。

  最后,在onDraw()函数中使用Paint和Canvas对象绘制我们需要的图形。

  drawBitmap(Bitmap bitmap, float left, float top, Paint paint);

  通过onTouchEvent(MotionEvent)的getAction()方法来获取Touch事件的类型,包括 ACTION_DOWN(按下触摸屏), ACTION_MOVE(按下触摸屏后移动受力点), ACTION_UP(松开触摸屏)

  和ACTION_CANCEL(不会由用户直接触发)。借助对于用户不同操作的判断,结合getRawX()、 getRawY()、getX()和getY()等方法来获取坐标,所有的绘画都在

  MotionEvent.ACTION_MOVE去做,MotionEvent.ACTION_UP(松开触摸屏)时,画出图形,更新画布

下面列出主要model代码:

  1.继承类IShape,AbsShape

public interface IShape { public void touchMove(int startX, int startY, int x, int y); public void drawShape(Canvas canvas); }

  

public abstract class AbsShape implements IShape { protected ControlView mView; protected Paint mPaint; public AbsShape(ControlView view, int model) { mView = view; // 去锯齿        mPaint = new Paint(); // 去锯齿        mPaint.setAntiAlias(true); // 设置paint的颜色        mPaint.setColor(model == ControlView.MODEL_ERASE ? Constants.BACK_COLOR : view.getPenColor()); // 设置paint的 style 为STROKE:空心 mPaint.setStyle(Paint.Style.STROKE); // 设置paint的外框宽度        mPaint.setStrokeWidth(model == ControlView.MODEL_ERASE ? view.getEraserWidth() : view.getPenWidth()); // 获取跟清晰的图像采样        mPaint.setDither(true); // 接合处为圆弧 mPaint.setStrokeJoin(Paint.Join.ROUND); // 画笔样式圆形 mPaint.setStrokeCap(Paint.Cap.ROUND); } }

  ①曲线

public class Path extends AbsShape { private Rect mInvalidRect; protected SerializablePath mPath; private float mStartX = 0; private float mStartY = 0; public Path(ControlView view, int model) { super(view, model); mPath = new SerializablePath(); mInvalidRect = new Rect(); } public void touchMove(int startX, int startY, int x, int y) { // 判断是不是down事件        if (mStartX == 0 && mStartY == 0) { mStartX = startX; mStartY = startY; mPath.moveTo(mStartX, mStartY); } int border = (int) mPaint.getStrokeWidth(); mInvalidRect.set((int) mStartX - border, (int) mStartY - border, (int) mStartX + border, (int) mStartY + border); float mCurveEndX = (x + mStartX) / 2; float mCurveEndY = (y + mStartY) / 2; // 使用贝赛尔曲线 mPath.quadTo(mStartX, mStartY, mCurveEndX, mCurveEndY); mInvalidRect.union((int) mCurveEndX - border, (int) mCurveEndY - border, (int) mCurveEndX + border, (int) mCurveEndY + border); mStartX = x; mStartY = y; mView.invalidate(mInvalidRect); } public void drawShape(Canvas canvas) { canvas.drawPath(mPath, mPaint); } }

  ②直线

  

public class Line extends AbsShape { private Rect mInvalidRect; protected SerializablePath mPath; public Line(ControlView view, int model) { super(view, model); mPath = new SerializablePath(); mInvalidRect = new Rect(); } public void touchMove(int startX, int startY, int x, int y) { mPath.reset(); mPath.moveTo(startX, startY); mPath.lineTo(x, y); int border = (int) mPaint.getStrokeWidth() * 2; mInvalidRect.set((int) startX - border, (int) startY - border, (int) startX + border, (int) startY + border); mInvalidRect.union((int) x - border, (int) y - border, (int) x + border, (int) y + border); mView.invalidate(mInvalidRect); } public void drawShape(Canvas canvas) { canvas.drawPath(mPath, mPaint); } }

  ③矩形

public class Rectangle extends AbsShape { private int mX; private int mY; private int mStartX; private int mStartY; private Rect mInvalidRect; public Rectangle(ControlView view, int model) { super(view, model); mInvalidRect = new Rect(); } public void touchMove(int startX, int startY, int x, int y) { mStartX = startX; mStartY = startY; mX = x; mY = y; int border = (int) mPaint.getStrokeWidth(); mInvalidRect.set(mStartX - border, mStartY - border, mStartX + border, mStartY + border); mInvalidRect.union(x - border, y - border, x + border, y + border); mView.invalidate(mInvalidRect); } public void drawShape(Canvas canvas) { canvas.drawRect(mStartX, mStartY, mX, mY, mPaint); } }

  ④正方形

  

public class Square extends AbsShape { private int mStartX; private int mStartY; private int mX; private int mY; private Rect mInvalidRect; public Square(ControlView view, int model) { super(view, model); mInvalidRect = new Rect(); } public void touchMove(int startX, int startY, int x, int y) { mStartX = startX; mStartY = startY; mX = x; mY = y; int border = (int) mPaint.getStrokeWidth(); mInvalidRect.set(mStartX - border, mStartY - border, mStartX + border, mStartY + border); mInvalidRect.union(x - border, y - border, x + border, y + border); mView.invalidate(mInvalidRect); } public void drawShape(Canvas canvas) { if ((mX > mStartX && mY > mStartY) || (mX < mStartX && mY < mStartY)) { if (Math.abs(mX - mStartX) > Math.abs(mY - mStartY)) { canvas.drawRect(mStartX, mStartY, mStartX + mY - mStartY, mY, mPaint); } else { canvas.drawRect(mStartX, mStartY, mX, mStartY + mX - mStartX, mPaint); } } else { if (Math.abs(mX - mStartX) > Math.abs(mY - mStartY)) { canvas.drawRect(mStartX, mStartY, mStartX + mStartY - mY, mY, mPaint); } else { canvas.drawRect(mStartX, mStartY, mX, mStartY + mStartX - mX, mPaint); } } } }

  ⑤椭圆

  

public class Oval extends AbsShape { private Rect mInvalidRect; private RectF mDrawRect; public Oval(ControlView view, int model) { super(view, model); mInvalidRect = new Rect(); mDrawRect = new RectF(); } public void touchMove(int startX, int startY, int x, int y) { int border = (int) mPaint.getStrokeWidth(); mInvalidRect.set(startX - border, startY - border, startX + border, startY + border); mInvalidRect.union(x - border, y - border, x + border, y + border); mDrawRect.set(startX, startY, x, y); mView.invalidate(mInvalidRect); } public void drawShape(Canvas canvas) { canvas.drawOval(mDrawRect, mPaint); } }

  ⑥圆

  

public class Circle extends AbsShape { private Rect mInvalidRect; private int cx; private int cy; private int radius; public Circle(ControlView view, int model) { super(view, model); mInvalidRect = new Rect(); } public void touchMove(int startX, int startY, int x, int y) { cx = (int) ((x + startX) / 2); cy = (int) ((y + startY) / 2); radius = (int) Math.sqrt(Math.pow(x - startX, 2) + Math.pow(y - startY, 2)) / 2; int border = (int) mPaint.getStrokeWidth(); mInvalidRect.set(cx - radius - border, cy - radius - border, cx + radius + border, cy + radius + border); mView.invalidate(mInvalidRect); } public void drawShape(Canvas canvas) { canvas.drawCircle(cx, cy, radius, mPaint); } }

  曲线和直线的SerializablePath:

  

public class SerializablePath extends Path implements Serializable { private static final long serialVersionUID = 1L; private ArrayList<float[]> pathPoints; public SerializablePath() { super(); pathPoints = new ArrayList<float[]>(); } public SerializablePath(SerializablePath path) { super(path); pathPoints = path.pathPoints; } public void addPathPoints(float[] points) { pathPoints.add(points); } public void loadPathPointsAsQuadTo() { float[] initPoints = pathPoints.remove(0); moveTo(initPoints[0], initPoints[1]); for (float[] pointSet : pathPoints) { quadTo(pointSet[0], pointSet[1], pointSet[2], pointSet[3]); } } }

四.核心操作代码

  主界面WhiteBoardActivity.java

  

public class WhiteBoardActivity extends Activity { private PopupWindow mPopupWindow; private LayoutInflater mLayoutInflater; private View mToolbox; private ControlView drawView; private ImageView mColorBlack; private ImageView mColorBlue; private ImageView mColorGreen; private ImageView mColorRed; private ImageView mColorYellow; private ImageView mColor; private ImageView mEdit; private ImageView mEraser; private ImageView mClear; private ImageView mSettings; private ImageView mShape; View width1; View width2; View width3; // 获取屏幕尺寸 DisplayMetrics dm; @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 保持屏幕常亮 getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_ewhiteboard); dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); int screenwWidth = dm.widthPixels; // 屏幕宽(dip,如:720dip)        int screenHeight = dm.heightPixels; // 屏幕宽(dip,如:1280dip)        drawView = new ControlView(this, screenwWidth, screenHeight); ((ViewGroup) findViewById(R.id.container)).addView(drawView); drawView.setPenColor(Color.BLACK); drawView.setPenWidth(3f); mLayoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); mPopupWindow = new PopupWindow(new View(this)); mPopupWindow.setFocusable(true); mPopupWindow.setBackgroundDrawable(new BitmapDrawable()); mToolbox = findViewById(R.id.toolbox); mSettings = (ImageView) findViewById(R.id.settings); mColor = (ImageView) findViewById(R.id.color); mEdit = (ImageView) findViewById(R.id.edit); mEraser = (ImageView) findViewById(R.id.eraser); mClear = (ImageView) findViewById(R.id.clear); mShape = (ImageView) findViewById(R.id.shape); initToolbox(); initColor(); initPenSize(); initEraserSize(); initShape(); } private void initToolbox() { mEdit.setSelected(true); drawView.setModel(ControlView.MODEL_NORMAL); mClear.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { new AlertDialog.Builder(WhiteBoardActivity.this) .setMessage("确定要清除白板吗?") .setPositiveButton("确定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { drawView.clear(); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }).create().show(); } }); mSettings.setSelected(false); mSettings.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Intent intent = new Intent(); intent.setClass(WhiteBoardActivity.this, SettingsActivity.class); startActivity(intent); } }); } private void initShape() { final int POP_WINDOW_WIDTH = WindowManager.LayoutParams.WRAP_CONTENT; final int POP_WINDOW_HEIGHT = Utils.dip2px(this, 60); final View popupView = mLayoutInflater.inflate( R.layout.view_popup_shape, null); final View width1 = popupView.findViewById(R.id.pen_width1); final View width2 = popupView.findViewById(R.id.pen_width2); final View width3 = popupView.findViewById(R.id.pen_width3); final View width4 = popupView.findViewById(R.id.pen_width4); final View width5 = popupView.findViewById(R.id.pen_width5); final View width6 = popupView.findViewById(R.id.pen_width6); mShape.setOnClickListener(new View.OnClickListener() { public void onClick(View paramView) { mPopupWindow.setContentView(popupView); mPopupWindow.setWidth(POP_WINDOW_WIDTH); mPopupWindow.setHeight(POP_WINDOW_HEIGHT); mPopupWindow.setAnimationStyle(R.style.pop_settings); mPopupWindow.showAtLocation( mShape, Gravity.LEFT | Gravity.TOP, mToolbox.getRight(), mToolbox.getTop() + mShape.getTop() - Utils.dip2px(WhiteBoardActivity.this, 5)); int penSize = drawView.getShap(); if (penSize == ControlView.SHAPE_PATH) { width1.setSelected(true); width2.setSelected(false); width3.setSelected(false); width4.setSelected(false); width5.setSelected(false); width6.setSelected(false); } else if (penSize == ControlView.SHAPE_LINE) { width2.setSelected(true); width1.setSelected(false); width3.setSelected(false); width4.setSelected(false); width5.setSelected(false); width6.setSelected(false); } else if (penSize == ControlView.SHAPE_CIRCLE) { width3.setSelected(true); width1.setSelected(false); width2.setSelected(false); width4.setSelected(false); width5.setSelected(false); width6.setSelected(false); } else if (penSize == ControlView.SHAPE_SQUARE) { width4.setSelected(true); width1.setSelected(false); width2.setSelected(false); width3.setSelected(false); width5.setSelected(false); width6.setSelected(false); } else if (penSize == ControlView.SHAPE_RECT) { width5.setSelected(true); width1.setSelected(false); width2.setSelected(false); width3.setSelected(false); width4.setSelected(false); width6.setSelected(false); } else if (penSize == ControlView.SHAPE_OVAL) { width6.setSelected(true); width1.setSelected(false); width2.setSelected(false); width3.setSelected(false); width4.setSelected(false); width5.setSelected(false); } } }); width1.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { drawView.setShape(ControlView.SHAPE_PATH); mPopupWindow.dismiss(); mShape.setImageResource(R.drawable.ic_path); } }); width2.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { drawView.setShape(ControlView.SHAPE_LINE); mPopupWindow.dismiss(); mShape.setImageResource(R.drawable.ic_line); } }); width3.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { drawView.setShape(ControlView.SHAPE_CIRCLE); mPopupWindow.dismiss(); mShape.setImageResource(R.drawable.ic_circle); } }); width4.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { drawView.setShape(ControlView.SHAPE_SQUARE); mPopupWindow.dismiss(); mShape.setImageResource(R.drawable.ic_square); } }); width5.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { drawView.setShape(ControlView.SHAPE_RECT); mPopupWindow.dismiss(); mShape.setImageResource(R.drawable.ic_rect); } }); width6.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { drawView.setShape(ControlView.SHAPE_OVAL); mPopupWindow.dismiss(); mShape.setImageResource(R.drawable.ic_oval); } }); } private void initColor() { final int POP_WINDOW_WIDTH = WindowManager.LayoutParams.WRAP_CONTENT; final int POP_WINDOW_HEIGHT = Utils.dip2px(this, 60); final View popupView = mLayoutInflater.inflate( R.layout.view_color_popup, null); final View colorFrame = findViewById(R.id.color_frame); colorFrame.setOnClickListener(new View.OnClickListener() { public void onClick(View paramView) { mPopupWindow.setContentView(popupView); mPopupWindow.setWidth(POP_WINDOW_WIDTH); mPopupWindow.setHeight(POP_WINDOW_HEIGHT); mPopupWindow.setAnimationStyle(R.style.pop_settings); mPopupWindow.showAtLocation( colorFrame, Gravity.LEFT | Gravity.TOP, mToolbox.getRight(), mToolbox.getTop() + colorFrame.getTop() - Utils.dip2px(WhiteBoardActivity.this, 5)); } }); mColor.setBackgroundColor(Color.BLACK); mColorBlack = (ImageView) popupView.findViewById(R.id.color_black); mColorBlack.setBackgroundColor(Color.BLACK); mColorBlue = (ImageView) popupView.findViewById(R.id.color_blue); mColorBlue.setBackgroundColor(Color.BLUE); mColorGreen = (ImageView) popupView.findViewById(R.id.color_green); mColorGreen.setBackgroundColor(Color.GREEN); mColorRed = (ImageView) popupView.findViewById(R.id.color_red); mColorRed.setBackgroundColor(Color.RED); mColorYellow = (ImageView) popupView.findViewById(R.id.color_yellow); mColorYellow.setBackgroundColor(Color.YELLOW); mColorBlack.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mColor.setBackgroundColor(Color.BLACK); drawView.setPenColor(Color.BLACK); mPopupWindow.dismiss(); } }); mColorBlue.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mColor.setBackgroundColor(Color.BLUE); drawView.setPenColor(Color.BLUE); mPopupWindow.dismiss(); } }); mColorGreen.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mColor.setBackgroundColor(Color.GREEN); drawView.setPenColor(Color.GREEN); mPopupWindow.dismiss(); } }); mColorRed.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mColor.setBackgroundColor(Color.RED); drawView.setPenColor(Color.RED); mPopupWindow.dismiss(); } }); mColorYellow.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mColor.setBackgroundColor(Color.YELLOW); drawView.setPenColor(Color.YELLOW); mPopupWindow.dismiss(); } }); } private void initPenSize() { final int POP_WINDOW_WIDTH = WindowManager.LayoutParams.WRAP_CONTENT; final int POP_WINDOW_HEIGHT = Utils.dip2px(this, 60); final View popupView = mLayoutInflater.inflate(R.layout.view_popup_pen, null); final View width1 = popupView.findViewById(R.id.pen_width1); final View width2 = popupView.findViewById(R.id.pen_width2); final View width3 = popupView.findViewById(R.id.pen_width3); mEdit.setOnClickListener(new View.OnClickListener() { public void onClick(View paramView) { mEdit.setSelected(true); mEraser.setSelected(false); drawView.setModel(ControlView.MODEL_NORMAL); mPopupWindow.setContentView(popupView); mPopupWindow.setWidth(POP_WINDOW_WIDTH); mPopupWindow.setHeight(POP_WINDOW_HEIGHT); mPopupWindow.setAnimationStyle(R.style.pop_settings); mPopupWindow.showAtLocation(mEdit, Gravity.LEFT | Gravity.TOP, mToolbox.getRight(), mToolbox.getTop() + mEdit.getTop() - Utils.dip2px(WhiteBoardActivity.this, 5)); float penSize = drawView.getPenWidth(); if (penSize == 1) { width1.setSelected(true); width2.setSelected(false); width3.setSelected(false); } else if (penSize == 3) { width2.setSelected(true); width1.setSelected(false); width3.setSelected(false); } else if (penSize == 6) { width3.setSelected(true); width1.setSelected(false); width2.setSelected(false); } } }); width1.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { drawView.setPenWidth(1f); mPopupWindow.dismiss(); } }); width2.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { drawView.setPenWidth(3f); mPopupWindow.dismiss(); } }); width3.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { drawView.setPenWidth(6f); mPopupWindow.dismiss(); } }); } private void initEraserSize() { final View popupView = mLayoutInflater.inflate( R.layout.view_popup_eraser, null); width1 = popupView.findViewById(R.id.pen_width1); width2 = popupView.findViewById(R.id.pen_width2); width3 = popupView.findViewById(R.id.pen_width3); mEraser.setOnClickListener(new View.OnClickListener() { public void onClick(View paramView) { mEdit.setSelected(false); mEraser.setSelected(true); drawView.setModel(ControlView.MODEL_ERASE); // 默认30 drawView.setEraserWidth(30f); } }); } @Override protected void onResume() { super.onResume(); SharedPreferences pref = PreferenceManager .getDefaultSharedPreferences(this); drawView.setOnlyPenInput(pref.getBoolean("only_pen_input", false)); } @Override public void onDestroy() { super.onDestroy(); } }

  操作类ControlView.java

  

public class ControlView extends ViewGroup { public static final int MODEL_NORMAL = 1; public static final int MODEL_ERASE = 2; public static String pointmsg; protected int mModel = MODEL_NORMAL; public static final int SHAPE_PATH = 1; public static final int SHAPE_LINE = 2; public static final int SHAPE_CIRCLE = 3; public static final int SHAPE_SQUARE = 4; public static final int SHAPE_RECT = 5; public static final int SHAPE_OVAL = 6; public static final int IMAGE = 8; private int mShapeType = SHAPE_PATH; public static final float scale = 210f / 297f; private Context mContext; public Hardware mHardware; public boolean mOnlyPenInput; protected Canvas mCanvas; protected Bitmap mBitmap; protected float mPenWidth = 3f; protected float mEraserWidth = 10f; protected int mColor = Color.BLACK; private Paint mBitmapPaint; private IShape mEraser; private IShape mShape; private int mStartX = 0; private int mStartY = 0; private int x = 0, y = 0; protected boolean mIsCanvasMoving; private boolean mIsTouchUp; int index = 1; int width = 0, height = 0; // 屏幕的宽高    public ControlView(Context context, int width, int height) { super(context); setWillNotDraw(false); mContext = context; mHardware = Hardware.getInstance(mContext); this.width = width; this.height = height; mHardware.addPenButtonEvent(this); mBitmapPaint = new Paint(Paint.DITHER_FLAG); mBitmap = MainApplication.getBitmap(); mCanvas = new Canvas(mBitmap); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { for (int i = 0; i < getChildCount(); i++) { getChildAt(i).layout(l, t, r, b); } } @Override protected void onDraw(Canvas canvas) { // 在View上绘制        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); if (mShape != null && !mIsTouchUp) { mShape.drawShape(canvas); } } @Override public boolean onTouchEvent(MotionEvent event) { if (mOnlyPenInput) { if (mHardware.hasPenDigitizer() && mHardware.isPenEvent(event)) { return touchEvent(event); } else { return false; } } else { return touchEvent(event); } } private boolean touchEvent(MotionEvent event) { if ((mHardware.hasPenDigitizer() && mHardware.isPenEvent(event)) || !mOnlyPenInput) { // 笔的按钮只有在move才能检测到,所以有可能在move时改变形状 // 所以所有的绘画都在move中去做            if (mModel == MODEL_ERASE || mHardware.isPenButtonPressed(event)) { mShape = mEraser; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mStartX = (int) event.getX(); mStartY = (int) event.getY(); // 创建一个橡皮                mEraser = new Path(this, MODEL_ERASE); // 根据选择创建相应图形                switch (mShapeType) { case SHAPE_PATH: // 随意曲线                    mShape = new Path(this, MODEL_NORMAL); break; case SHAPE_LINE:// 直线                    mShape = new Line(this, MODEL_NORMAL); break; case SHAPE_CIRCLE://                    mShape = new Circle(this, MODEL_NORMAL); break; case SHAPE_SQUARE:// 正方形                    mShape = new Square(this, MODEL_NORMAL); break; case SHAPE_RECT:// 矩形                    mShape = new Rectangle(this, MODEL_NORMAL); break; case SHAPE_OVAL:// 椭圆形                    mShape = new Oval(this, MODEL_NORMAL); break; default: break; } return true; case MotionEvent.ACTION_MOVE: x = (int) event.getX(); y = (int) event.getY(); // 进入拖动模式                if (event.getPointerCount() >= 2) { mIsCanvasMoving = true; resetView(); return false; } // 虽然只有一个触摸点,但是没恢复绘画模式                if (!mIsCanvasMoving) { // 是否结束绘画                    mIsTouchUp = false; mShape.touchMove(mStartX, mStartY, x, y); } return true; case MotionEvent.ACTION_UP: if (!mIsCanvasMoving) { mIsTouchUp = true; mShape.drawShape(mCanvas); // 更新画布 invalidate(); } else { // 恢复绘画模式                    mIsCanvasMoving = false; } return true; } } return false; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mHardware.onKeyDown(keyCode, event)) { return true; } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (mHardware.onKeyUp(keyCode, event)) { return true; } return super.onKeyUp(keyCode, event); } public void resetView() { mIsTouchUp = true; invalidate(); } public void clear() { restoreBitmap(); invalidate(); } public void setPenWidth(float penWidth) { mPenWidth = penWidth; } public float getPenWidth() { return mPenWidth; } public void setEraserWidth(float penWidth) { mEraserWidth = penWidth; } public float getEraserWidth() { return mEraserWidth; } public void setPenColor(int color) { mColor = color; } public int getPenColor() { return mColor; } public void setModel(int model) { mModel = model; } public void setShape(int shape) { mShapeType = shape; } public int getShap() { return mShapeType; } public boolean useForWriting(MotionEvent event) { return !mOnlyPenInput || mHardware.isPenEvent(event); } public boolean useForTouch(MotionEvent event) { return !mOnlyPenInput || (mOnlyPenInput && !mHardware.isPenEvent(event)); } private void restoreBitmap() { mBitmap.eraseColor(Constants.BACK_COLOR); mCanvas = new Canvas(mBitmap); } public void setOnlyPenInput(boolean b) { mOnlyPenInput = b; } }

  MainApplication类

  

public class MainApplication extends Application { public static final float scale = 210f / 297f; public static int CANVAS_WIDTH; public static int CANVAS_HEIGHT; public static int SCREEN_WIDTH; public static int SCREEN_HEIGHT; private static Bitmap curBitmap; @SuppressWarnings("deprecation") @Override public void onCreate() { super.onCreate(); Display display = ((WindowManager) getSystemService("window")) .getDefaultDisplay(); if (display.getWidth() < display.getHeight()) { SCREEN_HEIGHT = display.getWidth(); SCREEN_WIDTH = display.getHeight(); } else { SCREEN_WIDTH = display.getWidth(); SCREEN_HEIGHT = display.getHeight(); } CANVAS_WIDTH = MainApplication.SCREEN_WIDTH; CANVAS_HEIGHT = (int) (MainApplication.SCREEN_WIDTH / scale); createPage(); } private static Bitmap createBitmap() { Bitmap bitmap = Bitmap.createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT, Bitmap.Config.ARGB_8888); bitmap.eraseColor(Constants.BACK_COLOR); return bitmap; } public static Bitmap getBitmap() { return curBitmap; } public static void createPage() { curBitmap = createBitmap(); } @Override public void onTerminate() { super.onTerminate(); curBitmap.recycle(); curBitmap = null; } }

  

  下面是效果图:

  好了,以上就是这个白板的主要功能和核心代码,有任何好的建议或者不明白的可以在下方评论。

  源码就不上传了,其余就是一些布局和图片。


更多相关文章

  1. Android(安卓)的提示接口-Toast
  2. Android之基础复习2D图形一
  3. Android(安卓)地图 —— 百度地图
  4. Android基于开源项目的WheelView的时间、地址联动选择对话框
  5. android开发-使用Dialog AlertDialog
  6. ExpandableListView用法和实例
  7. android图形系统详解:View layer
  8. Android(安卓)Launcher分析和修改2——Icon修改、界面布局调整、
  9. css margin属性理解与使用

随机推荐

  1. 开发者必看|Android(安卓)8.0 新特性及开
  2. Android(安卓)控件之 Spinner下拉列表 使
  3. React Native添加Android原生模块
  4. android 机器人
  5. 浅析Android下的Android.mk文件
  6. Android事件分发机制完全解析,带你从源码
  7. Study on Android【一】--概述
  8. android简介
  9. Android(安卓)ANR错误排查
  10. Android(安卓)Metro风格的Launcher开发系