这是我第一次使用Android中的Canvas类
我想要的是使用Path类在画布上绘制不同的颜色和画笔。我不想使用Bitmap,因为我需要对它应用适当的撤消重做功能。我正在做的只是在画布上绘制,但在onDraw函数中,我使用for循环绘制整个路径,但如果用户选择不同的颜色和画笔来绘制,则会出现此问题。然后我将把所有这些存储在特定的Paint列表中,我现在正在做同样的事情。还有另一种好办法吗?
我使用的代码是:
DrawView类
public class DrawView extends View implements OnTouchListener {
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Paint> paints = new ArrayList<Paint>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
private Context context;
private int initialcolor = 0xff000000;
private StyleEnum styleEnum;
private Style mStyle;
private int strokeWidth = 6;
private int effect;
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
mPaint = new Paint();
// add paint strokes
addPaintStrokes(mPaint);
mCanvas = new Canvas();
mPath = new Path();
paths.add(mPath);
paints.add(mPaint);
rect = new Rect();
mRectPaint = new Paint(Paint.DITHER_FLAG);
mRectPaint.setColor(Color.WHITE);
mRectPaint.setStyle(Paint.Style.FILL);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
这里我使用另一个类型为Paint的ArrayList来包含要在每个新创建的对象上维护的绘制相关项
@Override
protected void onDraw(Canvas canvas) {
float cX = canvas.getWidth() / 2.0f;
float cY = canvas.getHeight() / (mScaleFactor * 10);
canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor, cX, cY);
RectF rec = new RectF(0, 0, canvas.getWidth(), canvas.getHeight());
canvas.drawRect(rec, mRectPaint);
if( paths.size() > 0 ){
for(int i = 0 ; i < paths.size() ; i++){
canvas.drawPath(paths.get(i), paints.get(i));
}
}
rect = canvas.getClipBounds();
canvas.restore();
}
private void touch_start(float x, float y) {
mStyle.strokeStart(x, y);
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= 4 || dy >= 4) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mStyle.stroke(mCanvas, x, y);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath = new Path();
paths.add(mPath);
mPaint = new Paint();
addPaintStrokes(mPaint);
paints.add(mPaint);
}
public void onClickUndo () {
if (paths.size()>0) {
undonePaths.add(paths.remove(paths.size()-1));
invalidate();
}
}
public void onClickRedo (){
if (undonePaths.size()>0) {
paths.add(undonePaths.remove(undonePaths.size()-1));
invalidate();
}
}
@Override
public boolean onTouch(View arg0, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
if (isDrawingEnabled) {
// Drawing Enable
float x = event.getX();
float y = event.getY();
x = x / mScaleFactor + rect.left;
y = y / mScaleFactor + rect.top;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
} else{
// Dragging Enable
final int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
float x = event.getX();
float y = event.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = event.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = event.findPointerIndex(mActivePointerId);
final float x = event.getX(pointerIndex);
final float y = event.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
}
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = event.getX(newPointerIndex);
mLastTouchY = event.getY(newPointerIndex);
mActivePointerId = event.getPointerId(newPointerIndex);
}
}
break;
}
}
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if(!isDrawingEnabled){
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 5.0f));
invalidate();
}
return true;
}
}
private void addPaintStrokes(Paint p){
p.setAntiAlias(true);
p.setDither(true);
p.setColor(initialcolor);
setBrushStyle(effect);
p.setStyle(Paint.Style.STROKE);
p.setStrokeJoin(Paint.Join.ROUND);
p.setStrokeCap(Paint.Cap.ROUND);
p.setStrokeWidth(getStrokeWidth());
}
public void setBrushStyle(int mBrushStyle) {
Log.e("mBrushStyle : ", "" + mBrushStyle);
this.effect = mBrushStyle;
switch (mBrushStyle) {
case 0: {
mPaint.setMaskFilter(null);
break;
}
case 1: {
MaskFilter mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },
0.4f, 6, 3.5f);
mPaint.setMaskFilter(mEmboss);
break;
}
case 2: {
int brushSize = getStrokeWidth();
if (brushSize > 0) {
MaskFilter mBlur = new BlurMaskFilter(brushSize,
BlurMaskFilter.Blur.NORMAL);
mPaint.setMaskFilter(mBlur);
} else {
MaskFilter mBlur = new BlurMaskFilter(1,
BlurMaskFilter.Blur.NORMAL);
mPaint.setMaskFilter(mBlur);
}
break;
}
}
}
答案 0 :(得分:1)
尝试将路径移动到undonePaths以在删除路径时保存路径。
撤消逻辑: 1.将当前路径移动到undonePaths(temp arraylist) 2.删除路径arraylist的当前路径。
重做逻辑: 1.将当前的undonePaths添加到路径arraylist 2.从undonePaths中删除移动的路径
这对我来说是gd,请尝试下面的代码段。
public void onClickUndo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
} else {
}
}
public void onClickRedo() {
if (undonePaths.size() > 0) {
paths.add(undonePaths.remove(undonePaths.size() - 1));
invalidate();
} else {
}
}
享受编码:) :):)
答案 1 :(得分:0)
问题在于,添加了每个路径后,每次调用onDraw
时,您都会在屏幕上累积更多内容。
如果您可以限制允许的撤消数量,则可以使用位图执行此操作。像这样创建你的位图:
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, h, oldWidth, oldHeight);
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
在touch_up
方法中,一旦paths
ArrayList达到一定大小(您将支持的撤消级别数),请取其第一个路径并将其绘制到mCanvas
(在此方法中,因此只执行一次)并将其从ArrayList(以及与其他ArrayList关联的Paint)中删除。在onDraw
方法中,首先绘制位图。
如果你必须有无限制的撤销,我认为你仍然可以用Bitmap做到这一点。只需保留您现在拥有的相同数组列表,但只能在触摸方法中绘制到mBitmap
。仅在mBitmap
方法中绘制onDraw
。当您需要撤消时,您可以清除mBitmap
,删除最后一条路径,并将所有剩余路径重绘为mBitmap
一次。