如何在Android中绘制多条不同颜色的线并撤销、重做路径?

4

我想在Android视图上绘制多条不同颜色的线,并实现路径的撤销和重做。

我使用了位图绘制选项,每个路径都有唯一的颜色,但是撤销和重做没有起作用。

这是我的bitmappaint代码:

public MyView(Context context, Object object) {
    super(context);
    setFocusable(true);
    setFocusableInTouchMode(true);
    
    mPath = new Path();
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setColor(0xFFFFFF00);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(3);

    mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);
}

protected void onSizeChanged(int w, int h, int oldw, int oldh) 
{
    super.onSizeChanged(w, h, oldw, oldh);
}

protected void onDraw(Canvas canvas) 
{
    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    for (Path p : paths)
    {
        canvas.drawPath(p, mPaint);
    }
    canvas.drawPath(mPath, mPaint);
}

public boolean onTouchEvent(MotionEvent event)
{
    float x = event.getX();
    float y = event.getY();
    int action = event.getAction();
    int action1=event.getAction();
    switch (event.getAction())
    {
    case MotionEvent.ACTION_DOWN:
        undonePaths.clear();
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        startPoint = new PointF(event.getX(), event.getY());
        endPoint = new PointF();
        invalidate();
        //   isDrawing = true;
        break;
    case MotionEvent.ACTION_MOVE:
        float dx = Math.abs(x - mX);
        System.out.println("action move");
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
        {
            //  currentDrawingPath.path.quadTo(mX,mY,(x + mX)/2, (y + mY)/2);
        }
        mX = x;
        mY = y;
        endPoint.x = event.getX();
        endPoint.y = event.getY();
        isDrawing = true;
        invalidate();
        break;
    case MotionEvent.ACTION_UP:
        mPath.lineTo(mX, mY);
        paths.add(mPath);
        mPath = new Path();
        //  mCanvas.drawPath(mPath, ppaint);
        endPoint.x = event.getX();
        endPoint.y = event.getY();
        isDrawing = false;
        invalidate();
        break;
    default:
        break;
    }       
}

bitmappaint画布的输出

没有使用bitmap时,如果我为路径选择了蓝色,则所有以前的路径颜色都会变成蓝色,这是一个颜色问题;

这是我的代码:

protected void onDraw(Canvas canvas) 
{
    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    for (Path p : paths)
    {
        canvas.drawPath(p, mPaint);
    }
    canvas.drawPath(mPath, mPaint);
}

不使用位图的canvas绘制输出

有人能帮助我在Android中以不同颜色绘制多条唯一路径吗?


你如何在程序中知道你使用了哪种颜色来绘制每个路径? - Shark
您可以使用itemize overlay类,在其中使用不同的覆盖层绘制不同颜色的线条,当您想要撤销先前的颜色时,请清除该覆盖层,并为此设置一些条件。例如:mapOverlays2 = mapView.getOverlays(); mapOverlays2.clear(); - Pir Fahim Shah
在这种情况下,我正在创建一个特定的覆盖层,并将其传递给其项目化覆盖层类,在该覆盖层之后占据位置,然后我们可以删除和清除此特定覆盖层,使得该行及其包含的内容从地图上移除。 - Pir Fahim Shah
2个回答

8
当你处理MotionEvent.ACTION_UP事件时,你需要像下面这样使用某些东西来保存用于绘制路径的颜色:
case MotionEvent.ACTION_UP:
    paths.add(mPath);
    colorsMap.put(mPath,selectedColor); // store the color of mPath
    ...

在绘制路径之前,您需要设置画笔颜色:
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    for (Path p : paths)
    {
        mPaint.setColor(colorsMap.get(p));
        canvas.drawPath(p, mPaint);
    }
    mPaint.setColor(selectedColor);
    canvas.drawPath(mPath, mPaint);
}

而colorsMap是一个简单的实例变量:

private Map<Path, Integer> colorsMap = new HashMap<Path, Integer>();    

要实现撤销/重做功能,只需从路径中删除最后一个元素(并将其存储在未完成列表中,以便在重做时可以恢复它)。请参见Android Canvas Redo and Undo Operation

嗨,感谢您的帖子。我认为您已经在colorsMap类中创建了get()和put()方法来解决这个问题。请提供关于colorsMap类的数据类型声明。 - Kevin Rameshwaran
非常感谢你,谢谢你的帮助,兄弟。我感到非常开心,它完美地运行了.... - Kevin Rameshwaran
@ben75,您提供的撤销和重做操作链接仅在我未在onDraw(Canvas canvas)方法中使用canvas.drawBitmap(bitmap,0,0,paintScreen)时才有效。但是,如果我使用了这行代码canvas.drawBitmap(bitmap,0,0,paintScreen),那么撤销和重做就停止工作了。为什么会发生这种情况?有什么解决办法吗? - AndroidDev
事实上,这个简单的撤销/重做仅处理路径绘制,因为路径/undonePaths列表只能包含“Path”。您可以定义自己的“DrawingOperation”类,其中包含一个“draw(Canvas)”方法,并使用一个“PathDrawingOperation”和一个“BitmapDrawingOperation”进行子类化。在“PathDrawingOperation”中,“draw”方法将简单地绘制路径,在“BitmapDrawingOperation”中,“draw”方法将绘制位图。调整您的代码,使路径/undonePaths变为“List <DrawingOperation>”(并将它们重命名为drawingOperations / undoneDrawingOperations)。 - ben75
我该如何实现删除功能?请提供一些建议。 - UserAndroid

1

这是一段可用的代码。我在自己的应用程序中测试过,它非常好用。也许它能帮到你。请留下评论。

        public class Main extends Activity implements OnColorChangedListener {
        //public static int selectedColor = Color.BLACK;
        public static ArrayList<Path> mMaindialog;
        // private ArrayList<Path> undonePaths;
        // public int selectedcolor;
        private static final String COLOR_PREFERENCE_KEY = "color";
        private FrameLayout relativelayout;
        static String sdpath,location;
        Boolean i;
        // Instance variables
        private Bitmap mBitmap=null;
        Bitmap bitmap;
        private Paint mPaint, mBitmapPaint, mPaint1;
        private MyView mView;
        ImageView idd;
        // private Path mPath;
        int slll = Color.BLACK;
        Bitmap map=ListView5.bMap;
        private Button ClearPaint, Colorpaint;
        Ghostdatabase gost;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
             idd=(ImageView)findViewById(R.id.imageView1);
            relativelayout = (FrameLayout) findViewById(R.id.frameLayout);

            DisplayMetrics metrics = getBaseContext().getResources()
                    .getDisplayMetrics();
            int w = metrics.widthPixels;
            int h = metrics.heightPixels;

            System.out.println(" width " + w);
            System.out.println(" height " + h);



            mView = new MyView(this, w, h);
            mView.setDrawingCacheEnabled(true);

            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setColor(Color.BLACK);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(4);

            ClearPaint = (Button) findViewById(R.id.ne);
            ClearPaint.setOnClickListener(new OnClickListener() {

                public void onClick(View v) {
                    // mBitmap.eraseColor(Color.TRANSPARENT);
                    // mPath.reset();
                    // mView.invalidate();

                    mView.onClickUndo();

                }
            });
            Button save22 = (Button) findViewById(R.id.save);
            save22.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    File cacheDir;
                    Toast.makeText(Main.this, "Photo", 500).show();
                    Bitmap icon;
                    relativelayout.setDrawingCacheEnabled(true);

                    icon = Bitmap.createBitmap(relativelayout.getDrawingCache());
                    Bitmap bitmap = icon;
                    relativelayout.setDrawingCacheEnabled(false);
                    // File mFile1 = Environment.getExternalStorageDirectory();
                    Date d = new Date();
                    String fileName = d.getTime() + "mg1.jpg";

                    File storagePath = (Environment.getExternalStorageDirectory());
                    File dest = new File(storagePath + "/CityAppImages");

                    if (!dest.exists()) {
                        dest.mkdirs();

                    }

                    File mFile2 = new File(dest, fileName);
                    sdpath = mFile2.getAbsolutePath();

                    Log.d("qqqqqqqqqqqqqqqqqqqqqqq", "zzzzzzzz" + sdpath);
                    try {
                        FileOutputStream outStream;

                        outStream = new FileOutputStream(mFile2);

                        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);

                        outStream.flush();

                        outStream.close();
                        Toast.makeText(Main.this, "Photo Saved Sucessfully", 500)
                                .show();
                    } catch (FileNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {

                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        Toast.makeText(Main.this, "Photo Not Saved Sucessfully",
                                500).show();
                    }

                    gost = new Ghostdatabase(Main.this);
                    gost.open();

                    gost.insertTitle(sdpath);
                }
            });

            Button view = (Button) findViewById(R.id.listtt);
            view.setOnClickListener(new OnClickListener() {

                public void onClick(View v) {

                    Intent ii = new Intent(Main.this, ListView5.class);
                    startActivity(ii);

                }
            });

            Button Colorpaint = (Button) findViewById(R.id.Color);
            Colorpaint.setOnClickListener(new OnClickListener() {

                public void onClick(View v) {
                    int color = PreferenceManager.getDefaultSharedPreferences(
                            Main.this).getInt(COLOR_PREFERENCE_KEY, Color.WHITE);
                    // int _color = R.color.red;
                    new ColorPickerDialog(v.getContext(),
                            new OnColorChangedListener() {

                                public void colorChanged(int color) {
                                    mPaint.setColor(color);

                                    slll = color;

                                    Log.i("TAG", "mpaint one" + mPaint);
                                }
                            }, mPaint.getColor()).show();
                    Log.i("TAG", "mpaint two" + mPaint);
                }
            });
            relativelayout.addView(mView);
        }



        // //////////******************* Pinting view
        // *******************///////////////////

        public class MyView extends View implements OnTouchListener {
            private Map<Path, Integer> colorsMap = new HashMap<Path, Integer>();
            private ArrayList<Path> mMaindialog = new ArrayList<Path>();
            private ArrayList<Path> undonePaths = new ArrayList<Path>();
            int colorPicked = slll;
            // Paint mPaint1;

            private Canvas mCanvas;
            private Path mPath;

            public MyView(Context c, int w, int h) {
                super(c);
                if(GlobalVariable.impath==1)
                {
                    Log.d("","111111"+GlobalVariable.impath);
                    System.out.println(GlobalVariable.impath);
                    Intent ii = getIntent();
                     location = ii.getStringExtra("IMAGE");
                    // bitmap.recycle();
                     Log.d("","location"+location);
                     bitmap = BitmapFactory.decodeFile(location);
                     mBitmap = Bitmap.createScaledBitmap(bitmap,300, 300,false);
                     Log.d("hhhhhhhhhhhhhhhssssssss","mBitmap"+mBitmap);
                     //mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
                    // idd.setImageBitmap(mBitmap);
                    Log.d("hhhhhhhhhhhhhhhssssssss","GlobalVariable.impath"+GlobalVariable.impath);
                }
                else if(GlobalVariable.impath==2){
                    //bitmap.recycle();
                    Log.d("","22222222222222222222222"+GlobalVariable.impath);
                    bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.base);
                    mBitmap = Bitmap.createScaledBitmap(bitmap,100, 100, false);
                    //mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
                    Log.d("hhhhhhhhhhhhhhhssssssss1111111","mBitmap"+mBitmap);
                }



    //          
                mCanvas = new Canvas(mBitmap);
                mPath = new Path();

            }

            @Override
            protected void onSizeChanged(int w, int h, int oldw, int oldh) {
                super.onSizeChanged(w, h, oldw, oldh);

            }

            @Override
            protected void onDraw(Canvas canvas) {

                canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

                for (Path p : mMaindialog) {
                    mPaint.setColor(colorsMap.get(p));
                    canvas.drawPath(p, mPaint);
                }
                mPaint.setColor(slll);
                canvas.drawPath(mPath, mPaint);
            }

            // //////************touching evants for painting**************///////
            private float mX, mY;
            private static final float TOUCH_TOLERANCE = 0;

            private void touch_start(float x, float y) {
                mPath.reset();
                mPath.moveTo(x, y);
                mX = x;
                mY = y;
                undonePaths.clear();
            }

            private void touch_move(float x, float y) {
                float dx = Math.abs(x - mX);
                float dy = Math.abs(y - mY);
                if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                    mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
                    mX = x;
                    mY = y;
                }
            }

            private void touch_up() {
                mPath.lineTo(mX, mY);
                // commit the path to our offscreen
                mCanvas.drawPath(mPath, mPaint);
                // kill this so we don't double draw
                mPath = new Path();
                mPath.reset();
                mMaindialog.add(mPath);
            }

            @Override
            public boolean onTouchEvent(MotionEvent event) {
                float x = event.getX();
                float y = event.getY();
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    // touch_start(x, y);
                    // invalidate();
                    undonePaths.clear();
                    mPath.reset();
                    mPath.moveTo(x, y);
                    mX = x;
                    mY = y;
                    invalidate();
                    break;
                case MotionEvent.ACTION_MOVE:
                    // touch_move(x, y);
                    // invalidate();
                    float dx = Math.abs(x - mX);
                    float dy = Math.abs(y - mY);
                    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                        mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
                        mX = x;
                        mY = y;
                    }
                    invalidate();
                    break;
                case MotionEvent.ACTION_UP:
                    // touch_up();
                    // invalidate();
                    mPath.lineTo(mX, mY);
                    mMaindialog.add(mPath);
                    colorsMap.put(mPath, slll);
                    mPath = new Path();
                    mPath.reset();
                    invalidate();
                    break;
                }
                return true;
            } // end of touch events for image

            private Paint createPen(int colorPicked) {
                // TODO Auto-generated method stub
                mPaint1 = new Paint();
                mPaint1.setColor(colorPicked);
                mPaint1.setAntiAlias(true);
                mPaint1.setDither(true);
                mPaint1.setStyle(Paint.Style.STROKE);
                mPaint1.setStrokeJoin(Paint.Join.ROUND);
                mPaint1.setStrokeCap(Paint.Cap.ROUND);
                // mPaint1.setStrokeWidth(3);
                return mPaint1;
            }

            public void onClickRedo() {
                if (undonePaths.size() > 0) {
                    mMaindialog.add(undonePaths.remove(undonePaths.size() - 1));
                    mView.invalidate();

                } else {

                }
                // toast the user
            }

            public void onClickUndo() {
                if (mMaindialog.size() > 0) {
                    undonePaths.add(mView.mMaindialog.remove(mView.mMaindialog
                            .size() - 1));
                    mView.invalidate();
                }

                else {

                }
            }

            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) {
                // TODO Auto-generated method stub
                return false;
            }
        }// end MyView

        @Override
        public void colorChanged(int color) {
            // TODO Auto-generated method stub
            PreferenceManager.getDefaultSharedPreferences(this).edit()
                    .putInt(COLOR_PREFERENCE_KEY, color).commit();
            slll = color;
        }



    }

我该如何实现擦除功能?请给些建议。 - UserAndroid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接