FaceView.java
package com.example.richelle.neeuro;
public class FaceView extends View {
private float radius;
NormalFace normalFace;
HappyFace happyFace;
public FaceView(Context context, AttributeSet attrs) {
super(context, attrs);
// get radius value
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.FaceView,
0, 0
);
try {
radius = a.getDimension(R.styleable.FaceView_radius, 20.0f);
} finally {
a.recycle();
}
// initiate HappyFace class
normalFace = new NormalFace(radius);
happyFace = new HappyFace(radius);
}
Handler setDelay;
Runnable startDelay;
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
normalFace.draw(canvas);
//delay timer
setDelay = new Handler();
startDelay = new Runnable() {
#Override
public void run() {
happyFace.draw(canvas);
}
};
setDelay.postDelayed(startDelay,5000);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int desiredWidth = (int) radius*2+(int) Math.ceil((radius/1.70));
int desiredHeight = (int) radius*2+(int)Math.ceil((radius/1.70));
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
Log.d("Width AT_MOST", "width: "+width);
} else {
//Be whatever you want
width = desiredWidth;
Log.d("Width ELSE", "width: "+width);
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
}
NormalFace.java
public class NormalFace {
//Paint object
Paint facePaint;
Paint mePaint;
float radius;
float adjust;
float mouthLeftX, mouthRightX, mouthTopY, mouthBottomY;
RectF mouthRectF;
Path mouthPath;
float eyeLeftX, eyeRightx, eyeTopY, eyeBottomY;
RectF eyeLeftRectF, eyeRightRectF;
public NormalFace(float radius){
this.radius= radius;
facePaint = new Paint();
facePaint.setColor(0xfffed325); // face color - yellow
facePaint.setDither(true);
facePaint.setStrokeJoin(Paint.Join.ROUND);
facePaint.setStrokeCap(Paint.Cap.ROUND);
facePaint.setPathEffect(new CornerPathEffect(10) );
facePaint.setAntiAlias(true);
facePaint.setShadowLayer(4, 2, 2, 0x80000000);
mePaint = new Paint();
mePaint.setColor(0xff2a2a2a); //black
mePaint.setDither(true);
mePaint.setStyle(Paint.Style.STROKE);
mePaint.setStrokeJoin(Paint.Join.ROUND);
mePaint.setStrokeCap(Paint.Cap.ROUND);
mePaint.setPathEffect(new CornerPathEffect(10) );
mePaint.setAntiAlias(true);
mePaint.setStrokeWidth(radius / 14.0f);
adjust = radius / 3.2f;
// Left Eye
eyeLeftX = radius-(radius*0.43f);
eyeRightx = eyeLeftX + (radius*0.3f);
eyeTopY = radius-(radius*0.5f);
eyeBottomY = eyeTopY + (radius*0.4f);
eyeLeftRectF = new RectF(eyeLeftX+adjust,eyeTopY+adjust,eyeRightx+adjust,eyeBottomY+adjust);
// Right Eye
eyeLeftX = eyeRightx + (radius*0.3f);
eyeRightx = eyeLeftX + (radius*0.3f);
eyeRightRectF = new RectF(eyeLeftX+adjust,eyeTopY+adjust,eyeRightx+adjust,eyeBottomY+adjust);
// Mouth
mouthLeftX = radius-(radius/2.0f);
mouthRightX = mouthLeftX+ radius;
// mouthTopY = 125 - (125*0.01f);
// mouthBottomY = mouthTopY + (125*0.01f);
mouthTopY = radius - (radius*(-0.2f));
mouthBottomY = mouthTopY + (radius*0.01f);
mouthRectF = new RectF(mouthLeftX+adjust,mouthTopY+adjust,mouthRightX+adjust,mouthBottomY+adjust);
//mouthRectF = new RectF(mouthLeftX+adjust,mouthTopY+70,mouthRightX+adjust,mouthBottomY+20); //a line
mouthPath = new Path();
mouthPath.arcTo(mouthRectF, 30, 120, true);
// mouthPath.arcTo(mouthRectF, 15, 135, true);
}
public void draw(Canvas canvas) {
// 1. draw face
canvas.drawCircle(radius+adjust, radius+adjust, radius, facePaint);
// 2. draw mouth
mePaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mouthPath, mePaint);
//canvas.drawLine(90, 155, 176, 155, mePaint);
// 3. draw eyes
mePaint.setStyle(Paint.Style.FILL);
canvas.drawArc(eyeLeftRectF, 0, 360, true, mePaint);
canvas.drawArc(eyeRightRectF, 0, 360, true, mePaint);
}
}
HappyFace.java
public class HappyFace {
//Paint object
Paint facePaint;
Paint mePaint;
float radius;
float adjust;
float mouthLeftX, mouthRightX, mouthTopY, mouthBottomY;
RectF mouthRectF;
Path mouthPath;
float eyeLeftX, eyeRightx, eyeTopY, eyeBottomY;
RectF eyeLeftRectF, eyeRightRectF;
public HappyFace(float radius){
this.radius= radius;
facePaint = new Paint();
facePaint.setColor(0xfffed325); // face color - yellow
facePaint.setDither(true);
facePaint.setStrokeJoin(Paint.Join.ROUND);
facePaint.setStrokeCap(Paint.Cap.ROUND);
facePaint.setPathEffect(new CornerPathEffect(10) );
facePaint.setAntiAlias(true);
facePaint.setShadowLayer(4, 2, 2, 0x80000000);
mePaint = new Paint();
mePaint.setColor(0xff2a2a2a); //black
mePaint.setDither(true);
mePaint.setStyle(Paint.Style.STROKE);
mePaint.setStrokeJoin(Paint.Join.ROUND);
mePaint.setStrokeCap(Paint.Cap.ROUND);
mePaint.setPathEffect(new CornerPathEffect(10) );
mePaint.setAntiAlias(true);
mePaint.setStrokeWidth(radius / 14.0f);
adjust = radius / 3.2f;
// Left Eye
eyeLeftX = radius-(radius*0.43f);
eyeRightx = eyeLeftX + (radius*0.3f);
eyeTopY = radius-(radius*0.5f);
eyeBottomY = eyeTopY + (radius*0.4f);
eyeLeftRectF = new RectF(eyeLeftX+adjust,eyeTopY+adjust,eyeRightx+adjust,eyeBottomY+adjust);
// Right Eye
eyeLeftX = eyeRightx + (radius*0.3f);
eyeRightx = eyeLeftX + (radius*0.3f);
eyeRightRectF = new RectF(eyeLeftX+adjust,eyeTopY+adjust,eyeRightx+adjust,eyeBottomY+adjust);
// Smiley Mouth
mouthLeftX = radius-(radius/2.0f);
mouthRightX = mouthLeftX+ radius;
mouthTopY = radius - (radius*0.2f);
mouthBottomY = mouthTopY + (radius*0.5f);
mouthRectF = new RectF(mouthLeftX+adjust,mouthTopY+adjust,mouthRightX+adjust,mouthBottomY+adjust);
mouthPath = new Path();
mouthPath.arcTo(mouthRectF, 30, 120, true);
}
public void draw(Canvas canvas) {
// 1. draw face
canvas.drawCircle(radius+adjust, radius+adjust, radius, facePaint);
// 2. draw mouth
mePaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mouthPath, mePaint);
// 3. draw eyes
mePaint.setStyle(Paint.Style.FILL);
canvas.drawArc(eyeLeftRectF, 0, 360, true, mePaint);
canvas.drawArc(eyeRightRectF, 0, 360, true, mePaint);
}
}
FaceView.java is to display the different facial expressions in the canvas. The NormalFace.java and HappyFace.java are the UI of the different facial expressions. I want to add a delay timer in FaceView.java so that the display of the normal face can be change to a happy face after the timer had finished counting down.
Use this: ms is delay in millisecond
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
You can use Handler class for this in android.Handler has a method postDelayed(),you can use this method for the delay,read about handler from here
Runnable happy = new Runnable() {
public void run() {
happyFace(); //suppose this is the method for happy face
}
};
and then call this method like this after 5 sec
handler.postDelayed(happy,5000);
It will post your code to be run after 5 sec
You can use Handler to delay your next task
import android.os.Handler;
Handler handler=new Handler();
Runnable r=new Runnable() {
public void run() {
// Your next task
}
};
handler.postDelayed(r, 30000);
30000 is the value of delay in milli seconds which makes it 30 secs
Related
I have a camera that feeds its data into a AutoFitTextureview (across whole screen) that should focus the camera depending on where the user has touched the texture view. The resolutions of the camera and textureview are different. How do I transform the touch rectangle into a MeteringRectangle. Tried the following code but it didn't work
private View.OnTouchListener mOnTouchListener =new View.OnTouchListener() {
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouch(View view, MotionEvent event) {
final int actionMasked = event.getActionMasked();
if (actionMasked != MotionEvent.ACTION_DOWN) {
return false;
}
Timber.d("Triggered mOnTouchListener");
final Rect sensorArraySize = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
Timber.d("Triggered mOnTouchListener");
RectF touchRect = new RectF((event.getX() - 100),(event.getY() - 100), (event.getX() + 100), (event.getY() + 100));
Matrix matrix=new Matrix();
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
matrix.setRectToRect(touchRect, bufferRect, Matrix.ScaleToFit.FILL);
//This doesnt work final int y = (int)((event.getX() / (float)view.getWidth()) * (float)sensorArraySize.height());
// final int x = (int)((event.getY() / (float)view.getHeight()) * (float)sensorArraySize.width());
// final int halfTouchWidth = 150;
// final int halfTouchHeight = 150;
// MeteringRectangle focusArea = new MeteringRectangle(Math.max(x - halfTouchWidth, 0),
// Math.max(y - halfTouchHeight, 0),
// halfTouchWidth * 2,
// halfTouchHeight * 2,
// MeteringRectangle.METERING_WEIGHT_MAX - 1);
MeteringRectangle focusArea = new MeteringRectangle(rectFToRect(bufferRect), MeteringRectangle.METERING_WEIGHT_MAX - 1);
cameraFocusIndicator.setHaveTouch(true, new Rect((int) (event.getX() - 100),(int) (event.getY() - 100), (int) (event.getX() + 100),(int) (event.getY() + 100)));
cameraFocusIndicator.invalidate();
Timber.d("Triggered setFocusMode");
focusAreaTouch = focusArea;
setFocusMode();
return true;
}
};
Code for setFocusMode
private void setFocusMode() {
try {
Timber.d("setFocusMode number of CONTROL_MAX_REGIONS_AF %s", mCameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF));
if(mCameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)==0)
return;
Timber.d("setFocusMode");
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
Timber.d("setFocusMode"+focusAreaTouch);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusAreaTouch});
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
Timber.e(e,"setFocusMode");
}
}
public class MovingBagView extends View {
private Bitmap bag[] = new Bitmap[2];
private int bagX;
private int bagY = 1000;
private int bagSpeed;
private Boolean touch = false;
private int canvasWidth, canvasHeight;
private int yellowX = 500, yellowY, yellowSpeed = -16;
private Paint yellowPaint = new Paint();
private int score;
private Bitmap backgroundImage;
private Paint scorePaint = new Paint();
private Bitmap life[] = new Bitmap[2];
public MovingBagView(Context context) {
super(context);
bag[0] = BitmapFactory.decodeResource(getResources(), R.drawable.bag1);
bag[1] = BitmapFactory.decodeResource(getResources(), R.drawable.bag2);
backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.background);
yellowPaint.setColor(Color.YELLOW);
yellowPaint.setAntiAlias(false);
scorePaint.setColor(Color.BLACK);
scorePaint.setTextSize(40);
scorePaint.setTypeface(Typeface.DEFAULT_BOLD);
scorePaint.setAntiAlias(true);
life[0] = BitmapFactory.decodeResource(getResources(), R.drawable.heart);
life[1] = BitmapFactory.decodeResource(getResources(), R.drawable.heart_grey);
bagX = 10;
score = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvasWidth = canvas.getWidth();
canvasHeight = canvas.getHeight();
canvas.drawBitmap(backgroundImage, 0, 0, null);
int minBagX = bag[0].getWidth();
int maxBagX = canvasWidth - bag[0].getWidth() * 2;
bagX = bagX + bagSpeed;
if (bagX < minBagX) {
bagX = minBagX;
}
if (bagX >= maxBagX) {
bagX = maxBagX;
}
bagSpeed = bagSpeed + 2;
if (touch) {
canvas.drawBitmap(bag[1], bagX, bagY, null);
}
else {
canvas.drawBitmap(bag[0], bagX, bagY, null);
}
yellowY = yellowY - yellowSpeed;
if (hitBallChecker(yellowX, yellowY)) {
score = score + 10;
yellowY = -100;
}
if (yellowY < 0) {
yellowY = canvasHeight + 21;
yellowX = (int)Math.floor(Math.random() * (maxBagX - minBagX)) + maxBagX;
}
canvas.drawCircle(yellowX, yellowY, 15, yellowPaint);
canvas.drawText("Score : " + score, 20, 60, scorePaint);
canvas.drawBitmap(life[0], 500, 10, null);
canvas.drawBitmap(life[0], 570, 10, null);
canvas.drawBitmap(life[0], 640, 10, null);
}
public boolean hitBallChecker(int x, int y) {
if (bagY < y && y < (bagY + bag[0].getHeight()) && bagX < x && x < (bagX + bag[0].getWidth())) {
return true;
}
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
touch = true;
bagSpeed = -22;
}
return true;
}
}
I've figured out how to make the balls drop from the top of the screen. The code is supposed to make multiple yellow balls drop from the top of the screen, but only one yellow ball drops. Random yellow balls are supposed to drop from the top, and they drop from different positions. You can see the preview of it below:
To implement this, you should consider creating a custom object Ball
public class Ball{
public int x;
public int y;
public int speed;
public Ball(int x, int y, int speed){
this.x = x;
this.y = y;
this.speed = speed;
}
}
Then you can add multiple Balls in an ArrayList and in the draw() you iterate through every Ball in the array and do what you've been doing to one Ball with each.
for(int i = 0; i < balls.length(); i++){
Ball ball = balls.get(i);
ball.y -= ball.speed;
// check for collisions
// draw ball
}
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
I have an android game where there are sprites moving about the screen. When one is hit, it adds or takes away from the score and then disappears.
What I would like it to do is create a blood splatter when it is hit which will also disappear.
I have actually achieved this but the blood splatter doesn't appear where the sprite was hit. It always goes to the bottom right-hand corner. I was wondering if there is anyone out there that can see where my problem is.
I have a TempSprite class just for the blood splatter and this is below:
public class TempSprite {
private float x;
private float y;
private Bitmap bmp;
private int life = 12;
private List<TempSprite> temps;
public TempSprite(List<TempSprite> temps, GameView gameView, float x,
float y, Bitmap bmp) {
this.x = Math.min(Math.max(x - bmp.getWidth() / 2, 0),
gameView.getWidth() - bmp.getWidth());
this.y = Math.min(Math.max(y - bmp.getHeight() / 2, 0),
gameView.getHeight() - bmp.getHeight());
this.bmp = bmp;
this.temps = temps;
}
public void onDraw(Canvas canvas) {
update();
canvas.drawBitmap(bmp, x, y, null);
}
private void update() {
if (--life < 1) {
temps.remove(this);
}
}
}
All the other code is in the GameView class, specifically in the doDraw and GameView methods:
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private final Bitmap bmpBlood;
/* Member (state) fields */
private GameLoopThread gameLoopThread;
private Paint paint; //Reference a paint object
/** The drawable to use as the background of the animation canvas */
private Bitmap mBackgroundImage;
// For creating the game Sprite
private Sprite sprite;
private BadSprite badSprite;
// For recording the number of hits
private int hitCount;
// For displaying the highest score
private int highScore;
// To track if a game is over
private boolean gameOver;
// To play sound
private SoundPool mySound;
private int zapSoundId;
private int screamSoundId;
// For multiple sprites
private ArrayList<Sprite> spritesArrayList;
private ArrayList<BadSprite> badSpriteArrayList;
// For the temp blood image
private List<TempSprite> temps = new ArrayList<TempSprite>();
//int backButtonCount = 0;
private void createSprites() {
// Initialise sprite object
spritesArrayList = new ArrayList<>();
badSpriteArrayList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
spritesArrayList.add(new Sprite(this));
badSpriteArrayList.add(new BadSprite(this));
}
}
public GameView(Context context) {
super(context);
// Focus must be on GameView so that events can be handled.
this.setFocusable(true);
// For intercepting events on the surface.
this.getHolder().addCallback(this);
// Background image added
mBackgroundImage = BitmapFactory.decodeResource(this.getResources(), R.drawable.castle);
// Populate multiple sprites
//createSprites();
//Vibrator vibe = (Vibrator) sprite.getSystemService(Context.VIBRATOR_SERVICE);
//vibe.vibrate(500);
// For the temp blood splatter
bmpBlood = BitmapFactory.decodeResource(getResources(), R.drawable.blood1);
//Sound effects for the sprite touch
mySound = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
screamSoundId = mySound.load(context, R.raw.scream, 1);
zapSoundId = mySound.load(context, R.raw.zap, 1);
}
/* Called immediately after the surface created */
public void surfaceCreated(SurfaceHolder holder) {
createSprites();
// We can now safely setup the game start the game loop.
ResetGame();//Set up a new game up - could be called by a 'play again option'
mBackgroundImage = Bitmap.createScaledBitmap(mBackgroundImage, getWidth(), getHeight(), true);
gameLoopThread = new GameLoopThread(this.getHolder(), this);
gameLoopThread.running = true;
gameLoopThread.start();
}
// For the countdown timer
private long startTime; // Timer to count down from
private final long interval = 1 * 1000; // 1 sec interval
private CountDownTimer countDownTimer; // Reference to the class
private boolean timerRunning = false;
private String displayTime; // To display the time on the screen
//To initialise/reset game
private void ResetGame(){
/* Set paint details */
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(20);
sprite = new Sprite(this);
hitCount = 0;
// Set timer
startTime = 10; // Start at 10s to count down
// Create new object - convert startTime to milliseconds
countDownTimer = new MyCountDownTimer(startTime*1000, interval);
countDownTimer.start(); // Start the time running
timerRunning = true;
gameOver = false;
}
// Countdown Timer - private class
private class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer (long startTime, long interval) {
super(startTime, interval);
}
public void onFinish() {
//displayTime = "Time is up!";
timerRunning = false;
countDownTimer.cancel();
gameOver = true;
}
public void onTick (long millisUntilFinished) {
displayTime = " " + millisUntilFinished / 1000;
}
}
//This class updates and manages the assets prior to drawing - called from the Thread
public void update(){
}
/**
* To draw the game to the screen
* This is called from Thread, so synchronisation can be done
*/
#SuppressWarnings("ResourceAsColor")
public void doDraw(Canvas canvas) {
canvas.drawBitmap(mBackgroundImage, 0, 0, null);
if (!gameOver) {
sprite.draw(canvas);
//paint.setColor(R.color.red);
canvas.drawText("Time Remaining: " + displayTime, 35, 50, paint);
canvas.drawText("Number of hits: " + hitCount, 35, 85, paint);
// Draw the blood splatter
for (int i = temps.size() - 1; i >= 0; i--) {
temps.get(i).onDraw(canvas);
}
// Draw all the objects on the canvas
for (int i = 0; i < spritesArrayList.size(); i++) {
Sprite sprite = spritesArrayList.get(i);
sprite.draw(canvas);
}
for (int i = 0; i < badSpriteArrayList.size(); i++) {
BadSprite badSprite = badSpriteArrayList.get(i);
badSprite.draw(canvas);
}
} else {
canvas.drawText("Game Over!", 35, 50, paint);
canvas.drawText("Your score was: " + hitCount, 35, 80, paint);
canvas.drawText("To go back home,", 280, 50, paint);
canvas.drawText("press the 'back' key", 280, 70, paint);
}
}
//To be used if we need to find where screen was touched
public boolean onTouchEvent(MotionEvent event) {
for (int i = spritesArrayList.size()-1; i>=0; i--) {
Sprite sprite = spritesArrayList.get(i);
if (sprite.wasItTouched(event.getX(), event.getY())) {
mySound.play(zapSoundId, 1.0f, 1.0f, 0,0, 1.5f);
spritesArrayList.remove(sprite);
//temps.add(new TempSprite(temps, this, x, y, bmpBlood));
hitCount--;
return super.onTouchEvent(event);
}
for (int i1 = badSpriteArrayList.size()-1; i1>=0; i1--) {
BadSprite badSprite = badSpriteArrayList.get(i1);
if (badSprite.wasItTouched(event.getX(), event.getY())) {
mySound.play(screamSoundId, 1.0f, 1.0f, 0, 0, 1.5f);
badSpriteArrayList.remove(badSprite);
temps.add(new TempSprite(temps, this, x, y, bmpBlood));
hitCount++;
return super.onTouchEvent(event);
}
}
}
//else {
return true;
// }
}
public void surfaceDestroyed(SurfaceHolder holder) {
gameLoopThread.running = false;
// Shut down the game loop thread cleanly.
boolean retry = true;
while(retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {}
}
}
public int getHitCount() {
return hitCount;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
}
As always, any help greatly appreciated.
Thanks
This was solved with the following code:
public class TempSprite {
private float x;
private float y;
private Bitmap bmp;
private int life = 12;
private List<TempSprite> temps;
public TempSprite(List<TempSprite> temps, GameView gameView, float x,
float y, Bitmap bmp) {
/*this.x = Math.min(Math.max(x - bmp.getWidth() / 2, 0),
gameView.getWidth() - bmp.getWidth());
this.y = Math.min(Math.max(y - bmp.getHeight() / 2, 0),
gameView.getHeight() - bmp.getHeight());*/
this.x = x;
this.y = y;
this.bmp = bmp;
this.temps = temps;
}
public void onDraw(Canvas canvas) {
update();
canvas.drawBitmap(bmp, x, y, null);
}
private void update() {
if (--life < 1) {
temps.remove(this);
}
}
}
You can see where the commented out sections are and below are what they were replaced with. I was trying to make things a little too complicated.
I was trying to animate a sprite for an android app and i've encounter a small problem. I'm drawing on a surfaceView that i add on top of already existing layouts. On this surfaceView, i wanted to animate few sprites so they would walk along a path.
So this is the result i'm facing right now :
The walking sprite is leaving a trail. So i decided to google this problem and apparently i had to clear the canvas first before drawing on it.
This was my onDraw method before :
public void onDraw(Canvas canvas) {
update();
int srcX = currentFrame * width;
int srcY = directionX * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
And this was my onDraw method after
public void onDraw(Canvas canvas) {
canvas.drawRGB(0, 0, 0);
update();
int srcX = currentFrame * width;
int srcY = directionX * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
So i now have this as a result
which is great because it leaves no more trail BUT i cant see the layouts underneath. Is there anyway i can get the best of both world ? I thought clearing the canvas would work but it obviously doesnt not work as expected.
I'll post my code below
SurfaceView :
public class MonsterView extends SurfaceView {
private Bitmap monsterImg;
private SurfaceHolder holder;
private MonsterThread mainThread;
private Sprite monsterSprite;
private int x;
private int xSpeed = 1;
public MonsterView(Context context) {
super(context);
this.mainThread = new MonsterThread(this);
this.x = 0;
holder = getHolder();
holder.setFormat(PixelFormat.TRANSPARENT);
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
mainThread.setRunning(true);
mainThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mainThread.setRunning(false);
while (retry) {
try {
mainThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
});
setZOrderOnTop(true);
monsterImg = BitmapFactory.decodeResource(getResources(), R.drawable.fire);
monsterSprite = new Sprite(this,monsterImg);
}
#Override
public void onDraw(Canvas canvas) {
if (x == getWidth() - monsterImg.getWidth()) {
xSpeed = -1;
}
if (x == 0) {
xSpeed = 1;
}
x = x + xSpeed;
monsterSprite.onDraw(canvas);
}
Thread :
public class MonsterThread extends Thread {
private MonsterView monsterSurface;
private boolean running;
static final long FPS = 35;
public MonsterThread(MonsterView monsterSurface){
this.monsterSurface = monsterSurface;
this.running = false;
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while(running){
Canvas c = null;
startTime = System.currentTimeMillis();
try{
c = monsterSurface.getHolder().lockCanvas();
synchronized (monsterSurface.getHolder()){
monsterSurface.onDraw(c);
}
} finally {
if( c!= null){
monsterSurface.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if(sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e){}
}
}
public MonsterView getMonsterSurface() {
return monsterSurface;
}
public void setMonsterSurface(MonsterView monsterSurface) {
this.monsterSurface = monsterSurface;
}
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
Sprite :
public class Sprite {
private static final int BMP_ROWS = 4;
private static final int BMP_COLUMNS = 3;
private int x = 0;
private int y = 0;
private int xSpeed = 5;
private MonsterView monsterView;
private Bitmap bmp;
private int currentFrame = 0;
private int width;
private int height;
private int directionX;
public Sprite(MonsterView monsterView, Bitmap bmp) {
this.monsterView = monsterView;
this.bmp=bmp;
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
this.directionX = 2;
}
private void update() {
if (x > monsterView.getWidth() - width - xSpeed) {
xSpeed = -5;
directionX = 1;
}
if (x + xSpeed < 0) {
xSpeed = 5;
directionX = 2;
}
x = x + xSpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
Log.d("test", ""+currentFrame);
}
public void onDraw(Canvas canvas) {
update();
int srcX = currentFrame * width;
int srcY = directionX * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
You're using setZOrderOnTop(), which is putting the Surface part of the SurfaceView on a layer above everything else. (By default, it's a separate layer below everything else.) When you clear it with canvas.drawRGB(0, 0, 0) you're setting the entire layer to opaque black, which is going to obscure the View layer beneath it.
If instead you clear it to transparent black, with canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR), you should get the results you want.
FWIW, you shouldn't override onDraw() if you're only drawing on the Surface. The onDraw() method is called by the View hierarchy to draw on the View part of the SurfaceView. If something manages to invalidate the SurfaceView's View, your onDraw() will be called, and you'll end up with a character sprite on the View layer. (Depending on your layout this may not be visible.) Just give the method a different name.
There are a number of ways to handle this, but generally, the way to do this is by maintaining a background layer (which is just another image), and sprite layers. Instead of clearing, at each frame you blit (copy) your background onto the surface (which erases everything), then you blit your sprites.
So you're going to have to draw the background bitmap onto the surface first before drawing your sprite. Right now you're drawing black which is covering your background layouts.
Alternatively you might be able to do canvas.drawRect with a Paint with paint.setColor to Color.Transparent.