【问题标题】:When saving the new image it keeps the old canvas保存新图像时,它会保留旧画布
【发布时间】:2013-09-05 16:02:38
【问题描述】:

我有一个允许用户绘制和保存的画布。它还允许用户更改颜色并使用不同颜色在同一画布上绘制。

我的绘画课:

package com.test.testing;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Paint.Style;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.test.testing.*;

public class CustomView extends View {
    Paint paint;
    Path path;
    float x = 0;
    float y = 0;
    private int cWhite = Color.WHITE;
    private Button btnS, btnSa;

    public CustomView(Context context) {
        super(context);
        paint = new Paint();
        path= new Path();
        paint.setAlpha(255);
        paint.setColor(cWhite);
        paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(20);

        btnS = (Button)((FreeDraw) context).findViewById(R.id.shareButton);
        btnSa = (Button)((FreeDraw) context).findViewById(R.id.saveButton);
    }

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(path,paint);
        canvas.drawCircle(x, y, 10, paint);
    }

    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            path.moveTo(event.getX(), event.getY());
            path.lineTo(event.getX(), event.getY());
            if (btnS.getVisibility() == View.VISIBLE && btnS != null) {
                //if share button is displaying but I drew something else
                //the share button should disappear and I should be presented
                //with the save button

                btnS.setVisibility(View.GONE);
                btnSa.setVisibility(View.VISIBLE);
            }
            if (btnSa.getVisibility() == View.VISIBLE && btnS != null) {
                //do nothing...
            }
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            x = event.getX();
            y = event.getY();
            path.lineTo(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            path.lineTo(event.getX(), event.getY());
            invalidate();
            break;
        case MotionEvent.ACTION_CANCEL:
            break;
        default:
            break;
        }
        return true;
    }
}

在我的 Activity 中,我调用 Paint 类并使用这样的 XML 布局:

layout = (FrameLayout)findViewById(R.id.viewd);
//layout.removeAllViews();
view = new CustomView(FreeDraw.this);
view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
layout.addView(view);

同样在同一个活动中,我有以下处理颜色变化的代码:

public void colorHandle() {
    // custom dialog
    final Dialog dialog = new Dialog(this);
    dialog.setContentView(R.layout.colorlayout);
    dialog.setTitle("Choose a Drawing Color");

    Button btnWH = (Button) dialog.findViewById(R.id.btnWhite);
    Button btnBL = (Button) dialog.findViewById(R.id.btnBlack);
    Button btnBLU = (Button) dialog.findViewById(R.id.btnBlue);
    Button btnCY = (Button) dialog.findViewById(R.id.btnCyan);
    Button btnDG = (Button) dialog.findViewById(R.id.btnDkGray);
    Button btnGR = (Button) dialog.findViewById(R.id.btnGray);
    Button btnGRE = (Button) dialog.findViewById(R.id.btnGreen);
    Button btnLG = (Button) dialog.findViewById(R.id.btnLtGray);
    Button btnMG = (Button) dialog.findViewById(R.id.btnMagenta);
    Button btnRD = (Button) dialog.findViewById(R.id.btnRed);
    Button btnYE = (Button) dialog.findViewById(R.id.btnYellow);

    if (btnWH != null) {
        btnWH.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.WHITE);
                dialog.dismiss();
            }
        });
    }
    if (btnBL != null) {
        btnBL.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.BLACK);
                dialog.dismiss();
            }
        });
    }
    if (btnBLU != null) {
        btnBLU.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.BLUE);
                dialog.dismiss();
            }
        });
    }
    if (btnCY != null) {
        btnCY.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.CYAN);
                dialog.dismiss();
            }
        });
    }
    if (btnDG != null) {
        btnDG.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.DKGRAY);
                dialog.dismiss();
            }
        });
    }
    if (btnGR != null) {
        btnGR.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.GRAY);
                dialog.dismiss();
            }
        });
    }
    if (btnGRE != null) {
        btnGRE.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.GREEN);
                dialog.dismiss();
            }
        });
    }
    if (btnLG != null) {
        btnLG.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.LTGRAY);
                dialog.dismiss();
            }
        });
    }
    if (btnMG != null) {
        btnMG.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.MAGENTA);
                dialog.dismiss();
            }
        });
    }
    if (btnRD != null) {
        btnRD.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.RED);
                dialog.dismiss();
            }
        });
    }
    if (btnYE != null) {
        btnYE.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.YELLOW);
                dialog.dismiss();
            }
        });
    }
    dialog.show();
}

我必须为每种颜色重复以下代码,因为一旦我绘制了一些东西并更改了颜色并绘制了其他东西,之前绘制的所有路径都会更改为新颜色,并且此代码修复了它:

        layout = (FrameLayout)findViewById(R.id.viewd);
        //layout.removeAllViews();
        view = new CustomView(FreeDraw.this);
        view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
        layout.addView(view);

我在Activity中保存图片部分的代码是:

View.OnClickListener saveHandle = new View.OnClickListener() {
    public void onClick(View v) {
        new SaveImageTask().execute(null, null, null);
    }
};
public class SaveImageTask extends AsyncTask<Void, Void, Void> {
     @Override
     protected Void doInBackground(Void... params) { //Running in background
        View content = layout;
        content.setDrawingCacheEnabled(true);
        content.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
        Bitmap bitmap = content.getDrawingCache();
        File folder = new File(Environment.getExternalStorageDirectory() + "/PB");
        if (!folder.exists()) {
            folder.mkdir();
        }
        file = new File(folder + "/pb_image_" + Math.random()  + ".png");
        FileOutputStream ostream;
        try {
            file.createNewFile();
            ostream = new FileOutputStream(file);
            bitmap.compress(CompressFormat.PNG, 100, ostream);
            ostream.flush();
            ostream.close();
            isSaved = true;
        } catch (Exception e) {
            e.printStackTrace();
            isSaved = false;
        }
        return null;
     }

     @Override
     protected  void onPreExecute() { //Activity is on progress
         //displayToast("Your image is saving...");
         btnSave.setVisibility(View.GONE);
         btnShare.setVisibility(View.GONE);
         pb.setVisibility(View.VISIBLE);
     }

     @Override
     protected void onPostExecute(Void v) { //Activity is done...
        if (isSaved == true) {
             displayToast("Image was saved.");
             btnSave.setVisibility(View.GONE);
             btnShare.setVisibility(View.VISIBLE);
             pb.setVisibility(View.GONE);
         }
         if (isSaved == false) {
             displayToast("Unable to save image. Try again later.");
             btnSave.setVisibility(View.VISIBLE);
             btnShare.setVisibility(View.GONE);
             pb.setVisibility(View.GONE);
         }
     }
}

我想做的是:

  • 当我画一些东西并保存图像时,应该会出现 SHARE 按钮,并且 Canvas 不应该清除(工作)
  • 当 SHARE 按钮可见时,我在画布上绘制了其他东西,SAVE 按钮应该会重新出现(工作)
  • 当我再次按下“保存”按钮时,它应该保存新的画布图纸(不工作,它正在保存我在第一步中保存的先前绘制的画布

如何修改我的代码来做到这一点

  • 不要为每种颜色创建新画布,而是创建新路径。
  • 保存画布上的绘图后,我在现有画布上绘制新内容并保存。新画布应与所有新旧绘制路径一起保存
  • 如果按下 ERASE 按钮,则清除整个画布

【问题讨论】:

    标签: java android android-canvas


    【解决方案1】:

    不要为每种颜色创建新画布,而是创建新路径。

    为用户每次触摸画布并在理论上绘制某些新内容时创建Path。存储新路径及其颜色,并在 onDraw 方法中迭代路径结构并使用其保存的颜色绘制每个路径:

    // this will hold the data of each path the user draws
    class DrawnItem {
        int color = Color.GREEN; // default values
        Path line = new Path();
    }
    
    Paint paint;
    int mCurrentColor = Color.GREEN; // start with green
    ArrayList<DrawnItem> mDrawings = new ArrayList<DrawnItem>();
    
    // in the onDraw method:
    protected void onDraw(Canvas canvas) {
        final int count = mDrawings.size();
        for (int i = 0; i < count; i++) {
            final DrawnItem item = mDrawings.get(i);
            paint.setColor(item.color);
            canvas.drawPath(item.line, paint);
        }
        paint.setColor(mCurrentColor);
        canvas.drawCircle(x, y, 10, paint);
    }
    
    private DrawnItem mCurrentItem = null;
    
    // and in the onTouch method:
    public boolean onTouchEvent(MotionEvent event) {
        final int action = event.getAction();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
           // the user started a new drawing so build a new DrawnItem
           mCurrentItem = new DrawnItem();
           mCurrentitem.color= mCurrentColor;  
           mDrawings.add(mCurrentItem);
           // use the item.line to setup the Path with the x and y values
           // .... 
           invalidate();
           break; 
           case MotionEvent.ACTION_MOVE:
               x = event.getX();
               y = event.getY();
               mCurrentItem.line.lineTo(x, y);
               invalidate();
           break;
        case MotionEvent.ACTION_UP:
            mCurrentItem.line.lineTo(event.getX(), event.getY());
            mCurrentItem = null;
            invalidate();
            break;
        case MotionEvent.ACTION_CANCEL:
            mCurrentItem = null; // this drawing session was canceled so this DrawnItem is now closed
            break;
        default:
            break;
    

    现在,在您的对话框中,您唯一需要做的就是将自定义视图的mCurrentColor 更新为所选颜色的点,然后从该点开始使用专用颜色绘制路径上的点。如果用户将颜色切换到以前存储的颜色,则将选择该颜色对应的路径。

    在 doInBackground() 中将视图保存为 Bitmap 的代码:

    Bitmap bitmap = Bitmap.createBitmap(layout.getWidth(), layout.getHeight(), Bitmap.Config. RGB_565);
    Canvas canvas = new Canvas(bitmap);
    layout.draw(canvas);
    

    如果按下 ERASE 按钮,则清除整个画布

    清除之前的路径结构并在您的自定义视图上调用invalidate()

    mDrawings.clear();
    customView.invalidate();
    

    【讨论】:

    • 我不能在我的 Paint 类中使用 private 变量,因为我将从另一个类访问这些变量。变量key在哪里初始化?
    • @ZahidH private 关键字不算,你可以删除它。关于 key 变量,这是一个错字,它是上一行中的 color
    • //use path below. 应该是我代码中的其他所有内容,对吧?
    • @ZahidH 我不知道我应该看到什么?!您应该尝试测试代码,然后提及出现的任何问题。
    • @ZahidH 如果您想要绘制路径的确切顺序,则需要一种新方法。我对我的答案进行了一些编辑。我不明白保存的问题。
    猜你喜欢
    • 1970-01-01
    • 2020-08-21
    • 2013-02-08
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多