我正在尝试实现一个应用程序来从设备获取图像并将其添加到画布然后使用画笔和橡皮擦开始绘制(就像Snapchat的想法) 我使用Drawing app作为基础
http://code.tutsplus.com/series/create-a-drawing-app-on-android--cms-704
我现在的问题是,当我在位图上绘制时,它开始绘制,但是当我完成并触摸时,绘图消失了。
这是问题的视频
https://vid.me/rgnF(尝试将声音静音有一些噪音:))
任何帮助将不胜感激。谢谢
public class DrawingView extends View {
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
public Bitmap canvasBitmap;
//brush sizes
private float brushSize, lastBrushSize;
//erase flag
private boolean erase=false;
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
//setup drawing
private void setupDrawing(){
//prepare for drawing and setup paint stroke properties
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
//size assigned to view
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
//draw the view - will be called after touch event
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
//redraw
invalidate();
return true;
}
//update color
public void setColor(String newColor){
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
//set brush size
public void setBrushSize(float newSize){
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
//get and set last brush size
public void setLastBrushSize(float lastSize){
lastBrushSize=lastSize;
}
public float getLastBrushSize(){
return lastBrushSize;
}
//set erase true or false
public void setErase(boolean isErase){
erase=isErase;
if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
else drawPaint.setXfermode(null);
}
//start new drawing
public void startNew(){
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
}
public class MainActivity extends Activity implements OnClickListener {
//custom drawing view
private DrawingView drawView;
//buttons
private ImageButton currPaint, drawBtn, eraseBtn, newBtn, saveBtn;
//sizes
private float smallBrush, mediumBrush, largeBrush;
Button mBtnPick;
int mWidth;
int mHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWidth = mHeight = 0;
//get drawing view
drawView = (DrawingView)findViewById(R.id.drawing);
//get the palette and first color button
LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors);
currPaint = (ImageButton)paintLayout.getChildAt(0);
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
//sizes from dimensions
smallBrush = getResources().getInteger(R.integer.small_size);
mediumBrush = getResources().getInteger(R.integer.medium_size);
largeBrush = getResources().getInteger(R.integer.large_size);
//draw button
drawBtn = (ImageButton)findViewById(R.id.draw_btn);
drawBtn.setOnClickListener(this);
//set initial size
drawView.setBrushSize(mediumBrush);
//erase button
eraseBtn = (ImageButton)findViewById(R.id.erase_btn);
eraseBtn.setOnClickListener(this);
//new button
newBtn = (ImageButton)findViewById(R.id.new_btn);
newBtn.setOnClickListener(this);
//save button
saveBtn = (ImageButton)findViewById(R.id.save_btn);
saveBtn.setOnClickListener(this);
// Getting reference to Button "Pick an Image"
mBtnPick = (Button) findViewById(R.id.button);
// Setting OnClickListener for the button
mBtnPick.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent();
i.setType("image/*");
i.setAction(Intent.ACTION_GET_CONTENT);
Intent customChooserIntent = Intent.createChooser(i, "Pick an image");
startActivityForResult(customChooserIntent, 10);
}
});
if(savedInstanceState!=null){
mWidth = savedInstanceState.getInt("width");
mHeight = savedInstanceState.getInt("height");
Bitmap bitmap = savedInstanceState.getParcelable("bitmap");
if(bitmap!=null){
drawView.canvasBitmap=bitmap;
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
//user clicked paint
public void paintClicked(View view){
//use chosen color
//set erase false
drawView.setErase(false);
drawView.setBrushSize(drawView.getLastBrushSize());
if(view!=currPaint){
ImageButton imgView = (ImageButton)view;
String color = view.getTag().toString();
drawView.setColor(color);
//update ui
imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint));
currPaint=(ImageButton)view;
}
}
@Override
public void onClick(View view){
if(view.getId()==R.id.draw_btn){
//draw button clicked
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Brush size:");
brushDialog.setContentView(R.layout.brush_chooser);
//listen for clicks on size buttons
ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
smallBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(smallBrush);
drawView.setLastBrushSize(smallBrush);
brushDialog.dismiss();
}
});
ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
mediumBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(mediumBrush);
drawView.setLastBrushSize(mediumBrush);
brushDialog.dismiss();
}
});
ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
largeBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(false);
drawView.setBrushSize(largeBrush);
drawView.setLastBrushSize(largeBrush);
brushDialog.dismiss();
}
});
//show and wait for user interaction
brushDialog.show();
}
else if(view.getId()==R.id.erase_btn){
//switch to erase - choose size
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Eraser size:");
brushDialog.setContentView(R.layout.brush_chooser);
//size buttons
ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
smallBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(true);
drawView.setBrushSize(smallBrush);
brushDialog.dismiss();
}
});
ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
mediumBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(true);
drawView.setBrushSize(mediumBrush);
brushDialog.dismiss();
}
});
ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
largeBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
drawView.setErase(true);
drawView.setBrushSize(largeBrush);
brushDialog.dismiss();
}
});
brushDialog.show();
}
else if(view.getId()==R.id.new_btn){
//new button
AlertDialog.Builder newDialog = new AlertDialog.Builder(this);
newDialog.setTitle("New drawing");
newDialog.setMessage("Start new drawing (you will lose the current drawing)?");
newDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
drawView.startNew();
dialog.dismiss();
}
});
newDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
dialog.cancel();
}
});
newDialog.show();
}
else if(view.getId()==R.id.save_btn){
//save drawing
AlertDialog.Builder saveDialog = new AlertDialog.Builder(this);
saveDialog.setTitle("Save drawing");
saveDialog.setMessage("Save drawing to device Gallery?");
saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
//save drawing
drawView.setDrawingCacheEnabled(true);
//attempt to save
String imgSaved = MediaStore.Images.Media.insertImage(
getContentResolver(), drawView.getDrawingCache(),
UUID.randomUUID().toString()+".png", "drawing");
//feedback
if(imgSaved!=null){
Toast savedToast = Toast.makeText(getApplicationContext(),
"Drawing saved to Gallery!", Toast.LENGTH_SHORT);
savedToast.show();
}
else{
Toast unsavedToast = Toast.makeText(getApplicationContext(),
"Oops! Image could not be saved.", Toast.LENGTH_SHORT);
unsavedToast.show();
}
drawView.destroyDrawingCache();
}
});
saveDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
dialog.cancel();
}
});
saveDialog.show();
}
}
// Courtesy : developer.android.com/training/displaying-bitmaps/load-bitmap.html
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
private Bitmap getBitmapFromUri(Uri data){
Bitmap bitmap = null;
// Starting fetch image from file
InputStream is=null;
try {
is = getContentResolver().openInputStream(data);
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// BitmapFactory.decodeFile(path, options);
BitmapFactory.decodeStream(is, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, mWidth, mHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
is = getContentResolver().openInputStream(data);
bitmap = BitmapFactory.decodeStream(is,null,options);
if(bitmap==null){
Toast.makeText(getBaseContext(), "Image is not Loaded",Toast.LENGTH_SHORT).show();
return null;
}
is.close();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch(NullPointerException e){
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == 10 && resultCode == RESULT_OK && null != intent) {
Uri data = intent.getData();
Bitmap bitmap = getBitmapFromUri(data);
if(bitmap!=null){
drawView.canvasBitmap=bitmap;
}
}
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
mWidth = drawView.getWidth();
mHeight = drawView.getHeight();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("width", mWidth);
outState.putInt("height", mHeight);
if(drawView.canvasBitmap!=null){
outState.putParcelable("bitmap", drawView.canvasBitmap);
}
super.onSaveInstanceState(outState);
}
}
答案 0 :(得分:1)
您正在做的是通过drawCanvas
对象获取图像画布并将其绘制在画布上,然后在其上绘制路径。
尝试另一种方法,通过drawCanvas
对象获取图像画布并在其上绘制路径,然后在画布上绘制结果图像。请参阅以下代码
// draw path on canvasBitmap
drawCanvas.drawPath(drawPath, drawPaint);
//Now draw canvasBitmap on canvas
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
//canvas.drawPath(drawPath, drawPaint); // No need for this line
实际发生的事情是您在ACTION_UP上绘制画布上的路径并重置路径对象,请参阅以下代码
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
根据Android的 reset()做的如下:
清除路径中的所有线条和曲线,使其变空。
在上面的代码之后,你调用invalidate();
清除画布并用空路径对象重绘它,因为你已经调用了drawPath.reset()
。这是线条消失的主要原因。
答案 1 :(得分:0)
最后,我通过将以下方法添加到DrawingView类
来解决了这个问题public void setPicture (Bitmap bitmap) {
setBackgroundDrawable(new BitmapDrawable(bitmap));
}
然后我用drawView.canvasBitmap=bitmap;
drawView.setPicture(bitmap);
的每一行
并且每件事情都很好:)