create/change/delete/undo number of different shapes on canvas, onClick() of button











up vote
1
down vote

favorite












I'm creating android application for shapes on canvas onClick of button.



What I want:



I have three buttons 'Square','Circle','Triangle'.
Each time I tap on button and object of that shape will be created & displayed in a random position on one canvas.(done)



On tap of each shape will cause it to become another shape.
tapping on a square will make it a circle
tapping on a circle will make it a triangle
tapping on a triangle will make it a square (done)



On long tap on a shape can delete the shape.(done)



How to implement undo functionality!



Tried and Error: To achieve this functionality I tried so far following code in which I can create one shape on click of button using bitmap in java and image view in xml.



Update_29/10: I work on same code and create multiple shapes on canvas using dynamic relative layout adding views.



My Question:



Is this right way(bitmap and imageview) to create shape on canvas by clicking on button?



I can create multiple shapes on canvas now but every time I'm creating new canvas instance!any other way to achieve this?



Update_29_10:



How to get click of shape so I can delete shape and undo functionality as well.



XML:



<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context=".MainActivity">

<RelativeLayout
android:id="@+id/relative4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:layout_above="@+id/btnCircle"
android:background="@color/colorAccent">

</RelativeLayout>
<Button
android:id="@+id/btnSquare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/square" />

<Button
android:id="@+id/btnCircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/btnSquare"
android:text="@string/circle" />


<Button
android:id="@+id/btnTriangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/btnCircle"
android:text="@string/triangle" />

<Button
android:id="@+id/btnUndo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/btnTriangle"
android:layout_alignParentBottom="true"
android:text="@string/undo" />




MainActivity.java:



public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Context mContext;
private Resources mResources;
private RelativeLayout mRelativeLayout;
private Button btnSquare, btnCircle, btnTriangle,btnUndo,btnState;
private int mSuareCount=0,mCircleCount=0,mTriangelCount=0;


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

private void initViews() {
mContext = getApplicationContext();
mResources = getResources();
mRelativeLayout = (RelativeLayout) findViewById(R.id.rl);
btnSquare = (Button) findViewById(R.id.btnSquare);
btnCircle = (Button)findViewById(R.id.btnCircle);
btnTriangle = (Button)findViewById(R.id.btnTriangle);
btnUndo=(Button)findViewById(R.id.btnUndo);
setOnClickListeners();
}

private void setOnClickListeners() {
btnSquare.setOnClickListener(this);
btnCircle.setOnClickListener(this);
btnTriangle.setOnClickListener(this);
btnUndo.setOnClickListener(this);
}

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnSquare:
drawSquare(null);
mSuareCount++;
break;

case R.id.btnCircle:
drawCircle(null);
mCircleCount++;
break;

case R.id.btnTriangle:
drawTriangle(null);
mTriangelCount++;
break;

case R.id.btnUndo:

break;

}
}

private void drawSquare(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
50, // Width
50, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.LTGRAY);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.YELLOW);
paint.setAntiAlias(true);

int padding = 50;
Rect rectangle = new Rect(
padding, // Left
padding, // Top
canvas.getWidth() - padding, // Right
canvas.getHeight() - padding // Bottom
);
canvas.drawRect(rectangle, paint);
addViews(bitmap,imageView,1);

// Display the newly created bitmap on app interface
if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);

final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawCircle(finalImageView);
mSuareCount--;
mCircleCount++;
}
});
}

private void drawCircle(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
50, // Width
50, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setAntiAlias(true);

int radius = Math.min(canvas.getWidth(), canvas.getHeight() / 2);
int padding = 5;
canvas.drawCircle(
canvas.getWidth() / 2, // cx
canvas.getHeight() / 2, // cy
radius - padding, // Radius
paint // Paint
);

addViews(bitmap,imageView,2);

// Display the newly created bitmap on app interface
if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);

final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawTriangle(finalImageView);
mCircleCount--;
mTriangelCount++;
}
});

}

private void drawTriangle(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
500, // Width
500, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(),
bitmap.getHeight());


paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.YELLOW);
paint.setAntiAlias(true);
Point point1_draw = new Point(90, 0);
Point point2_draw = new Point(0, 180);
Point point3_draw = new Point(180, 180);

Path path = new Path();
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point1_draw.x, point1_draw.y);
path.close();
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#3F51B5"));
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
//addViews(bitmap,imageView);

addViews(bitmap,imageView,3);

if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);
final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawSquare(finalImageView);
mSuareCount++;
mTriangelCount--;
}
});

}

private void addViews(Bitmap bitmap, ImageView imageView, final int value) {
final int min = 20;
final int max = 80;


Drawable d = getResources().getDrawable(R.mipmap.ic_launcher_round);
final int w = d.getIntrinsicWidth();
final int random = new Random().nextInt((max - min) + 1) + min;

RelativeLayout relative4 = (RelativeLayout) findViewById(R.id.relative4);
int width = relative4.getMeasuredWidth();
int height = relative4.getMeasuredHeight();
if (imageView == null) {
imageView = new ImageView(this);
}
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);
params.setMargins(new Random().nextInt((width - 0) + 1), new Random().nextInt((height - 0) + 1), 10, 10);
imageView.setLayoutParams(params);
imageView.setImageBitmap(bitmap);


if (imageView != null) {
ViewGroup parent = (ViewGroup) imageView.getParent();
if (parent != null) {
parent.removeView(imageView);
}
}

relative4.addView(imageView);

final ImageView finalImageView = imageView;


imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

switch (value) {
case 1:
drawCircle(finalImageView);
mSuareCount--;
mCircleCount++;
break;

case 2:
drawTriangle(finalImageView);
mCircleCount--;
mTriangelCount++;
break;

case 3:
drawSquare(finalImageView);
mTriangelCount--;
mSuareCount++;
break;

}

}
});

imageView.setOnLongClickListener(new View.OnLongClickListener(){


@Override
public boolean onLongClick(View v) {
switch (value) {
case 1:
relative4.removeView(finalImageView);
mSquareCount--;
break;

case 2:
relative4.removeView(finalImageView);
mCircleCount--;
break;

case 3:
relative4.removeView(finalImageView);
mTriangleCount--;
break;
}
return true;
});
}

}


enter image description here










share|improve this question
























  • Creating bitmap cause an Oop memory allocation issue.
    – Piyush
    Oct 26 at 11:10










  • @Piyush then how to achieve this fuctionality?
    – Rucha Bhatt Joshi
    Oct 26 at 11:20






  • 1




    Why do you need to generate bitmap? Are you getting it from resource drawable or another folder?
    – Piyush
    Oct 26 at 12:04










  • @Piyush how to draw shape on canvas without bitmap!?
    – Rucha Bhatt Joshi
    Oct 26 at 12:17










  • You can go through this too.
    – Piyush
    Oct 26 at 12:20















up vote
1
down vote

favorite












I'm creating android application for shapes on canvas onClick of button.



What I want:



I have three buttons 'Square','Circle','Triangle'.
Each time I tap on button and object of that shape will be created & displayed in a random position on one canvas.(done)



On tap of each shape will cause it to become another shape.
tapping on a square will make it a circle
tapping on a circle will make it a triangle
tapping on a triangle will make it a square (done)



On long tap on a shape can delete the shape.(done)



How to implement undo functionality!



Tried and Error: To achieve this functionality I tried so far following code in which I can create one shape on click of button using bitmap in java and image view in xml.



Update_29/10: I work on same code and create multiple shapes on canvas using dynamic relative layout adding views.



My Question:



Is this right way(bitmap and imageview) to create shape on canvas by clicking on button?



I can create multiple shapes on canvas now but every time I'm creating new canvas instance!any other way to achieve this?



Update_29_10:



How to get click of shape so I can delete shape and undo functionality as well.



XML:



<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context=".MainActivity">

<RelativeLayout
android:id="@+id/relative4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:layout_above="@+id/btnCircle"
android:background="@color/colorAccent">

</RelativeLayout>
<Button
android:id="@+id/btnSquare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/square" />

<Button
android:id="@+id/btnCircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/btnSquare"
android:text="@string/circle" />


<Button
android:id="@+id/btnTriangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/btnCircle"
android:text="@string/triangle" />

<Button
android:id="@+id/btnUndo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/btnTriangle"
android:layout_alignParentBottom="true"
android:text="@string/undo" />




MainActivity.java:



public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Context mContext;
private Resources mResources;
private RelativeLayout mRelativeLayout;
private Button btnSquare, btnCircle, btnTriangle,btnUndo,btnState;
private int mSuareCount=0,mCircleCount=0,mTriangelCount=0;


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

private void initViews() {
mContext = getApplicationContext();
mResources = getResources();
mRelativeLayout = (RelativeLayout) findViewById(R.id.rl);
btnSquare = (Button) findViewById(R.id.btnSquare);
btnCircle = (Button)findViewById(R.id.btnCircle);
btnTriangle = (Button)findViewById(R.id.btnTriangle);
btnUndo=(Button)findViewById(R.id.btnUndo);
setOnClickListeners();
}

private void setOnClickListeners() {
btnSquare.setOnClickListener(this);
btnCircle.setOnClickListener(this);
btnTriangle.setOnClickListener(this);
btnUndo.setOnClickListener(this);
}

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnSquare:
drawSquare(null);
mSuareCount++;
break;

case R.id.btnCircle:
drawCircle(null);
mCircleCount++;
break;

case R.id.btnTriangle:
drawTriangle(null);
mTriangelCount++;
break;

case R.id.btnUndo:

break;

}
}

private void drawSquare(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
50, // Width
50, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.LTGRAY);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.YELLOW);
paint.setAntiAlias(true);

int padding = 50;
Rect rectangle = new Rect(
padding, // Left
padding, // Top
canvas.getWidth() - padding, // Right
canvas.getHeight() - padding // Bottom
);
canvas.drawRect(rectangle, paint);
addViews(bitmap,imageView,1);

// Display the newly created bitmap on app interface
if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);

final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawCircle(finalImageView);
mSuareCount--;
mCircleCount++;
}
});
}

private void drawCircle(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
50, // Width
50, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setAntiAlias(true);

int radius = Math.min(canvas.getWidth(), canvas.getHeight() / 2);
int padding = 5;
canvas.drawCircle(
canvas.getWidth() / 2, // cx
canvas.getHeight() / 2, // cy
radius - padding, // Radius
paint // Paint
);

addViews(bitmap,imageView,2);

// Display the newly created bitmap on app interface
if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);

final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawTriangle(finalImageView);
mCircleCount--;
mTriangelCount++;
}
});

}

private void drawTriangle(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
500, // Width
500, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(),
bitmap.getHeight());


paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.YELLOW);
paint.setAntiAlias(true);
Point point1_draw = new Point(90, 0);
Point point2_draw = new Point(0, 180);
Point point3_draw = new Point(180, 180);

Path path = new Path();
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point1_draw.x, point1_draw.y);
path.close();
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#3F51B5"));
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
//addViews(bitmap,imageView);

addViews(bitmap,imageView,3);

if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);
final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawSquare(finalImageView);
mSuareCount++;
mTriangelCount--;
}
});

}

private void addViews(Bitmap bitmap, ImageView imageView, final int value) {
final int min = 20;
final int max = 80;


Drawable d = getResources().getDrawable(R.mipmap.ic_launcher_round);
final int w = d.getIntrinsicWidth();
final int random = new Random().nextInt((max - min) + 1) + min;

RelativeLayout relative4 = (RelativeLayout) findViewById(R.id.relative4);
int width = relative4.getMeasuredWidth();
int height = relative4.getMeasuredHeight();
if (imageView == null) {
imageView = new ImageView(this);
}
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);
params.setMargins(new Random().nextInt((width - 0) + 1), new Random().nextInt((height - 0) + 1), 10, 10);
imageView.setLayoutParams(params);
imageView.setImageBitmap(bitmap);


if (imageView != null) {
ViewGroup parent = (ViewGroup) imageView.getParent();
if (parent != null) {
parent.removeView(imageView);
}
}

relative4.addView(imageView);

final ImageView finalImageView = imageView;


imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

switch (value) {
case 1:
drawCircle(finalImageView);
mSuareCount--;
mCircleCount++;
break;

case 2:
drawTriangle(finalImageView);
mCircleCount--;
mTriangelCount++;
break;

case 3:
drawSquare(finalImageView);
mTriangelCount--;
mSuareCount++;
break;

}

}
});

imageView.setOnLongClickListener(new View.OnLongClickListener(){


@Override
public boolean onLongClick(View v) {
switch (value) {
case 1:
relative4.removeView(finalImageView);
mSquareCount--;
break;

case 2:
relative4.removeView(finalImageView);
mCircleCount--;
break;

case 3:
relative4.removeView(finalImageView);
mTriangleCount--;
break;
}
return true;
});
}

}


enter image description here










share|improve this question
























  • Creating bitmap cause an Oop memory allocation issue.
    – Piyush
    Oct 26 at 11:10










  • @Piyush then how to achieve this fuctionality?
    – Rucha Bhatt Joshi
    Oct 26 at 11:20






  • 1




    Why do you need to generate bitmap? Are you getting it from resource drawable or another folder?
    – Piyush
    Oct 26 at 12:04










  • @Piyush how to draw shape on canvas without bitmap!?
    – Rucha Bhatt Joshi
    Oct 26 at 12:17










  • You can go through this too.
    – Piyush
    Oct 26 at 12:20













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I'm creating android application for shapes on canvas onClick of button.



What I want:



I have three buttons 'Square','Circle','Triangle'.
Each time I tap on button and object of that shape will be created & displayed in a random position on one canvas.(done)



On tap of each shape will cause it to become another shape.
tapping on a square will make it a circle
tapping on a circle will make it a triangle
tapping on a triangle will make it a square (done)



On long tap on a shape can delete the shape.(done)



How to implement undo functionality!



Tried and Error: To achieve this functionality I tried so far following code in which I can create one shape on click of button using bitmap in java and image view in xml.



Update_29/10: I work on same code and create multiple shapes on canvas using dynamic relative layout adding views.



My Question:



Is this right way(bitmap and imageview) to create shape on canvas by clicking on button?



I can create multiple shapes on canvas now but every time I'm creating new canvas instance!any other way to achieve this?



Update_29_10:



How to get click of shape so I can delete shape and undo functionality as well.



XML:



<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context=".MainActivity">

<RelativeLayout
android:id="@+id/relative4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:layout_above="@+id/btnCircle"
android:background="@color/colorAccent">

</RelativeLayout>
<Button
android:id="@+id/btnSquare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/square" />

<Button
android:id="@+id/btnCircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/btnSquare"
android:text="@string/circle" />


<Button
android:id="@+id/btnTriangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/btnCircle"
android:text="@string/triangle" />

<Button
android:id="@+id/btnUndo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/btnTriangle"
android:layout_alignParentBottom="true"
android:text="@string/undo" />




MainActivity.java:



public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Context mContext;
private Resources mResources;
private RelativeLayout mRelativeLayout;
private Button btnSquare, btnCircle, btnTriangle,btnUndo,btnState;
private int mSuareCount=0,mCircleCount=0,mTriangelCount=0;


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

private void initViews() {
mContext = getApplicationContext();
mResources = getResources();
mRelativeLayout = (RelativeLayout) findViewById(R.id.rl);
btnSquare = (Button) findViewById(R.id.btnSquare);
btnCircle = (Button)findViewById(R.id.btnCircle);
btnTriangle = (Button)findViewById(R.id.btnTriangle);
btnUndo=(Button)findViewById(R.id.btnUndo);
setOnClickListeners();
}

private void setOnClickListeners() {
btnSquare.setOnClickListener(this);
btnCircle.setOnClickListener(this);
btnTriangle.setOnClickListener(this);
btnUndo.setOnClickListener(this);
}

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnSquare:
drawSquare(null);
mSuareCount++;
break;

case R.id.btnCircle:
drawCircle(null);
mCircleCount++;
break;

case R.id.btnTriangle:
drawTriangle(null);
mTriangelCount++;
break;

case R.id.btnUndo:

break;

}
}

private void drawSquare(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
50, // Width
50, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.LTGRAY);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.YELLOW);
paint.setAntiAlias(true);

int padding = 50;
Rect rectangle = new Rect(
padding, // Left
padding, // Top
canvas.getWidth() - padding, // Right
canvas.getHeight() - padding // Bottom
);
canvas.drawRect(rectangle, paint);
addViews(bitmap,imageView,1);

// Display the newly created bitmap on app interface
if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);

final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawCircle(finalImageView);
mSuareCount--;
mCircleCount++;
}
});
}

private void drawCircle(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
50, // Width
50, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setAntiAlias(true);

int radius = Math.min(canvas.getWidth(), canvas.getHeight() / 2);
int padding = 5;
canvas.drawCircle(
canvas.getWidth() / 2, // cx
canvas.getHeight() / 2, // cy
radius - padding, // Radius
paint // Paint
);

addViews(bitmap,imageView,2);

// Display the newly created bitmap on app interface
if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);

final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawTriangle(finalImageView);
mCircleCount--;
mTriangelCount++;
}
});

}

private void drawTriangle(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
500, // Width
500, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(),
bitmap.getHeight());


paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.YELLOW);
paint.setAntiAlias(true);
Point point1_draw = new Point(90, 0);
Point point2_draw = new Point(0, 180);
Point point3_draw = new Point(180, 180);

Path path = new Path();
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point1_draw.x, point1_draw.y);
path.close();
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#3F51B5"));
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
//addViews(bitmap,imageView);

addViews(bitmap,imageView,3);

if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);
final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawSquare(finalImageView);
mSuareCount++;
mTriangelCount--;
}
});

}

private void addViews(Bitmap bitmap, ImageView imageView, final int value) {
final int min = 20;
final int max = 80;


Drawable d = getResources().getDrawable(R.mipmap.ic_launcher_round);
final int w = d.getIntrinsicWidth();
final int random = new Random().nextInt((max - min) + 1) + min;

RelativeLayout relative4 = (RelativeLayout) findViewById(R.id.relative4);
int width = relative4.getMeasuredWidth();
int height = relative4.getMeasuredHeight();
if (imageView == null) {
imageView = new ImageView(this);
}
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);
params.setMargins(new Random().nextInt((width - 0) + 1), new Random().nextInt((height - 0) + 1), 10, 10);
imageView.setLayoutParams(params);
imageView.setImageBitmap(bitmap);


if (imageView != null) {
ViewGroup parent = (ViewGroup) imageView.getParent();
if (parent != null) {
parent.removeView(imageView);
}
}

relative4.addView(imageView);

final ImageView finalImageView = imageView;


imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

switch (value) {
case 1:
drawCircle(finalImageView);
mSuareCount--;
mCircleCount++;
break;

case 2:
drawTriangle(finalImageView);
mCircleCount--;
mTriangelCount++;
break;

case 3:
drawSquare(finalImageView);
mTriangelCount--;
mSuareCount++;
break;

}

}
});

imageView.setOnLongClickListener(new View.OnLongClickListener(){


@Override
public boolean onLongClick(View v) {
switch (value) {
case 1:
relative4.removeView(finalImageView);
mSquareCount--;
break;

case 2:
relative4.removeView(finalImageView);
mCircleCount--;
break;

case 3:
relative4.removeView(finalImageView);
mTriangleCount--;
break;
}
return true;
});
}

}


enter image description here










share|improve this question















I'm creating android application for shapes on canvas onClick of button.



What I want:



I have three buttons 'Square','Circle','Triangle'.
Each time I tap on button and object of that shape will be created & displayed in a random position on one canvas.(done)



On tap of each shape will cause it to become another shape.
tapping on a square will make it a circle
tapping on a circle will make it a triangle
tapping on a triangle will make it a square (done)



On long tap on a shape can delete the shape.(done)



How to implement undo functionality!



Tried and Error: To achieve this functionality I tried so far following code in which I can create one shape on click of button using bitmap in java and image view in xml.



Update_29/10: I work on same code and create multiple shapes on canvas using dynamic relative layout adding views.



My Question:



Is this right way(bitmap and imageview) to create shape on canvas by clicking on button?



I can create multiple shapes on canvas now but every time I'm creating new canvas instance!any other way to achieve this?



Update_29_10:



How to get click of shape so I can delete shape and undo functionality as well.



XML:



<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context=".MainActivity">

<RelativeLayout
android:id="@+id/relative4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:layout_above="@+id/btnCircle"
android:background="@color/colorAccent">

</RelativeLayout>
<Button
android:id="@+id/btnSquare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/square" />

<Button
android:id="@+id/btnCircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/btnSquare"
android:text="@string/circle" />


<Button
android:id="@+id/btnTriangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/btnCircle"
android:text="@string/triangle" />

<Button
android:id="@+id/btnUndo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/btnTriangle"
android:layout_alignParentBottom="true"
android:text="@string/undo" />




MainActivity.java:



public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Context mContext;
private Resources mResources;
private RelativeLayout mRelativeLayout;
private Button btnSquare, btnCircle, btnTriangle,btnUndo,btnState;
private int mSuareCount=0,mCircleCount=0,mTriangelCount=0;


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

private void initViews() {
mContext = getApplicationContext();
mResources = getResources();
mRelativeLayout = (RelativeLayout) findViewById(R.id.rl);
btnSquare = (Button) findViewById(R.id.btnSquare);
btnCircle = (Button)findViewById(R.id.btnCircle);
btnTriangle = (Button)findViewById(R.id.btnTriangle);
btnUndo=(Button)findViewById(R.id.btnUndo);
setOnClickListeners();
}

private void setOnClickListeners() {
btnSquare.setOnClickListener(this);
btnCircle.setOnClickListener(this);
btnTriangle.setOnClickListener(this);
btnUndo.setOnClickListener(this);
}

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnSquare:
drawSquare(null);
mSuareCount++;
break;

case R.id.btnCircle:
drawCircle(null);
mCircleCount++;
break;

case R.id.btnTriangle:
drawTriangle(null);
mTriangelCount++;
break;

case R.id.btnUndo:

break;

}
}

private void drawSquare(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
50, // Width
50, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.LTGRAY);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.YELLOW);
paint.setAntiAlias(true);

int padding = 50;
Rect rectangle = new Rect(
padding, // Left
padding, // Top
canvas.getWidth() - padding, // Right
canvas.getHeight() - padding // Bottom
);
canvas.drawRect(rectangle, paint);
addViews(bitmap,imageView,1);

// Display the newly created bitmap on app interface
if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);

final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawCircle(finalImageView);
mSuareCount--;
mCircleCount++;
}
});
}

private void drawCircle(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
50, // Width
50, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setAntiAlias(true);

int radius = Math.min(canvas.getWidth(), canvas.getHeight() / 2);
int padding = 5;
canvas.drawCircle(
canvas.getWidth() / 2, // cx
canvas.getHeight() / 2, // cy
radius - padding, // Radius
paint // Paint
);

addViews(bitmap,imageView,2);

// Display the newly created bitmap on app interface
if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);

final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawTriangle(finalImageView);
mCircleCount--;
mTriangelCount++;
}
});

}

private void drawTriangle(ImageView imageView) {
Bitmap bitmap = Bitmap.createBitmap(
500, // Width
500, // Height
Bitmap.Config.ARGB_8888 // Config
);

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(),
bitmap.getHeight());


paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.YELLOW);
paint.setAntiAlias(true);
Point point1_draw = new Point(90, 0);
Point point2_draw = new Point(0, 180);
Point point3_draw = new Point(180, 180);

Path path = new Path();
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point1_draw.x, point1_draw.y);
path.close();
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#3F51B5"));
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
//addViews(bitmap,imageView);

addViews(bitmap,imageView,3);

if (imageView == null) {
imageView = new ImageView(this);
}
imageView.setImageBitmap(bitmap);
final ImageView finalImageView = imageView;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
drawSquare(finalImageView);
mSuareCount++;
mTriangelCount--;
}
});

}

private void addViews(Bitmap bitmap, ImageView imageView, final int value) {
final int min = 20;
final int max = 80;


Drawable d = getResources().getDrawable(R.mipmap.ic_launcher_round);
final int w = d.getIntrinsicWidth();
final int random = new Random().nextInt((max - min) + 1) + min;

RelativeLayout relative4 = (RelativeLayout) findViewById(R.id.relative4);
int width = relative4.getMeasuredWidth();
int height = relative4.getMeasuredHeight();
if (imageView == null) {
imageView = new ImageView(this);
}
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);
params.setMargins(new Random().nextInt((width - 0) + 1), new Random().nextInt((height - 0) + 1), 10, 10);
imageView.setLayoutParams(params);
imageView.setImageBitmap(bitmap);


if (imageView != null) {
ViewGroup parent = (ViewGroup) imageView.getParent();
if (parent != null) {
parent.removeView(imageView);
}
}

relative4.addView(imageView);

final ImageView finalImageView = imageView;


imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

switch (value) {
case 1:
drawCircle(finalImageView);
mSuareCount--;
mCircleCount++;
break;

case 2:
drawTriangle(finalImageView);
mCircleCount--;
mTriangelCount++;
break;

case 3:
drawSquare(finalImageView);
mTriangelCount--;
mSuareCount++;
break;

}

}
});

imageView.setOnLongClickListener(new View.OnLongClickListener(){


@Override
public boolean onLongClick(View v) {
switch (value) {
case 1:
relative4.removeView(finalImageView);
mSquareCount--;
break;

case 2:
relative4.removeView(finalImageView);
mCircleCount--;
break;

case 3:
relative4.removeView(finalImageView);
mTriangleCount--;
break;
}
return true;
});
}

}


enter image description here







android canvas shapes buttonclick ondraw






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 7 at 11:07

























asked Oct 26 at 10:43









Rucha Bhatt Joshi

66611026




66611026












  • Creating bitmap cause an Oop memory allocation issue.
    – Piyush
    Oct 26 at 11:10










  • @Piyush then how to achieve this fuctionality?
    – Rucha Bhatt Joshi
    Oct 26 at 11:20






  • 1




    Why do you need to generate bitmap? Are you getting it from resource drawable or another folder?
    – Piyush
    Oct 26 at 12:04










  • @Piyush how to draw shape on canvas without bitmap!?
    – Rucha Bhatt Joshi
    Oct 26 at 12:17










  • You can go through this too.
    – Piyush
    Oct 26 at 12:20


















  • Creating bitmap cause an Oop memory allocation issue.
    – Piyush
    Oct 26 at 11:10










  • @Piyush then how to achieve this fuctionality?
    – Rucha Bhatt Joshi
    Oct 26 at 11:20






  • 1




    Why do you need to generate bitmap? Are you getting it from resource drawable or another folder?
    – Piyush
    Oct 26 at 12:04










  • @Piyush how to draw shape on canvas without bitmap!?
    – Rucha Bhatt Joshi
    Oct 26 at 12:17










  • You can go through this too.
    – Piyush
    Oct 26 at 12:20
















Creating bitmap cause an Oop memory allocation issue.
– Piyush
Oct 26 at 11:10




Creating bitmap cause an Oop memory allocation issue.
– Piyush
Oct 26 at 11:10












@Piyush then how to achieve this fuctionality?
– Rucha Bhatt Joshi
Oct 26 at 11:20




@Piyush then how to achieve this fuctionality?
– Rucha Bhatt Joshi
Oct 26 at 11:20




1




1




Why do you need to generate bitmap? Are you getting it from resource drawable or another folder?
– Piyush
Oct 26 at 12:04




Why do you need to generate bitmap? Are you getting it from resource drawable or another folder?
– Piyush
Oct 26 at 12:04












@Piyush how to draw shape on canvas without bitmap!?
– Rucha Bhatt Joshi
Oct 26 at 12:17




@Piyush how to draw shape on canvas without bitmap!?
– Rucha Bhatt Joshi
Oct 26 at 12:17












You can go through this too.
– Piyush
Oct 26 at 12:20




You can go through this too.
– Piyush
Oct 26 at 12:20












2 Answers
2






active

oldest

votes

















up vote
1
down vote



accepted
+50










While aanshu's solution is probably the more efficient way to do this, his solution makes it difficult to recognize clicks on the single shapes.



Instead of making one big subclass of ImageView and overriding onDraw and drawing each of the sub-shapes, you could make a subclass of ImageView for each class of square, circle and triangle. Something like this:



public class SquareView extends ImageView {
@Override
protected void onDraw(Canvas canvas) {
//draw your Square on the canvas given
}
}


Same for Circle and triangle. Then just generate one of these views as you were generating image views before but do not set the Bitmap. You can add them to the layout and it will call the onDraw function and give it a canvas. Now you can register your onClickListener for each of these views as before. When the view is clicked you replace it with an instance of a different class, for example you replace SquareView with a CircleView.



For the undo operations, you could just make this. This is very pseudocode like, I also might be mixing some programming languages but the idea is everywhere the same. If something is unclear, please ask.



Stack<Runnable> undoStack;
//and now whenever you do something that should be undoable you just add a runnable that will undo it:
//for example if a user clicked a SquareView:
removeView(squareView);
CircleView circleView = new CircleView();
//take the information from the squareView that is needed
circleview.position = squareView.position;
addView(circleView);
undoStack.push(() -> removeView(circleView); addView(squareView););
//When you undo you just call
undoStack.pop().run();


A bit of background about your code, because I think it will help you understand. This is the source of android ImageView. When you call setImageBitmap(bitmap), it passes the bitmap to an instance of BitmapDrawable which it calls mDrawable. Then in the ImageViews onDraw(Canvas canvas) method it calls mDrawable.draw(canvas) which in case of BitmapDrawable (source here) after a lot of other stuff calls canvas.drawBitmap(bitmap). So basically what your code does: it creates a Bitmap from a canvas and then via ImageView and BitmapDrawable the bitmap is drawn back on a canvas. My and aanshu's solution draw directly on this final canvas. That is why they are better than your current solution.



Edit:
While searching something else, I stumbled upon drawable shape resources. As with any drawable resource you can just pass them to ImageViews. This way you probably wouldn't have to override the onDraw function. But I never worked with them, so I'll just leave this here.






share|improve this answer























  • for daw square,circle and triangle same function I should use?
    – Rucha Bhatt Joshi
    Nov 7 at 10:27












  • You make three classes SquareView, CircleView and TriangleView. In each of these classes you implement the drawing in the onDraw function.
    – findusl
    Nov 7 at 10:28










  • which function I have to use to create that shape same function which I used before? I'll try your solution
    – Rucha Bhatt Joshi
    Nov 7 at 10:38










  • Yes you draw the shapes the same way as you did before on the canvas that is passed to onDraw. Make sure the view has the right size then the canvas should have the size as well.
    – findusl
    Nov 7 at 10:41






  • 1




    A quick comment: you probably want to extend View instead of ImageView. Not only do you lose all of ImageView's functionality when you override onDraw(), but you're going to do something very different from an ImageView (drawing vectors vs. drawing bitmaps).
    – Project
    Nov 7 at 19:50




















up vote
2
down vote













You may implement the functionality using with the following approach (psudo code):



Step 1:



interface ShapeInfo {
void drawShape(Canvas canvas);
}


Step 2:
Implement the 3 different classes (Rect, Triangle, Circle) with this interface



Step 3: Set a background to RelativeLayout



Step 4: Add a CustomView in RelativeLayout
make this custom view transparent.



    public class CustomView extends ImageView{

ArrayList<ShapeInfo> alShapesInfo = new ArrayList();
public CustomView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for ( ShapeInfo s:alShapesInfo)
s.drawShape(canvas);

}
public void addShapeInfo(ShapeInfo s){alShapeinfo.add(s); invalidate();}

public void undo(){alShapeInfo.delete(alShapeInfo.size()-1); invalidate();}
}


Spte 5:
In main activity on button click of add triangle, circle, rect call customview.addshapeinfo



Step 6: to undo call



customview.undo





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53006963%2fcreate-change-delete-undo-number-of-different-shapes-on-canvas-onclick-of-but%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote



    accepted
    +50










    While aanshu's solution is probably the more efficient way to do this, his solution makes it difficult to recognize clicks on the single shapes.



    Instead of making one big subclass of ImageView and overriding onDraw and drawing each of the sub-shapes, you could make a subclass of ImageView for each class of square, circle and triangle. Something like this:



    public class SquareView extends ImageView {
    @Override
    protected void onDraw(Canvas canvas) {
    //draw your Square on the canvas given
    }
    }


    Same for Circle and triangle. Then just generate one of these views as you were generating image views before but do not set the Bitmap. You can add them to the layout and it will call the onDraw function and give it a canvas. Now you can register your onClickListener for each of these views as before. When the view is clicked you replace it with an instance of a different class, for example you replace SquareView with a CircleView.



    For the undo operations, you could just make this. This is very pseudocode like, I also might be mixing some programming languages but the idea is everywhere the same. If something is unclear, please ask.



    Stack<Runnable> undoStack;
    //and now whenever you do something that should be undoable you just add a runnable that will undo it:
    //for example if a user clicked a SquareView:
    removeView(squareView);
    CircleView circleView = new CircleView();
    //take the information from the squareView that is needed
    circleview.position = squareView.position;
    addView(circleView);
    undoStack.push(() -> removeView(circleView); addView(squareView););
    //When you undo you just call
    undoStack.pop().run();


    A bit of background about your code, because I think it will help you understand. This is the source of android ImageView. When you call setImageBitmap(bitmap), it passes the bitmap to an instance of BitmapDrawable which it calls mDrawable. Then in the ImageViews onDraw(Canvas canvas) method it calls mDrawable.draw(canvas) which in case of BitmapDrawable (source here) after a lot of other stuff calls canvas.drawBitmap(bitmap). So basically what your code does: it creates a Bitmap from a canvas and then via ImageView and BitmapDrawable the bitmap is drawn back on a canvas. My and aanshu's solution draw directly on this final canvas. That is why they are better than your current solution.



    Edit:
    While searching something else, I stumbled upon drawable shape resources. As with any drawable resource you can just pass them to ImageViews. This way you probably wouldn't have to override the onDraw function. But I never worked with them, so I'll just leave this here.






    share|improve this answer























    • for daw square,circle and triangle same function I should use?
      – Rucha Bhatt Joshi
      Nov 7 at 10:27












    • You make three classes SquareView, CircleView and TriangleView. In each of these classes you implement the drawing in the onDraw function.
      – findusl
      Nov 7 at 10:28










    • which function I have to use to create that shape same function which I used before? I'll try your solution
      – Rucha Bhatt Joshi
      Nov 7 at 10:38










    • Yes you draw the shapes the same way as you did before on the canvas that is passed to onDraw. Make sure the view has the right size then the canvas should have the size as well.
      – findusl
      Nov 7 at 10:41






    • 1




      A quick comment: you probably want to extend View instead of ImageView. Not only do you lose all of ImageView's functionality when you override onDraw(), but you're going to do something very different from an ImageView (drawing vectors vs. drawing bitmaps).
      – Project
      Nov 7 at 19:50

















    up vote
    1
    down vote



    accepted
    +50










    While aanshu's solution is probably the more efficient way to do this, his solution makes it difficult to recognize clicks on the single shapes.



    Instead of making one big subclass of ImageView and overriding onDraw and drawing each of the sub-shapes, you could make a subclass of ImageView for each class of square, circle and triangle. Something like this:



    public class SquareView extends ImageView {
    @Override
    protected void onDraw(Canvas canvas) {
    //draw your Square on the canvas given
    }
    }


    Same for Circle and triangle. Then just generate one of these views as you were generating image views before but do not set the Bitmap. You can add them to the layout and it will call the onDraw function and give it a canvas. Now you can register your onClickListener for each of these views as before. When the view is clicked you replace it with an instance of a different class, for example you replace SquareView with a CircleView.



    For the undo operations, you could just make this. This is very pseudocode like, I also might be mixing some programming languages but the idea is everywhere the same. If something is unclear, please ask.



    Stack<Runnable> undoStack;
    //and now whenever you do something that should be undoable you just add a runnable that will undo it:
    //for example if a user clicked a SquareView:
    removeView(squareView);
    CircleView circleView = new CircleView();
    //take the information from the squareView that is needed
    circleview.position = squareView.position;
    addView(circleView);
    undoStack.push(() -> removeView(circleView); addView(squareView););
    //When you undo you just call
    undoStack.pop().run();


    A bit of background about your code, because I think it will help you understand. This is the source of android ImageView. When you call setImageBitmap(bitmap), it passes the bitmap to an instance of BitmapDrawable which it calls mDrawable. Then in the ImageViews onDraw(Canvas canvas) method it calls mDrawable.draw(canvas) which in case of BitmapDrawable (source here) after a lot of other stuff calls canvas.drawBitmap(bitmap). So basically what your code does: it creates a Bitmap from a canvas and then via ImageView and BitmapDrawable the bitmap is drawn back on a canvas. My and aanshu's solution draw directly on this final canvas. That is why they are better than your current solution.



    Edit:
    While searching something else, I stumbled upon drawable shape resources. As with any drawable resource you can just pass them to ImageViews. This way you probably wouldn't have to override the onDraw function. But I never worked with them, so I'll just leave this here.






    share|improve this answer























    • for daw square,circle and triangle same function I should use?
      – Rucha Bhatt Joshi
      Nov 7 at 10:27












    • You make three classes SquareView, CircleView and TriangleView. In each of these classes you implement the drawing in the onDraw function.
      – findusl
      Nov 7 at 10:28










    • which function I have to use to create that shape same function which I used before? I'll try your solution
      – Rucha Bhatt Joshi
      Nov 7 at 10:38










    • Yes you draw the shapes the same way as you did before on the canvas that is passed to onDraw. Make sure the view has the right size then the canvas should have the size as well.
      – findusl
      Nov 7 at 10:41






    • 1




      A quick comment: you probably want to extend View instead of ImageView. Not only do you lose all of ImageView's functionality when you override onDraw(), but you're going to do something very different from an ImageView (drawing vectors vs. drawing bitmaps).
      – Project
      Nov 7 at 19:50















    up vote
    1
    down vote



    accepted
    +50







    up vote
    1
    down vote



    accepted
    +50




    +50




    While aanshu's solution is probably the more efficient way to do this, his solution makes it difficult to recognize clicks on the single shapes.



    Instead of making one big subclass of ImageView and overriding onDraw and drawing each of the sub-shapes, you could make a subclass of ImageView for each class of square, circle and triangle. Something like this:



    public class SquareView extends ImageView {
    @Override
    protected void onDraw(Canvas canvas) {
    //draw your Square on the canvas given
    }
    }


    Same for Circle and triangle. Then just generate one of these views as you were generating image views before but do not set the Bitmap. You can add them to the layout and it will call the onDraw function and give it a canvas. Now you can register your onClickListener for each of these views as before. When the view is clicked you replace it with an instance of a different class, for example you replace SquareView with a CircleView.



    For the undo operations, you could just make this. This is very pseudocode like, I also might be mixing some programming languages but the idea is everywhere the same. If something is unclear, please ask.



    Stack<Runnable> undoStack;
    //and now whenever you do something that should be undoable you just add a runnable that will undo it:
    //for example if a user clicked a SquareView:
    removeView(squareView);
    CircleView circleView = new CircleView();
    //take the information from the squareView that is needed
    circleview.position = squareView.position;
    addView(circleView);
    undoStack.push(() -> removeView(circleView); addView(squareView););
    //When you undo you just call
    undoStack.pop().run();


    A bit of background about your code, because I think it will help you understand. This is the source of android ImageView. When you call setImageBitmap(bitmap), it passes the bitmap to an instance of BitmapDrawable which it calls mDrawable. Then in the ImageViews onDraw(Canvas canvas) method it calls mDrawable.draw(canvas) which in case of BitmapDrawable (source here) after a lot of other stuff calls canvas.drawBitmap(bitmap). So basically what your code does: it creates a Bitmap from a canvas and then via ImageView and BitmapDrawable the bitmap is drawn back on a canvas. My and aanshu's solution draw directly on this final canvas. That is why they are better than your current solution.



    Edit:
    While searching something else, I stumbled upon drawable shape resources. As with any drawable resource you can just pass them to ImageViews. This way you probably wouldn't have to override the onDraw function. But I never worked with them, so I'll just leave this here.






    share|improve this answer














    While aanshu's solution is probably the more efficient way to do this, his solution makes it difficult to recognize clicks on the single shapes.



    Instead of making one big subclass of ImageView and overriding onDraw and drawing each of the sub-shapes, you could make a subclass of ImageView for each class of square, circle and triangle. Something like this:



    public class SquareView extends ImageView {
    @Override
    protected void onDraw(Canvas canvas) {
    //draw your Square on the canvas given
    }
    }


    Same for Circle and triangle. Then just generate one of these views as you were generating image views before but do not set the Bitmap. You can add them to the layout and it will call the onDraw function and give it a canvas. Now you can register your onClickListener for each of these views as before. When the view is clicked you replace it with an instance of a different class, for example you replace SquareView with a CircleView.



    For the undo operations, you could just make this. This is very pseudocode like, I also might be mixing some programming languages but the idea is everywhere the same. If something is unclear, please ask.



    Stack<Runnable> undoStack;
    //and now whenever you do something that should be undoable you just add a runnable that will undo it:
    //for example if a user clicked a SquareView:
    removeView(squareView);
    CircleView circleView = new CircleView();
    //take the information from the squareView that is needed
    circleview.position = squareView.position;
    addView(circleView);
    undoStack.push(() -> removeView(circleView); addView(squareView););
    //When you undo you just call
    undoStack.pop().run();


    A bit of background about your code, because I think it will help you understand. This is the source of android ImageView. When you call setImageBitmap(bitmap), it passes the bitmap to an instance of BitmapDrawable which it calls mDrawable. Then in the ImageViews onDraw(Canvas canvas) method it calls mDrawable.draw(canvas) which in case of BitmapDrawable (source here) after a lot of other stuff calls canvas.drawBitmap(bitmap). So basically what your code does: it creates a Bitmap from a canvas and then via ImageView and BitmapDrawable the bitmap is drawn back on a canvas. My and aanshu's solution draw directly on this final canvas. That is why they are better than your current solution.



    Edit:
    While searching something else, I stumbled upon drawable shape resources. As with any drawable resource you can just pass them to ImageViews. This way you probably wouldn't have to override the onDraw function. But I never worked with them, so I'll just leave this here.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 7 at 15:37

























    answered Nov 6 at 11:07









    findusl

    729724




    729724












    • for daw square,circle and triangle same function I should use?
      – Rucha Bhatt Joshi
      Nov 7 at 10:27












    • You make three classes SquareView, CircleView and TriangleView. In each of these classes you implement the drawing in the onDraw function.
      – findusl
      Nov 7 at 10:28










    • which function I have to use to create that shape same function which I used before? I'll try your solution
      – Rucha Bhatt Joshi
      Nov 7 at 10:38










    • Yes you draw the shapes the same way as you did before on the canvas that is passed to onDraw. Make sure the view has the right size then the canvas should have the size as well.
      – findusl
      Nov 7 at 10:41






    • 1




      A quick comment: you probably want to extend View instead of ImageView. Not only do you lose all of ImageView's functionality when you override onDraw(), but you're going to do something very different from an ImageView (drawing vectors vs. drawing bitmaps).
      – Project
      Nov 7 at 19:50




















    • for daw square,circle and triangle same function I should use?
      – Rucha Bhatt Joshi
      Nov 7 at 10:27












    • You make three classes SquareView, CircleView and TriangleView. In each of these classes you implement the drawing in the onDraw function.
      – findusl
      Nov 7 at 10:28










    • which function I have to use to create that shape same function which I used before? I'll try your solution
      – Rucha Bhatt Joshi
      Nov 7 at 10:38










    • Yes you draw the shapes the same way as you did before on the canvas that is passed to onDraw. Make sure the view has the right size then the canvas should have the size as well.
      – findusl
      Nov 7 at 10:41






    • 1




      A quick comment: you probably want to extend View instead of ImageView. Not only do you lose all of ImageView's functionality when you override onDraw(), but you're going to do something very different from an ImageView (drawing vectors vs. drawing bitmaps).
      – Project
      Nov 7 at 19:50


















    for daw square,circle and triangle same function I should use?
    – Rucha Bhatt Joshi
    Nov 7 at 10:27






    for daw square,circle and triangle same function I should use?
    – Rucha Bhatt Joshi
    Nov 7 at 10:27














    You make three classes SquareView, CircleView and TriangleView. In each of these classes you implement the drawing in the onDraw function.
    – findusl
    Nov 7 at 10:28




    You make three classes SquareView, CircleView and TriangleView. In each of these classes you implement the drawing in the onDraw function.
    – findusl
    Nov 7 at 10:28












    which function I have to use to create that shape same function which I used before? I'll try your solution
    – Rucha Bhatt Joshi
    Nov 7 at 10:38




    which function I have to use to create that shape same function which I used before? I'll try your solution
    – Rucha Bhatt Joshi
    Nov 7 at 10:38












    Yes you draw the shapes the same way as you did before on the canvas that is passed to onDraw. Make sure the view has the right size then the canvas should have the size as well.
    – findusl
    Nov 7 at 10:41




    Yes you draw the shapes the same way as you did before on the canvas that is passed to onDraw. Make sure the view has the right size then the canvas should have the size as well.
    – findusl
    Nov 7 at 10:41




    1




    1




    A quick comment: you probably want to extend View instead of ImageView. Not only do you lose all of ImageView's functionality when you override onDraw(), but you're going to do something very different from an ImageView (drawing vectors vs. drawing bitmaps).
    – Project
    Nov 7 at 19:50






    A quick comment: you probably want to extend View instead of ImageView. Not only do you lose all of ImageView's functionality when you override onDraw(), but you're going to do something very different from an ImageView (drawing vectors vs. drawing bitmaps).
    – Project
    Nov 7 at 19:50














    up vote
    2
    down vote













    You may implement the functionality using with the following approach (psudo code):



    Step 1:



    interface ShapeInfo {
    void drawShape(Canvas canvas);
    }


    Step 2:
    Implement the 3 different classes (Rect, Triangle, Circle) with this interface



    Step 3: Set a background to RelativeLayout



    Step 4: Add a CustomView in RelativeLayout
    make this custom view transparent.



        public class CustomView extends ImageView{

    ArrayList<ShapeInfo> alShapesInfo = new ArrayList();
    public CustomView(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
    }

    @Override
    protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    for ( ShapeInfo s:alShapesInfo)
    s.drawShape(canvas);

    }
    public void addShapeInfo(ShapeInfo s){alShapeinfo.add(s); invalidate();}

    public void undo(){alShapeInfo.delete(alShapeInfo.size()-1); invalidate();}
    }


    Spte 5:
    In main activity on button click of add triangle, circle, rect call customview.addshapeinfo



    Step 6: to undo call



    customview.undo





    share|improve this answer



























      up vote
      2
      down vote













      You may implement the functionality using with the following approach (psudo code):



      Step 1:



      interface ShapeInfo {
      void drawShape(Canvas canvas);
      }


      Step 2:
      Implement the 3 different classes (Rect, Triangle, Circle) with this interface



      Step 3: Set a background to RelativeLayout



      Step 4: Add a CustomView in RelativeLayout
      make this custom view transparent.



          public class CustomView extends ImageView{

      ArrayList<ShapeInfo> alShapesInfo = new ArrayList();
      public CustomView(Context context) {
      super(context);
      // TODO Auto-generated constructor stub
      }

      @Override
      protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);
      for ( ShapeInfo s:alShapesInfo)
      s.drawShape(canvas);

      }
      public void addShapeInfo(ShapeInfo s){alShapeinfo.add(s); invalidate();}

      public void undo(){alShapeInfo.delete(alShapeInfo.size()-1); invalidate();}
      }


      Spte 5:
      In main activity on button click of add triangle, circle, rect call customview.addshapeinfo



      Step 6: to undo call



      customview.undo





      share|improve this answer

























        up vote
        2
        down vote










        up vote
        2
        down vote









        You may implement the functionality using with the following approach (psudo code):



        Step 1:



        interface ShapeInfo {
        void drawShape(Canvas canvas);
        }


        Step 2:
        Implement the 3 different classes (Rect, Triangle, Circle) with this interface



        Step 3: Set a background to RelativeLayout



        Step 4: Add a CustomView in RelativeLayout
        make this custom view transparent.



            public class CustomView extends ImageView{

        ArrayList<ShapeInfo> alShapesInfo = new ArrayList();
        public CustomView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        }

        @Override
        protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for ( ShapeInfo s:alShapesInfo)
        s.drawShape(canvas);

        }
        public void addShapeInfo(ShapeInfo s){alShapeinfo.add(s); invalidate();}

        public void undo(){alShapeInfo.delete(alShapeInfo.size()-1); invalidate();}
        }


        Spte 5:
        In main activity on button click of add triangle, circle, rect call customview.addshapeinfo



        Step 6: to undo call



        customview.undo





        share|improve this answer














        You may implement the functionality using with the following approach (psudo code):



        Step 1:



        interface ShapeInfo {
        void drawShape(Canvas canvas);
        }


        Step 2:
        Implement the 3 different classes (Rect, Triangle, Circle) with this interface



        Step 3: Set a background to RelativeLayout



        Step 4: Add a CustomView in RelativeLayout
        make this custom view transparent.



            public class CustomView extends ImageView{

        ArrayList<ShapeInfo> alShapesInfo = new ArrayList();
        public CustomView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        }

        @Override
        protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for ( ShapeInfo s:alShapesInfo)
        s.drawShape(canvas);

        }
        public void addShapeInfo(ShapeInfo s){alShapeinfo.add(s); invalidate();}

        public void undo(){alShapeInfo.delete(alShapeInfo.size()-1); invalidate();}
        }


        Spte 5:
        In main activity on button click of add triangle, circle, rect call customview.addshapeinfo



        Step 6: to undo call



        customview.undo






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 6 at 7:43

























        answered Nov 6 at 7:28









        aanshu

        1,035611




        1,035611






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53006963%2fcreate-change-delete-undo-number-of-different-shapes-on-canvas-onclick-of-but%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Xamarin.form Move up view when keyboard appear

            Post-Redirect-Get with Spring WebFlux and Thymeleaf

            Anylogic : not able to use stopDelay()