简体   繁体   English

每次尝试更改绘画的属性(厚度或颜色)时,它都会更改Canvas(android)(java)上已有的绘画

[英]Every time I try to change a property of my paint (thickness or color), it changes existing paint that's already on the Canvas (android) (java)

I'm trying to create a simple drawing app that allows you to draw on a canvas, and you're able to change the color and thickness of it. 我正在尝试创建一个简单的绘图应用程序,使您可以在画布上绘图,并且可以更改其颜色和厚度。 The problem that's occurring is that every time I try to change the color or thickness of the paint, it changes ALREADY existing paint that's on the canvas. 发生的问题是,每当我尝试更改油漆的颜色或厚度时,都会更改画布上已经存在的油漆。 I understand why it's not working, but I just don't know how to fix it and where exactly the problem lies. 我知道为什么它不起作用,但我只是不知道如何解决它以及问题出在哪里。

CanvasView Class CanvasView类别

package samkough.com.painter;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;

public class CanvasView extends View
{
    /*
    * When the user touches the screen and moves their finger to draw,
    * we will use a Path to trace their drawing action on the canvas.
    * Both the canvas and the drawing on top of it are represented by Paint
    * objects. The initial paint color corresponds to the first color
    * in the palette we created last time, which will be initially selected
    * when the app launches. Finally we declare variables for the canvas
    * and bitmap - the user paths drawn with drawPaint will be drawn onto
    * the canvas, which is drawn with canvasPaint.
    * */
    //drawing paint
    private Paint paint = new Paint();
    // canvas paint
    private Paint canvasPaint = new Paint();
    //drawing path
    private Path path = new Path();
    // canvas
    private Canvas canvas = new Canvas();
    //canvas bitmap
    private Bitmap canvasBitmap;
    // brush size and pixel size
    private float brushSize, pixelAmount;

    public CanvasView(Context context, AttributeSet attrs)
    {
        // Setting the anti-alias, stroke join and cap styles will make the user's drawings appear smoother.
        super(context, attrs);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(5);
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
    }

    @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);
        canvas = new Canvas(canvasBitmap);
    }

    @Override
    protected void onDraw(Canvas drawCanvas)
    {
        drawCanvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
        drawCanvas.drawPath(path, paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e)
    {
        // get the coords of the touch event
        float eventX = e.getX();
        float eventY = e.getY();

        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // set a new starting point
                path.moveTo(eventX, eventY);
                path.reset();
                path.moveTo(eventX, eventY);
                return true;
            case MotionEvent.ACTION_MOVE:
                // connect the points
                path.lineTo(eventX, eventY);
                break;
            default:
                return false;
        }

        // makes you view repaint and call ondraw
        invalidate();
        return true;
    }

    public void clearCanvas()
    {
        path.reset();
        invalidate();
    }

    public void setStrokeWidth(float f)
    {
        pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, f, getResources().getDisplayMetrics());
        brushSize = pixelAmount;

        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(brushSize);
        invalidate();
    }

    public void setColor(int p)
    {
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setColor(p);
        invalidate();
    }
}

MainActivity Class MainActivity类

package samkough.com.painter;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;

import com.samkough.painter.R;

public class MainActivity extends Activity {

    private CanvasView canvasView;
    private int orange;
    private int purple;
    private float strokeWidth;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        canvasView = (CanvasView) findViewById(R.id.canvasView);
        orange = Color.rgb(250, 128, 0);
        purple = Color.rgb(128, 0, 128);
        strokeWidth = 0;

        // REGULAR BUTTONS: save, about, reset
        Button saveB = (Button) findViewById(R.id.saveButton);
        Button aboutB = (Button) findViewById(R.id.aboutButton);
        Button resetB = (Button) findViewById(R.id.resetButton);

        // IMAGE BUTTONS: red, blue, green, yellow, black, purple, orange, erase, brush thickness plus, brush thickness minus
        ImageButton redIb = (ImageButton) findViewById(R.id.redButton);
        ImageButton blueIb = (ImageButton) findViewById(R.id.blueButton);
        ImageButton greenIb = (ImageButton) findViewById(R.id.greenButton);
        ImageButton yellowIb = (ImageButton) findViewById(R.id.yellowButton);
        ImageButton blackIb = (ImageButton) findViewById(R.id.blackButton);
        ImageButton purpleIb = (ImageButton) findViewById(R.id.purpleButton);
        ImageButton orangeIb = (ImageButton) findViewById(R.id.orangeButton);
        ImageButton eraseIb = (ImageButton) findViewById(R.id.eraseButton);
        ImageButton plusIb = (ImageButton) findViewById(R.id.plusButton);
        ImageButton minusIb = (ImageButton) findViewById(R.id.minusButton);

        minusIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                strokeWidth -= 2;
                canvasView.setStrokeWidth(strokeWidth);
            }
        });

        plusIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                strokeWidth += 2;
                canvasView.setStrokeWidth(strokeWidth);
            }
        });

        eraseIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                canvasView.setColor(Color.TRANSPARENT);
            }
        });

        orangeIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                canvasView.setColor(orange);
            }
        });

        purpleIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                canvasView.setColor(purple);
            }
        });

        blackIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                canvasView.setColor(Color.BLACK);
            }
        });

        yellowIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                canvasView.setColor(Color.YELLOW);
            }
        });

        greenIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                canvasView.setColor(Color.GREEN);
            }
        });

        blueIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                canvasView.setColor(Color.BLUE);
            }
        });

        redIb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                canvasView.setColor(Color.RED);
            }
        });

        saveB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            }
        });

        aboutB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(), AboutActivity.class);

                startActivity(intent);
            }
        });

        resetB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                canvasView.clearCanvas();
            }
        });
    }


    @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;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

In CanvasView.java , this line CanvasView.java ,此行

private Paint paint = new Paint();

declares one paint object for the whole class, and this line 为整个类声明一个绘画对象,这一行

private Path path = new Path();

declares one path object for the whole class. 为整个类声明一个路径对象。

When onDraw is called, your whole canvas area is being redrawn. 调用onDraw ,整个画布区域将被重绘。 That means that 那意味着

drawCanvas.drawPath(path, paint);

is drawing the entire path that has been added since the activity was created with whatever the current value of paint is. 正在绘制活动创建以来添加的完整path ,无论paint的当前值是多少。

One way of working around this is to have a list of Path objects and a list of Paint objects. 解决此问题的一种方法是拥有一个Path对象列表和一个Paint对象列表。 The first element of the Path list would store the first path that was drawn--say, everything drawn up until the point when they change paint. “路径”列表的第一个元素将存储绘制的第一个路径-例如,绘制的所有内容直到它们更改绘制点为止。 The first element of the paint list would store the corresponding paint that was used. 绘画列表的第一个元素将存储所使用的相应绘画。 Whenever the user changes the paint and begins painting, you'll need to create a new Path object, and add it and the new Paint object to the lists. 每当用户更改绘画并开始绘画时,您都需要创建一个新的Path对象,并将其和新的Paint对象添加到列表中。

Once you have lists of the paths and the paints they were drawn with, you can do something like this in onDraw : 获得路径列表以及绘制路径时,可以在onDraw

for (int i = 0; i < paths.size(); i++) {
  Path path = paths.get(i);
  Paint paint = paints.get(i);
  drawCanvas.drawPath(path, paint);
} 

You have created canvas , but you are not using that to draw anything on it. 您已经创建了canvas ,但没有使用它在其上绘制任何东西。 So essentially, the line drawCanvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); 因此本质上,这行drawCanvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); doesn't do anything. 什么也没做

What you need to do instead is draw the path on the canvas . 您需要做的是在canvas上绘制path Then draw the canvasBitmap using drawCanvas . 然后绘制canvasBitmap使用drawCanvas This way you can maintain a single path and a single paint instead of multiple ones. 这样,您可以维护一个path和一个paint而不是多个paint

@Override
protected void onDraw(Canvas drawCanvas)
{
    canvas.drawPath(path, paint);
    drawCanvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
}

When you do the above, each time the user draw's a new path, the canvasBitmap will hold all the old paths in it. 当您执行上述操作时,每次用户绘制新路径时, canvasBitmap都会在其中保留所有旧路径。 So each time the onDraw is called, only the new path is drawn. 因此,每次调用onDraw ,仅绘制新path

Always remember: It's a bad practice to create multiple PAINT objects . 永远记住:创建多个PAINT对象是一种不好的做法。 Try to reuse the Paint object as much as possible. 尝试尽可能重用Paint对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM