I am new to android programing. I am trying to draw a new bitmap image every time the user touches the screen. With the current code right now, all it does is change where the bitmap is at. It doesn't make a new one. How could I make a new one?? Here is the code:
public class MainDrawingView extends View {
public float eventX;
public float eventY;
public AlertDialog.Builder alertThing;
Context context = getContext();
//Bitmaps
public Bitmap redSquare;
public String x;
public String y;
//Colors
public boolean red = false;
public boolean blue = false;
//Squares
public boolean topRight = false;
public boolean topLeft = false;
public boolean bottomLeft = false;
public boolean bottomRight = false;
public int width = context.getResources().getDisplayMetrics().widthPixels;
public int height = context.getResources().getDisplayMetrics().heightPixels;
public int center = height/2;
public int widthDiv = width/2;
private Paint paint = new Paint();
private Point pointStart = new Point();
private Point pointEnd = new Point();
public MainDrawingView(Context context, AttributeSet attrs){
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(5f);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
alertThing = new AlertDialog.Builder(context);
//define bitmap
redSquare = BitmapFactory.decodeResource(getResources(), R.drawable.red);
}
#Override
public void onDraw(Canvas canvas){
//canvas.drawPath(path, paint);
canvas.drawLine(pointStart.x, pointStart.y, pointEnd.x, pointEnd.y,paint);
//Makes a straight line go through the center of the screen.
canvas.drawLine(0,height/2.5f, width,height/2.5f,paint);
//Makes a straight line go up and down.
canvas.drawLine(width/2.3f,0, width/2.3f, height,paint);
//Chnages the square colors.
// top left combo
if(topLeft){
if(red){
Toast.makeText(context,"jgjgjgjgjgjgjgjgjjg", Toast.LENGTH_SHORT).show();
new Drawings(redSquare, canvas, eventX, eventY);
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event){
//Gets the coords of the tap
eventX = event.getX();
eventY = event.getY();
int pointX = Math.round(eventX);
int pointY = Math.round(eventY);
x = String.valueOf(eventX);
y = String.valueOf(eventY);
//This is the top left "square"
if(eventY < center && eventX < widthDiv ){
alertThing.setTitle("edit square");
alertThing.setMessage("please choose an option");
alertThing.setPositiveButton("red", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
topLeft = true;
red = true;
invalidate();
}
});
alertThing.setNeutralButton("Chnange color to blue", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
alertThing.create();
alertThing.show();
}
Toast.makeText(context, "center is :" +x, Toast.LENGTH_SHORT ).show();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
//Sets a new starting point
pointStart.set(pointX,pointY);
return true;
case MotionEvent.ACTION_UP:
//Contects the points
pointEnd.set(pointX,pointY);
break;
default:
return false;
}
invalidate();
return true;
}
}
Here is the Drawings class that draws the bitmaps:
public class Drawings {
public Drawings(Bitmap bitmap, Canvas canvas,float x, float y){
canvas.drawBitmap(bitmap, x,y,null);
}
}
You really should see what canvas.drawBitmap does. Of course it changes the position, since the touch position changes too.
You create a new bitmap just like you did it when defining bitmap.
But creating new objects in the onDraw will be very slow.
Related
How can i implement freehand cropping on Imageview.
Using below code i'm able to draw freehand path and can able to crop image but i'm facing some other problems
Now what i have tried so far
Here is my code
code for cropping image using canvas
public class SomeView extends View implements View.OnTouchListener {
private Paint paint;
int DIST = 2;
boolean flgPathDraw = true;
Point mfirstpoint = null;
boolean bfirstpoint = false;
Point mlastpoint = null;
Bitmap bitmap;
Context mContext;
public SomeView(Context c, Bitmap bitmap) {
super(c);
mContext = c;
this.bitmap = bitmap;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
this.setOnTouchListener(this);
points = new ArrayList<Point>();
bfirstpoint = false;
}
public SomeView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
points = new ArrayList<Point>();
bfirstpoint = false;
this.setOnTouchListener(this);
}
public void onDraw(Canvas canvas) {
/*Rect dest = new Rect(0, 0, getWidth(), getHeight());
paint.setFilterBitmap(true);
canvas.drawBitmap(bitmap, null, dest, paint);*/
canvas.drawBitmap(bitmap, 0, 0, null);
Path path = new Path();
boolean first = true;
for (int i = 0; i < points.size(); i += 2) {
Point point = points.get(i);
if (first) {
first = false;
path.moveTo(point.x, point.y);
} else if (i < points.size() - 1) {
Point next = points.get(i + 1);
path.quadTo(point.x, point.y, next.x, next.y);
} else {
mlastpoint = points.get(i);
path.lineTo(point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
public boolean onTouch(View view, MotionEvent event) {
// if(event.getAction() != MotionEvent.ACTION_DOWN)
// return super.onTouchEvent(event);
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
if (flgPathDraw) {
if (bfirstpoint) {
if (comparepoint(mfirstpoint, point)) {
// points.add(point);
points.add(mfirstpoint);
flgPathDraw = false;
showcropdialog();
} else {
points.add(point);
}
} else {
points.add(point);
}
if (!(bfirstpoint)) {
mfirstpoint = point;
bfirstpoint = true;
}
}
invalidate();
Log.e("Hi ==>", "Size: " + point.x + " " + point.y);
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d("Action up*****~~>>>>", "called");
mlastpoint = point;
if (flgPathDraw) {
if (points.size() > 12) {
if (!comparepoint(mfirstpoint, mlastpoint)) {
flgPathDraw = false;
points.add(mfirstpoint);
showcropdialog();
}
}
}
}
return true;
}
private boolean comparepoint(Point first, Point current) {
int left_range_x = (int) (current.x - 3);
int left_range_y = (int) (current.y - 3);
int right_range_x = (int) (current.x + 3);
int right_range_y = (int) (current.y + 3);
if ((left_range_x < first.x && first.x < right_range_x)
&& (left_range_y < first.y && first.y < right_range_y)) {
if (points.size() < 10) {
return false;
} else {
return true;
}
} else {
return false;
}
}
public void fillinPartofPath() {
Point point = new Point();
point.x = points.get(0).x;
point.y = points.get(0).y;
points.add(point);
invalidate();
}
public void resetView() {
points.clear();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
points = new ArrayList<Point>();
bfirstpoint = false;
flgPathDraw = true;
invalidate();
}
private void showcropdialog() {
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent;
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
cropImage();
break;
case DialogInterface.BUTTON_NEGATIVE:
/*// No button clicked
intent = new Intent(mContext, DisplayCropActivity.class);
intent.putExtra("crop", false);
mContext.startActivity(intent);
bfirstpoint = false;*/
resetView();
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Do you Want to save Crop or Non-crop image?")
.setPositiveButton("Crop", dialogClickListener)
.setNegativeButton("Non-crop", dialogClickListener).show()
.setCancelable(false);
}
}
Code for cropping bitmap
public void cropImage() {
setContentView(R.layout.activity_picture_preview);
imageView = findViewById(R.id.image);
int widthOfscreen = 0;
int heightOfScreen = 0;
DisplayMetrics dm = new DisplayMetrics();
try {
getWindowManager().getDefaultDisplay().getMetrics(dm);
} catch (Exception ex) {
}
widthOfscreen = dm.widthPixels;
heightOfScreen = dm.heightPixels;
Bitmap bitmap2 = mBitmap;
Bitmap resultingImage = Bitmap.createBitmap(widthOfscreen,
heightOfScreen, bitmap2.getConfig());
Canvas canvas = new Canvas(resultingImage);
Paint paint = new Paint();
Path path = new Path();
for (int i = 0; i < points.size(); i++) {
path.lineTo(points.get(i).x, points.get(i).y);
}
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap2, 0, 0, paint);
imageView.setImageBitmap(resultingImage);
}
Here what i get result using above code
Cropping image using Finger touch
This image showing result after cropping image
This is my expected output
Please check below screenshot for the same
This Image showing cropping image using Finger touch
This image showing result after cropping image
The Below problems i'am facing in above code
Unable to set bitmap in full screen using canvas
If i set bitmap in full screen in canvas than image is stretching
How to set transparent background to cropped bitmap
Unable to add border to cropped image
The result of image Cropping is not as expected
Here are some other post that i have tried so far
crop free hand selected part of image
Freehand cropping on the image in android
Android Freehand bitmap cropping
Android: Free Cropping of Image
implemanting freehand crop in android
Get the free hand cropping Image From the original in android
Darken parts of a free-hand cropped image in android
Android-freehand-image-crop
Android Top Image Cropper Libraries
Crop a shape from an Android bitmap
Freehand Image Crop draw inside bitmap region
none of the above post help to achieve my excepted output
If need more information please do let me know. Thanks in advance. Your efforts will be appreciated.
In general, your code looks OK, but I have a few comments:
Unable to set bitmap in full screen using canvas
If i set bitmap in full screen in canvas than image is stretching
The portion of the image that you are selecting needs to be placed in a smaller bitmap so the layout XML can position it as you like. You are creating a bitmap that is full screen. See the following demo for details.
How to set transparent background to cropped bitmap
I am unclear about what the issue is.
Unable to add border to cropped image
The result of image Cropping is not as expected
See below.
Here is a small demo app using your code. You didn't provide an MCVE, so I threw the following together for demonstration purposes. Other than getting the app to function I think that the only change is to draw the border in MainActivity.java. The border width starts at the cut-out path that the user draws and reaches inward to the cut-out. If you want to actually frame the cutout without losing any pixels, then you will need to expand the path to accommodate the frame which I arbitrarily set to 20 pixels.
I also had to create the layouts used, so you may want to look at those. They are posted below.
Here is the demo video with the code to follow:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Bitmap mBitmap;
private SomeView mSomeView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dog);
mSomeView = new SomeView(this, mBitmap);
LinearLayout layout = findViewById(R.id.layout);
LinearLayout.LayoutParams lp =
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
layout.addView(mSomeView, lp);
}
public void cropImage() {
setContentView(R.layout.activity_picture_preview);
ImageView imageView = findViewById(R.id.image);
Bitmap fullScreenBitmap =
Bitmap.createBitmap(mSomeView.getWidth(), mSomeView.getHeight(), mBitmap.getConfig());
Canvas canvas = new Canvas(fullScreenBitmap);
Path path = new Path();
List<Point> points = mSomeView.getPoints();
for (int i = 0; i < points.size(); i++) {
path.lineTo(points.get(i).x, points.get(i).y);
}
// Cut out the selected portion of the image...
Paint paint = new Paint();
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(mBitmap, 0, 0, paint);
// Frame the cut out portion...
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
canvas.drawPath(path, paint);
// Create a bitmap with just the cropped area.
Region region = new Region();
Region clip = new Region(0, 0, fullScreenBitmap.getWidth(), fullScreenBitmap.getHeight());
region.setPath(path, clip);
Rect bounds = region.getBounds();
Bitmap croppedBitmap =
Bitmap.createBitmap(fullScreenBitmap, bounds.left, bounds.top,
bounds.width(), bounds.height());
imageView.setImageBitmap(croppedBitmap);
}
}
SomeView.java
I don't think there were any substantive changes to this class.
public class SomeView extends View implements View.OnTouchListener {
private Paint paint;
private List<Point> points;
int DIST = 2;
boolean flgPathDraw = true;
Point mfirstpoint = null;
boolean bfirstpoint = false;
Point mlastpoint = null;
Bitmap bitmap;
Context mContext;
public SomeView(Context c, Bitmap bitmap) {
super(c);
mContext = c;
this.bitmap = bitmap;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
this.setOnTouchListener(this);
points = new ArrayList<Point>();
bfirstpoint = false;
}
public SomeView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
points = new ArrayList<Point>();
bfirstpoint = false;
this.setOnTouchListener(this);
}
public void onDraw(Canvas canvas) {
/*Rect dest = new Rect(0, 0, getWidth(), getHeight());
paint.setFilterBitmap(true); canvas.drawBitmap(bitmap, null, dest, paint);*/
canvas.drawBitmap(bitmap, 0, 0, null);
Path path = new Path();
boolean first = true;
for (int i = 0; i < points.size(); i += 2) {
Point point = points.get(i);
if (first) {
first = false;
path.moveTo(point.x, point.y);
} else if (i < points.size() - 1) {
Point next = points.get(i + 1);
path.quadTo(point.x, point.y, next.x, next.y);
} else {
mlastpoint = points.get(i);
path.lineTo(point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
public boolean onTouch(View view, MotionEvent event) {
// if(event.getAction() != MotionEvent.ACTION_DOWN)
// return super.onTouchEvent(event);
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
if (flgPathDraw) {
if (bfirstpoint) {
if (comparepoint(mfirstpoint, point)) {
// points.add(point);
points.add(mfirstpoint);
flgPathDraw = false;
showcropdialog();
} else {
points.add(point);
}
} else {
points.add(point);
}
if (!(bfirstpoint)) {
mfirstpoint = point;
bfirstpoint = true;
}
}
invalidate();
Log.e("Hi ==>", "Size: " + point.x + " " + point.y);
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d("Action up*****~~>>>>", "called");
mlastpoint = point;
if (flgPathDraw) {
if (points.size() > 12) {
if (!comparepoint(mfirstpoint, mlastpoint)) {
flgPathDraw = false;
points.add(mfirstpoint);
showcropdialog();
}
}
}
}
return true;
}
private boolean comparepoint(Point first, Point current) {
int left_range_x = (int) (current.x - 3);
int left_range_y = (int) (current.y - 3);
int right_range_x = (int) (current.x + 3);
int right_range_y = (int) (current.y + 3);
if ((left_range_x < first.x && first.x < right_range_x)
&& (left_range_y < first.y && first.y < right_range_y)) {
if (points.size() < 10) {
return false;
} else {
return true;
}
} else {
return false;
}
}
public void fillinPartofPath() {
Point point = new Point();
point.x = points.get(0).x;
point.y = points.get(0).y;
points.add(point);
invalidate();
}
public void resetView() {
points.clear();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
points = new ArrayList<Point>();
bfirstpoint = false;
flgPathDraw = true;
invalidate();
}
private void showcropdialog() {
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent;
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
((MainActivity) mContext).cropImage();
break;
case DialogInterface.BUTTON_NEGATIVE:
/*// No button clicked
intent = new Intent(mContext, DisplayCropActivity.class); intent.putExtra("crop", false); mContext.startActivity(intent);
bfirstpoint = false;*/ resetView();
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Do you Want to save Crop or Non-crop image?")
.setPositiveButton("Crop", dialogClickListener)
.setNegativeButton("Non-crop", dialogClickListener).show()
.setCancelable(false);
}
public List<Point> getPoints() {
return points;
}
}
activity_main.xml
<LinearLayout
android:id="#+id/layout"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"/>
activity_picture_preview.xml
<android.support.constraint.ConstraintLayout x
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimary">
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="#drawable/dog" />
</android.support.constraint.ConstraintLayout>
If you want to create a cropped bitmap with a 100px border, use the following code in cropImage():
// Create a bitmap with just the cropped area.
Region region = new Region();
Region clip = new Region(0, 0, fullScreenBitmap.getWidth(), fullScreenBitmap.getHeight());
region.setPath(path, clip);
Rect sourceBounds = region.getBounds();
Rect destBounds =
new Rect(CROPPED_MARGIN, CROPPED_MARGIN, sourceBounds.width() + CROPPED_MARGIN,
sourceBounds.height() + CROPPED_MARGIN);
Bitmap croppedBitmap =
Bitmap.createBitmap(sourceBounds.width() + CROPPED_MARGIN * 2,
sourceBounds.height() + CROPPED_MARGIN * 2, mBitmap.getConfig());
canvas.setBitmap(croppedBitmap);
canvas.drawBitmap(fullScreenBitmap, sourceBounds, destBounds, null);
imageView.setImageBitmap(croppedBitmap);
// Add as member variable.
private static final int CROPPED_MARGIN = 100;
I have tried lots of solution for this problem in my project, but this code is working.
Here, i put my own project's Code Here. You can use it, if you found your solution in it.
public class CropView extends View implements View.OnTouchListener {
public static final String INTENT_KEY_CROP = "crop";
public static final String CACHE_KEY = "bitmap";
public static List<Point> points;
boolean flgPathDraw = true;
boolean bFirstPoint = false;
private Point firstPoint = null;
private Point lastPoint = null;
private final Bitmap originalImageBitmap;
private int canvasWidth;
private int canvasHeight;
private Paint paint;
private Context context;
private static LruCache<String, Bitmap> mMemoryCache;
private final ImageCropListener imageCropListener;
public interface ImageCropListener {
void onClickDialogPositiveButton();
void onClickDialogNegativeButton();
}
public static Bitmap getBitmapFromMemCache() {
return mMemoryCache.get(CACHE_KEY);
}
public CropView(Context c, Bitmap bm, ImageCropListener listener) {
super(c);
context = c;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setPathEffect(new DashPathEffect(new float[] { 10, 20 }, 0));
paint.setStrokeWidth(5);
paint.setColor(Color.WHITE);
this.setOnTouchListener(this);
points = new ArrayList<>();
bFirstPoint = false;
this.originalImageBitmap = bm;
this.imageCropListener = listener;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
#Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getByteCount() / 1024;
}
};
}
public CropView(Context context, AttributeSet attrs, Bitmap bm,
ImageCropListener listener) {
super(context, attrs);
this.context = context;
setFocusable(true);
setFocusableInTouchMode(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
this.setOnTouchListener(this);
points = new ArrayList<>();
bFirstPoint = false;
this.originalImageBitmap = bm;
this.imageCropListener = listener;
}
public void addBitmapToMemoryCache(Bitmap bitmap) {
if (getBitmapFromMemCache() == null) {
mMemoryCache.put(CACHE_KEY, bitmap);
}
}
private float calcBitmapScale(int canvasWidth, int canvasHeight, int bmpWidth, int bmpHeight) {
float scale = (float)canvasWidth / (float)bmpWidth;
float tmp = bmpHeight * scale;
if (tmp < canvasHeight) {
scale = (float)canvasHeight / (float)bmpHeight;
return scale;
}
return scale;
}
public void onDraw(Canvas canvas) {
canvasWidth = canvas.getWidth();
canvasHeight = canvas.getHeight();
/* int bmpWidth = this.originalImageBitmap.getWidth();
int bmpHeight = this.originalImageBitmap.getHeight();
float toCanvasScale = this.calcBitmapScale(canvasWidth, canvasHeight, bmpWidth, bmpHeight);
float diffX = (bmpWidth * toCanvasScale - canvasWidth);
float diffY = (bmpHeight * toCanvasScale - canvasHeight);
float addX = (diffX / toCanvasScale) / 2;
float addY = (diffY / toCanvasScale) / 2;
Rect rSrc = new Rect((int)addX, (int)addY,
(int)((canvasWidth / toCanvasScale) + addX), (int)((canvasHeight /
toCanvasScale) + addY));
RectF rDest = new RectF(0, 0, canvasWidth, canvasHeight);
*/
canvas.drawBitmap(originalImageBitmap, 0, 0, null);
Path cropAreaPath = new Path();
boolean isFirstPoint = true;
for (int i = 0; i < points.size(); i += 2) {
Point point = points.get(i);
if (isFirstPoint) {
isFirstPoint = false;
// 最初の処理でPathのx,y座標をpointの座標に移動する
cropAreaPath.moveTo(point.x, point.y);
} else if (i < points.size() - 1) {
Point next = points.get(i + 1);
cropAreaPath.quadTo(point.x, point.y, next.x, next.y);
} else {
lastPoint = points.get(i);
cropAreaPath.lineTo(point.x, point.y);
}
}
canvas.drawPath(cropAreaPath, paint);
}
public boolean onTouch(View view, MotionEvent event) {
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
if (flgPathDraw) {
if (bFirstPoint) {
if (comparePoint(firstPoint, point)) {
// points.add(point);
points.add(firstPoint);
flgPathDraw = false;
showCropDialog();
} else {
points.add(point);
}
} else {
points.add(point);
}
if (!(bFirstPoint)) {
firstPoint = point;
bFirstPoint = true;
}
}
invalidate();
//Log.e("Hi ==>", "Size: " + point.x + " " + point.y);
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d("Action up***>", "called");
lastPoint = point;
if (flgPathDraw) {
if (points.size() > 12) {
if (!comparePoint(firstPoint, lastPoint)) {
flgPathDraw = false;
points.add(firstPoint);
showCropDialog();
}
}
}
}
return true;
}
private boolean comparePoint(Point first, Point current) {
int left_range_x = (int) (current.x - 3);
int left_range_y = (int) (current.y - 3);
int right_range_x = (int) (current.x + 3);
int right_range_y = (int) (current.y + 3);
if ((left_range_x < first.x && first.x < right_range_x)
&& (left_range_y < first.y && first.y < right_range_y)) {
if (points.size() < 10) {
return false;
} else {
return true;
}
} else {
return false;
}
}
public void fillinPartofPath() {
Point point = new Point();
point.x = points.get(0).x;
point.y = points.get(0).y;
points.add(point);
invalidate();
}
public void resetView() {
points.clear();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
flgPathDraw = true;
invalidate();
}
private void showCropDialog() {
final Bitmap croppedImage = cropImage(this.originalImageBitmap);
DialogInterface.OnClickListener dialogClickListener = new
DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
addBitmapToMemoryCache(croppedImage);
imageCropListener.onClickDialogPositiveButton();
break;
case DialogInterface.BUTTON_NEGATIVE:
bFirstPoint = false;
resetView();
imageCropListener.onClickDialogNegativeButton();
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("Do you Want to save Crop or Non-crop image?")
.setPositiveButton("Crop", dialogClickListener)
.setNegativeButton("Cancel", dialogClickListener).show()
.setCancelable(false);
}
private Bitmap cropImage(Bitmap image) {
Bitmap cropImage = Bitmap.createBitmap(canvasWidth, canvasHeight,
image.getConfig());
Canvas canvas = new Canvas(cropImage);
Paint paint = new Paint();
paint.setAntiAlias(true);
Path path = new Path();
for (int i = 0; i < CropView.points.size(); i++) {
path.lineTo(CropView.points.get(i).x, CropView.points.get(i).y);
}
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(originalImageBitmap, 0, 0, paint);
return cropImage;
}
class Point {
public float dy;
public float dx;
float x, y;
#Override
public String toString(){
return x + ", " + y;
}
}
}
Then You can get Crop Result..as like,
Bitmap cropBitmap = CropView.getBitmapFromMemCache();
cropBitmap = getBitmapWithTransparentBG(cropBitmap,Color.WHITE);
Drawable d = new BitmapDrawable(getResources(),cropBitmap);
public Bitmap getBitmapWithTransparentBG(Bitmap srcBitmap, int bgColor) {
Bitmap result = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
int nWidth = result.getWidth();
int nHeight = result.getHeight();
for (int y = 0; y < nHeight; ++y)
for (int x = 0; x < nWidth; ++x) {
int nPixelColor = result.getPixel(x, y);
if (nPixelColor == bgColor)
result.setPixel(x, y, Color.TRANSPARENT);
}
return result;
}
I Think, This code will be perfect for your problem solution.. Thanks
Inside my gameplay screen I want to create a Pause Screen Menu which I can select the Retry button or Back to main screen if I click the pause button.I already draw the pause button inside my class.My problem is how can I draw the pause menu screen?
Here is my code
//pause
pause = new Texture("pause.png");
myTextureRegion = new TextureRegion(pause);
myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion);
pause_btnDialog = new ImageButton(myTexRegionDrawable); //Set the button up
pause_btnDialog.setPosition(580,1150);
stage.addActor(pause_btnDialog); //Add the button to the stage to perform rendering and take input.
Gdx.input.setInputProcessor(stage);
pause_btnDialog.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
System.out.println("Pause Button Pressed");
//Show Pause Screen menu
//game.setScreen(new PauseGameday1(game));
}
});
stage.addActor(pause_btnDialog);
GameScreen
public class IngamedayOne implements Screen ,InputProcessor {
final MyGdxGame game;
// Constant rows and columns of the sprite sheet
private static final int FRAME_COLS = 5, FRAME_ROWS = 1;
private boolean peripheralAvailable;
private static final float ACCELERATION = 20f;
// Objects used
Animation<TextureRegion> walkAnimation; // Must declare frame type (TextureRegion)
Texture cat ,left_paw,right_paw,progressbar_background,progressbar_knob,pause,meter;
Texture carpet,desk,plants,square_carpet,shoes;
SpriteBatch spriteBatch;
Sprite sprite;
private Texture Background;
ImageButton left_paw_btn,right_paw_btn,pause_btnDialog;
Viewport viewport;
private Stage stage;
// A variable for tracking elapsed time for the animation
float stateTime;
private TextureRegion myTextureRegion;
private TextureRegionDrawable myTexRegionDrawable;
private boolean isPause;
private Group pauseGroup;
//Screen Size
OrthographicCamera camera;
float catSpeed = 50.0f; // 10 pixels per second.
float catX;
float catY;
public boolean paused = false;
public IngamedayOne(final MyGdxGame game) {
this.game = game;
Gdx.input.setCatchBackKey(true);
Gdx.graphics.setContinuousRendering(false);
Gdx.graphics.requestRendering();
stage = new Stage(new StretchViewport( 720, 1280));
camera = new OrthographicCamera();
camera.setToOrtho(false, 720, 1280);
camera.translate( 1280/2, 720/2 );
Gdx.input.setInputProcessor(stage);
spriteBatch = new SpriteBatch();
viewport = new StretchViewport(720, 1280);
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// Load the sprite sheet as a texture
cat = new Texture(Gdx.files.internal("cat.png"));
sprite = new Sprite(cat);
catX=300;
catY=0;
Gdx.input.setInputProcessor( this);
peripheralAvailable = Gdx.input.isPeripheralAvailable(Input.Peripheral.Accelerometer);
int orientation = Gdx.input.getRotation();
Input.Orientation nativeOrientation = Gdx.input.getNativeOrientation();
viewport = new StretchViewport(720, 1280);
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// Progressbar
progressbar_background = new Texture("progression_map.png");
progressbar_knob = new Texture("cat_head.png");
//pause
pause = new Texture("pause.png");
myTextureRegion = new TextureRegion(pause);
myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion);
pause_btnDialog = new ImageButton(myTexRegionDrawable); //Set the button up
pause_btnDialog.setPosition(580,1150);
stage.addActor(pause_btnDialog); //Add the button to the stage to perform rendering and take input.
Gdx.input.setInputProcessor(stage);
pause_btnDialog.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
System.out.println("Pause Button Pressed");
//Show Pause Screen menu
game.setScreen(new PauseGameday1(game));
pause();
}
});
stage.addActor(pause_btnDialog);
meter = new Texture("meter.png");
//background
Background = new Texture(Gdx.files.internal("floor.png")); //File from assets folder
// Use the split utility method to create a 2D array of TextureRegions. This is
// possible because this sprite sheet contains frames of equal size and they are
// all aligned.
TextureRegion[][] tmp = TextureRegion.split(cat, cat.getWidth() / FRAME_COLS, cat.getHeight()/ FRAME_ROWS);
// Place the regions into a 1D array in the correct order, starting from the top
// left, going across first. The Animation constructor requires a 1D array.
TextureRegion[] walkFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < FRAME_COLS; j++) {
walkFrames[index++] = tmp[i][j];
}
}
// Initialize the Animation with the frame interval and array of frames
walkAnimation = new Animation<TextureRegion>(0.200f, walkFrames);
// Instantiate a SpriteBatch for drawing and reset the elapsed animation
// time to 0
spriteBatch = new SpriteBatch();
stateTime = 0f;
//left_control
left_paw = new Texture(Gdx.files.internal("left_paw.png"));
myTextureRegion = new TextureRegion(left_paw);
myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion);
left_paw_btn = new ImageButton(myTexRegionDrawable); //Set the button up
left_paw_btn.setPosition(10,25);
stage.addActor(left_paw_btn); //Add the button to the stage to perform rendering and take input.
Gdx.input.setInputProcessor(stage);
left_paw_btn.addListener(new InputListener(){
#Override
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("Left Button Pressed");
//Start Animation
}
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
return true;
}
});
stage.addActor(left_paw_btn);
//right_control
right_paw = new Texture(Gdx.files.internal("right_paw.png"));
myTextureRegion = new TextureRegion(right_paw);
myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion);
right_paw_btn = new ImageButton(myTexRegionDrawable); //Set the button up
right_paw_btn.setPosition(517,25);
stage.addActor(right_paw_btn); //Add the button to the stage to perform rendering and take input.
Gdx.input.setInputProcessor(stage);
right_paw_btn.addListener(new InputListener(){
#Override
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("Right Button Pressed");
//Start Animation
stateTime += Gdx.graphics.getDeltaTime(); // Accumulate elapsed animation time
camera.update();
}
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
return true;
}
});
stage.addActor(right_paw_btn);
}
public enum State
{
PAUSE,
RUN,
RESUME,
STOPPED
}
private State state = State.RUN;
#Override
public void show() {
}
#Override
public void render(float delta) {
// clear previous frame
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Clear screen
stateTime += Gdx.graphics.getDeltaTime(); // Accumulate elapsed animation time
camera.update();
spriteBatch.begin();
TextureRegion currentFrame = walkAnimation.getKeyFrame(stateTime, true);
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.draw(Background,0,0);
spriteBatch.draw(currentFrame,catX,catY); // Draw current frame at (50, 50)
spriteBatch.draw(meter,190,990);
spriteBatch.draw(progressbar_background,20,1170);
spriteBatch.draw(progressbar_knob,18,1170);
//Moving player on desktop
if(Gdx.input.isKeyPressed(Input.Keys.LEFT))
catX -= Gdx.graphics.getDeltaTime() * catSpeed;
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT))
catX += Gdx.graphics.getDeltaTime() * catSpeed;
if(Gdx.input.isKeyPressed(Input.Keys.UP))
catY += Gdx.graphics.getDeltaTime() * catSpeed;
if(Gdx.input.isKeyPressed(Input.Keys.DOWN))
catY -= Gdx.graphics.getDeltaTime() * catSpeed;
//Mobile acceleration
if (Gdx.input.isPeripheralAvailable(Input.Peripheral.Accelerometer))
{
catX -= Gdx.input.getAccelerometerX();
catY += Gdx.input.getAccelerometerY();
}
if(catY<0) {
catY =0;
}
if(catY> Gdx.graphics.getWidth()-100) {
catY =Gdx.graphics.getWidth()-100;
}
if(catX<0){
catX =0;
}
if(catX> Gdx.graphics.getHeight()-250) {
catX =Gdx.graphics.getHeight()-250;
}
switch (state)
{
case RUN:
//do suff here
break;
case PAUSE:
break;
case RESUME:
break;
default:
break;
}
spriteBatch.end();
stage.act(); //acting a stage to calculate positions of actors etc
stage.draw(); //drawing it to render all
}
#Override
public void resize(int width, int height) {
viewport.update(width, height);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
}
#Override
public void pause() {
this.state = State.PAUSE;
}
#Override
public void resume() {
this.state = State.RESUME;
}
#Override
public boolean keyDown(int keycode) {
return true;
}
#Override
public boolean keyUp(int keycode) {
return false;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
#Override
public void hide() {
}
#Override
public void dispose() { // SpriteBatches and Textures must always be disposed
spriteBatch.dispose();
cat.dispose();
left_paw.dispose();
right_paw.dispose();
stage.dispose();
Background.dispose();
progressbar_background.dispose();
progressbar_knob.dispose();
}
}
Pause Menu
public class PauseGameday1 implements Screen {
final MyGdxGame game;
private Texture Background,pauseImg;
private Stage stage;
SpriteBatch spriteBatch;
OrthographicCamera camera;
private static final int WIDTH= 720;
private static final int HEIGHT= 1280;
private TextureRegion myTextureRegion;
private TextureRegionDrawable myTexRegionDrawable;
Viewport viewport;
public PauseGameday1( MyGdxGame game) {
this.game = game;
stage = new Stage(new StretchViewport( 720, 1280));
camera = new OrthographicCamera();
camera.setToOrtho(false, 720, 1280);
camera.translate( 1280/2, 720/2 );
Gdx.input.setInputProcessor(stage);
spriteBatch = new SpriteBatch();
viewport = new StretchViewport(720, 1280);
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Background = new Texture(Gdx.files.internal("backgroundimage.png")); //background image
pauseImg = new Texture(Gdx.files.internal("pausemenu/pause_text.png"));
}
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Clear screen
camera.update();
spriteBatch.begin();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.draw(Background,0,0);
spriteBatch.draw(pauseImg,230,900);
stage.act(Gdx.graphics.getDeltaTime()); //Perform ui logic
spriteBatch.end();
stage.getViewport().apply();
stage.draw(); //Draw the ui
}
#Override
public void resize(int width, int height) {
viewport.update(width, height);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
}
Can anyone correct my codes?
You only declared pauseGroup but never used in your game, Call pause() method from pause_button. It will create pauseGroup for you and add to your Stage. In pause() method, create Actor(UI) and add to pauseGroup. You can't use multiple screen at a time with your Game class because Game having reference of single Screen.
pause_btnDialog.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
pause();
}
});
#Override
public void render(float delta) {
// clear previous frame
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Clear screen
camera.update();
spriteBatch.begin();
spriteBatch.setProjectionMatrix(camera.combined);
if(this.state==State.RESUME)
stateTime += Gdx.graphics.getDeltaTime(); // Accumulate elapsed animation time
TextureRegion currentFrame = walkAnimation.getKeyFrame(stateTime, true);
spriteBatch.draw(Background,0,0);
spriteBatch.draw(currentFrame,catX,catY); // Draw current frame at (50, 50)
spriteBatch.draw(meter,190,990);
spriteBatch.draw(progressbar_background,20,1170);
spriteBatch.draw(progressbar_knob,18,1170);
if(this.state==State.RESUME){
//Moving player on desktop
if(Gdx.input.isKeyPressed(Input.Keys.LEFT))
catX -= Gdx.graphics.getDeltaTime() * catSpeed;
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT))
catX += Gdx.graphics.getDeltaTime() * catSpeed;
if(Gdx.input.isKeyPressed(Input.Keys.UP))
catY += Gdx.graphics.getDeltaTime() * catSpeed;
if(Gdx.input.isKeyPressed(Input.Keys.DOWN))
catY -= Gdx.graphics.getDeltaTime() * catSpeed;
//Mobile acceleration
if (Gdx.input.isPeripheralAvailable(Input.Peripheral.Accelerometer))
{
catX -= Gdx.input.getAccelerometerX();
catY += Gdx.input.getAccelerometerY();
}
if(catY<0) {
catY =0;
}
if(catY> Gdx.graphics.getWidth()-100) {
catY =Gdx.graphics.getWidth()-100;
}
if(catX<0){
catX =0;
}
if(catX> Gdx.graphics.getHeight()-250) {
catX =Gdx.graphics.getHeight()-250;
}
}
switch (state)
{
case RUN:
//do suff here
break;
case PAUSE:
break;
case RESUME:
break;
default:
break;
}
spriteBatch.end();
stage.act(); //acting a stage to calculate positions of actors etc
stage.draw(); //drawing it to render all
}
public void pause(){
this.state = State.PAUSE;
pauseGroup = new Group;
Image semiTransparentBG= ......
// setSize(Size of screen) and make it semi transparent.
pauseGroup.addActor(semiTransparentBG);
//crate all other pause UI buttons with listener and add to pauseGroup
stage.addActor(pauseGroup);
}
public void resume() {
if(this.state = State.PAUSE){
this.state = State.RESUME;
pauseGroup.remove();
}
}
'I want to remove contents of the image that has been drawn on canvas like finger eraser but drawCircle is not removing.Here my code
'
public class PaintView extends View {
Canvas c1;
Paint mPaintt;
Bitmap mBitmap;
Matrix mMatrix;
RectF mSrcRectF;
RectF mDestRectF;
boolean mPause;
Bitmap bit;
Path path;
int X = -100;
int Y = -100;
Paint mPaint;
Bitmap mBitmaps;
public PaintView(Context context, AttributeSet attributeSet){
super(context,attributeSet);
mPaintt=new Paint();
mMatrix = new Matrix();
mSrcRectF = new RectF();
mDestRectF = new RectF();
mPause = false;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaint.setAntiAlias(true);
mPaint.setColor(Color.TRANSPARENT);
mPaint.setMaskFilter(new BlurMaskFilter(15, BlurMaskFilter.Blur.NORMAL));
}
public void addBitmap(Bitmap bitmap){
mBitmap = bitmap;
}
public Bitmap getBitmap(){
return mBitmap;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
X = (int) ev.getX();
Y = (int) ev.getY();
invalidate();
break;
}
case MotionEvent.ACTION_MOVE: {
X = (int) ev.getX();
Y = (int) ev.getY();
invalidate();
break;
}
case MotionEvent.ACTION_UP:
break;
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(!mPause){
if(mBitmap!=null){
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
//mPaint.setColor(Color.TRANSPARENT);
// Setting size of Source Rect
mSrcRectF.set(0, 0,mBitmap.getWidth(),mBitmap.getHeight());
// Setting size of Destination Rect
mDestRectF.set(0, 0, getWidth(), getHeight());
// Scaling the bitmap to fit the PaintView
mMatrix.setRectToRect( mSrcRectF , mDestRectF, Matrix.ScaleToFit.CENTER);
canvas.drawBitmap(mBitmap, mMatrix,mPaintt);
canvas.drawCircle(X,Y,30,mPaint);
}
}
// Redraw the canvas
invalidate();
}
// Pause or resume onDraw method
public void pause(boolean pause){
mPause = pause;
}
}
How to take first touch coordinates and make it constant.
I wanna click something on screen then draw a permanent on first touch and then want to move another circle within the the permanent circle one
hers the code am trying :
public class MainActivity extends Activity implements OnTouchListener {
private float x;
private float y;
static float lasttouchx;
static float lasttouchy;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyCustomPanel view = new MyCustomPanel(this);
ViewGroup.LayoutParams params =
new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
addContentView(view, params);
view.setOnTouchListener(this);
}
private class MyCustomPanel extends View {
public MyCustomPanel(Context context) {
super(context);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(5);
paint.setTextSize(50);
canvas.drawText(" X : " + (int) x + " Y : " + (int) y, canvas.getWidth() - 500, 200, paint);
paint.setStyle(Paint.Style.FILL);
if((x<=1000&& x>=18)&&(y<=1380&&y>=348)){
paint.setColor(Color.BLUE);
canvas.drawCircle(x, y, 100, paint);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(20);
canvas.drawCircle(lasttouchx, lasttouchy, 500, paint);
}
else{}
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
x = event.getX();
y = event.getY();
int action = event.getActionMasked();
switch (action){
case MotionEvent.ACTION_DOWN:
lasttouchx = event.getX();
lasttouchy = event.getY();
return false;
}
v.invalidate();
return true;
}
}
Override onTouchEvent(MotionEvent event) and then call event.getX() and event.getY() to get the coordinate positions of where the user touched.
then store value to some variable.
now use these values you want and try replacing to another.
Check stack answer to get touch screen information answer
I am trying to remove my last path drawn on my canvas. I have tryed so far to add my paths in a ArrayList but I didn't find any method to remove the path easilly from canvas.
public class PaintView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
private static final int TOUCH_TOLERANCE_DP = 20;
private static final int BACKGROUND = Color.TRANSPARENT;
private List<Point> mPoints = new ArrayList<Point>();
private int mLastPointIndex = 0;
private int mTouchTolerance;
private boolean isPathStarted = false;
private boolean canCreatePoints = true;
private Polygon poly;
private Builder build;
private ArrayList<Polygon> polyList;
private ArrayList<Path> undoPath, redoPath;
public PaintView(Context context) {
super(context);
mCanvas = new Canvas();
mPath = new Path();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
mTouchTolerance = dp2px(TOUCH_TOLERANCE_DP);
polyList = new ArrayList<Polygon>();
undoPath = new ArrayList<Path>();
redoPath = new ArrayList<Path>();
}
#Override
protected void onSizeChanged(int width, int height, int oldWidth,
int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
clear();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(BACKGROUND);
canvas.drawBitmap(mBitmap, 0, 0, null);
canvas.drawPath(mPath, mPaint);
for(Path p : undoPath) {
canvas.drawPath(p, mPaint);
}
for (Point point : mPoints) {
canvas.drawPoint(point.x, point.y, mPaint);
}
}
Below is onTouch method, I create lines using Path when variable canCreatePoints it's true.If canCreatePoints it's false I check in a ArrayList<Polygon> if my touch point is inside a polygon.
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(canCreatePoints == true)
{
create_point(x,y);
if( mPoints.size() > 1 )
{
// start point
Point p = mPoints.get(mLastPointIndex);
mPath.moveTo(p.x, p.y);
// end point
p = mPoints.get(mLastPointIndex + 1);
mPath.lineTo(p.x, p.y);
mCanvas.drawPath(mPath, mPaint);
undoPath.add(mPath);
mPath.reset();
// increment point index
++mLastPointIndex;
}
}
if(canCreatePoints == false)
{
Points pp = new Points(Math.round(x), Math.round(y));
boolean contains;
for(Polygon tempPoly:polyList){
contains = tempPoly.contains(pp);
if(contains == true)
{
Log.i("TEST","Poligonul contine punctul");
Toast.makeText(getContext(),"Test poly "+polyList.indexOf(tempPoly),
Toast.LENGTH_SHORT).show();
}
}
}
invalidate();
break;
}
return true;
}
private void create_point(float x, float y){
Point p = new Point(Math.round(x),Math.round(y));
mPoints.add(p);
}
Bellow I finnish my polygon form by action of a Button. I create a path from last point to first point and draw it on canvas.
public void finnishDraw(){
if( mPoints.size() > 1 )
{
// start point
Point p = mPoints.get(0);
mPath.moveTo(p.x, p.y);
// end point
p = mPoints.get( mPoints.size() - 1);
mPath.lineTo(p.x, p.y);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
invalidate();
int x[] = new int[mPoints.size()];
int y[] = new int[mPoints.size()];
build = new Builder();
for(int i=0 ; i<mPoints.size() ; i++)
{
p = mPoints.get(i);
x[i] = p.x;
y[i] = p.y;
build.addVertex(new Points(x[i],y[i]));
Log.i("TEST","Adaug la builder punctele "+x[i]+" si "+y[i]);
}
poly = build.build();
polyList.add(poly);
mPoints.clear();
mLastPointIndex = 0;
}
}
So far I found only a solution with a back-up Bitmap before drawing a line but I didn't understand how it really works.
You can't undo a drawPath on a Canvas. From the documentation:
Via the Canvas, your drawing is actually performed upon an underlying
Bitmap, which is placed into the window.
As you say, you need a backup Bitmap to save the state of the current Bitmap before drawing on it, for example using a Memento pattern.
Take a look at Fast undo/redo for bitmap editor when memory is limited? and Fast undo facility for bitmap editor application (the last one targetting iPhone, but the underlying idea is the same)
Another approach less memory consuming could be saving the state of the objects that you want to draw on your canvas and draw them on demand (when you need to show a partial or a full result).
To remove the last path only apply this function:
public void clearLast(){
if(!paths.isEmpty()) {
backgroundColor = DEFAULT_BG_COLOR;
int size = paths.size();
paths.remove(paths.get(size-1));
normal();
invalidate();
}
}