前一阵子做了一个项目,里面有用到画板,在手机上画图,类似一个电子白板,画出曲线,圆,矩形。。 后来查了资料,
单独优化出了一个小程序,在原来基础上新增了橡皮檫功能,画出的图形可以是曲线,直线,矩形,正方形,圆,椭圆,也可以筛选相册图片显示到画板,
画图的同时更改画笔的颜色
基本思路是在画板上确认两个点,一个起点,一个终点,根据选择的图形样式,拖动的时候有预览图形,松开时图形定下来显示到画板上。
曲线是用贝塞尔曲线,其余基本图形由两个点确定位置大小,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;
}
}