Reputation: 1667
This is the first time I am working with the Canvas class in Android.
What I want is to draw lines in different colors on the canvas. I have an issue I cannot resolve.
I draw the first line in black, after I change the color to red and try to draw a second line in red, and the first line drawn in black color changes to red.
Code I used is:
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class DrawView extends View implements OnTouchListener
{
private Canvas m_Canvas;
private Path m_Path;
private Paint m_Paint;
ArrayList<Pair<Path, Paint>> paths = new ArrayList<Pair<Path, Paint>>();
ArrayList<Pair<Path, Paint>> undonePaths = new ArrayList<Pair<Path, Paint>>();
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
// Bitmap canvasBackground;
public DrawView(Context context)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
onCanvasInitialization();
}
public void onCanvasInitialization()
{
m_Paint = new Paint();
m_Paint.setAntiAlias(true);
m_Paint.setDither(true);
m_Paint.setColor(Color.parseColor("#37A1D1"));
m_Paint.setStyle(Paint.Style.STROKE);
m_Paint.setStrokeJoin(Paint.Join.ROUND);
m_Paint.setStrokeCap(Paint.Cap.ROUND);
m_Paint.setStrokeWidth(2);
m_Canvas = new Canvas();
m_Path = new Path();
Paint newPaint = new Paint(m_Paint);
paths.add(new Pair<Path, Paint>(m_Path, newPaint));
// Bitmap canvas = BitmapFactory.decodeResource(getResources(), R.drawable.theme1_img_note).copy(Bitmap.Config.ARGB_8888, true);
// canvasBackground = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888 );
// m_Canvas = new Canvas(canvasBackground);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas)
{
for (Pair<Path, Paint> p : paths)
{
canvas.drawPath(p.first, p.second);
}
}
public boolean onTouch(View arg0, MotionEvent event)
{
float x = event.getX();
float y = event.getY();
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;
}
return true;
}
private void touch_start(float x, float y)
{
m_Path.reset();
m_Path.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 >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
{
m_Path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up()
{
m_Path.lineTo(mX, mY);
// commit the path to our offscreen
m_Canvas.drawPath(m_Path, m_Paint);
// kill this so we don't double draw
m_Path = new Path();
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
paths.add(new Pair<Path, Paint>(m_Path, newPaint));
}
public void onClickPenButton(int penWidth)
{
m_Paint.setStrokeWidth(penWidth);
m_Path = new Path();
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
paths.add(new Pair<Path, Paint>(m_Path, newPaint));
}
public void onClickPenColorButton(int penColor)
{
m_Paint.setColor(penColor);
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
paths.add(new Pair<Path, Paint>(m_Path, newPaint));
}
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
{
}
}
}
Upvotes: 3
Views: 4673
Reputation: 99
You will have to create seperate objects for both PATHs and PAINTs,then create properties of each paint object separately. And then in onDraw function, you'll have to specify the canvas drawCircle method for each path and its corresponding paint.
For example, I had a similar issue and it took me a while to solve it.
First I wanted to have a view where I can draw a line. The code was:
package com.example.ex13_singletouch
import android.content.Context
import android.graphics.*
import android.view.MotionEvent
import android.view.View
class SingleTouchView(context: Context): View(context) { //AFTER COLON : WAS SOMETHING THAT WOULD BE RETURNED
private val paint= Paint()
private val path = Path()
//TO CREATE THE X-Y POSITION OF THE FINGER ON THE SCREEN
private var evenX: Float = 0F
private var evenY: Float = 0F
private var fingerDown = false //CHECKS IF YOUR FINGER IS TOUCHING THE SCREEN OR NOT
//INITIALIZATION
init {
paint.isAntiAlias = true
paint.strokeWidth = 6F
paint.strokeJoin = Paint.Join.ROUND
paint.color = Color.BLACK
paint.style = Paint.Style.STROKE
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
evenX = event!!.x
evenY = event!!.y
when(event.action){
MotionEvent.ACTION_DOWN -> {
fingerDown = true
path.moveTo(evenX,evenY)
return true
}
MotionEvent.ACTION_MOVE -> {
path.lineTo(evenX,evenY) //WHEN YOU MOVE YOUR FINGER ON THE SCREEM, X AND Y KEEPS UPDATING AND IT DRAWS A LINE
}
MotionEvent.ACTION_UP -> {
fingerDown = false
}
else -> return false
}
invalidate() //JUMP TO THE ON DRAW TO DRAW SOMETHING THAT WE DEFINE
return super.onTouchEvent(event)
}
//THIS FUNCTION SHAPES OUT THE THING WE DRAW. MEANS IT WILL MAKE A LINE STRAIGH OR WILL MAKE A CIRCLE ROUND
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas!!.drawPath(path, paint)
if (fingerDown){
canvas.drawCircle(evenX, evenY, 10F, paint)
}
}
}
Then I planned to draw lines that could have 3 differnt colours - Black, Blue and Red. Here is my updated code
package com.example.ex13_singletouch
import android.content.Context
import android.graphics.*
import android.view.MotionEvent
import android.view.View
import java.util.*
import kotlin.collections.ArrayList
class SingleTouchView(context: Context): View(context) { //AFTER COLON : WAS SOMETHING THAT WOULD BE RETURNED
//private val paint= Paint()
private val paint1= Paint()
private val paint2= Paint()
private val paint3= Paint()
//private val path = Path()
private val path1 = Path()
private val path2 = Path()
private val path3 = Path()
//TO CREATE THE X-Y POSITION OF THE FINGER ON THE SCREEN
private var evenX: Float = 0F
private var evenY: Float = 0F
private var fingerDown = false //CHECKS IF YOUR FINGER IS TOUCHING THE SCREEN OR NOT
var colorControl = 1
//INITIALIZATION
init {
paint1.isAntiAlias = true
paint1.strokeWidth = 6F
paint1.strokeJoin = Paint.Join.ROUND
paint1.color = Color.BLACK
paint1.style = Paint.Style.STROKE
paint2.isAntiAlias = true
paint2.strokeWidth = 6F
paint2.strokeJoin = Paint.Join.ROUND
paint2.color = Color.BLUE
paint2.style = Paint.Style.STROKE
paint3.isAntiAlias = true
paint3.strokeWidth = 6F
paint3.strokeJoin = Paint.Join.ROUND
paint3.color = Color.RED
paint3.style = Paint.Style.STROKE
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
evenX = event!!.x
evenY = event!!.y
when(event.action){
MotionEvent.ACTION_DOWN -> {
fingerDown = true
//path.moveTo(evenX,evenY)
if (colorControl==1){
path1.moveTo(evenX,evenY)
}
if (colorControl==2){
path2.moveTo(evenX,evenY)
}
if (colorControl==3){
path3.moveTo(evenX,evenY)
}
return true
}
MotionEvent.ACTION_MOVE -> {
//path.lineTo(evenX,evenY) //WHEN YOU MOVE YOUR FINGER ON THE SCREEM, X AND Y KEEPS UPDATING AND IT DRAWS A LINE
if (colorControl==1){
path1.lineTo(evenX,evenY)
}
if (colorControl==2){
path2.lineTo(evenX,evenY)
}
if (colorControl==3){
path3.lineTo(evenX,evenY)
}
}
MotionEvent.ACTION_UP -> {
fingerDown = false
if (colorControl==3){
colorControl=1
}
else {
colorControl++
}
}
else -> return false
}
invalidate() //JUMP TO THE ON DRAW TO DRAW SOMETHING THAT WE DEFINE
return super.onTouchEvent(event)
}
//THIS FUNCTION SHAPES OUT THE THING WE DRAW. MEANS IT WILL MAKE A LINE STRAIGH OR WILL MAKE A CIRCLE ROUND
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas!!.drawPath(path1, paint1)
canvas!!.drawPath(path2, paint2)
canvas!!.drawPath(path3, paint3)
}
}
You can look at the differences between these 2 codes and see for the changes I made. I hope this is helpful.
Upvotes: 0
Reputation: 18460
You have only one m_Paint
object, so when onDraw
is called it will draw all paths using the last color you have set.
You can store the color for each path and inside onDraw
you have to set the color before drawing the path
Edit
Here is the outline for a quick solution, night not be the most elegant one:
HashMap
with the path as key and the Color as valueonClickPenColorButton
save the color to an instance say currentColor
touch_start
you can push the path object with the currentColor
into the HashMap
Modify onDraw to get the color for each path. This code is only for illustration so modify it as needed.
protected void onDraw(Canvas canvas)
{
for (Path p : paths)
{
// Assuming your HashMap variable is pathColor
m_Paint.setColor(pathColor.get(p));
canvas.drawPath(p, m_Paint);
}
}
Upvotes: 4