I have a class which extends SurfaceView and implements SurfaceHolder.Callback. Using onDraw() method i'm drawing some bitmaps on my canvas. The, after pressing a button I'm adding new image to the canvas calling invalidate(). Is any possibility to save all the changes which I made on every invalidate() which were earlier, so as to after new invalidate() add new image, but not delete the earlier?
From what I have understood you will want to save the image that was drawn and also it's position? By using the code I provided you will have a list that is filled with the image and position. The list is unordered; if you would like an ordered list you can use a LinkedList instead.
Create a new class, you may name it anything.
public class ImageHolder {
private int mX;
private int mY;
private int mDrawableResource;
private String mBitmapFilePath;
public ImageHolder(int x, int y, int drawableResource, String bitmapFilePath) {
mX = x;
mY = y;
mDrawableResource = drawableResource;
mBitmapFilePath = bitmapFilePath;
}
public int getX() {
return mX;
}
public int getY() {
return mY;
}
public int getDrawableResource() {
return mDrawableResource;
}
public String getBitmapFilePath() {
return mBitmapFilePath;
}
}
Then in your SurfaceView you add it a holder each time you draw to a list. Notice that this is bare minimum code so no synchronization has been added.
private void customDrawMethod() {
mImageHolders.add(new ImageHolder(x, y, drawableResource, bitmapFilePath));
Canvas canvas = getHolder().lockCanvas();
canvas.drawBitmap(bitmap, matrix, paint);
getHolder().unlockCanvasAndPost(canvas);
}
I added both a Bitmap and a Drawable because I am unsure what you use. I could not post more code because I have no idea what you want to do with the saved images. More info could help you further.
This is pretty straightforward case of using Bitmaps to store your previous canvas. Simply attach a bitmap to your canvas. Before drawing, save the old bitmap to something like "prevBitmap" and then draw over it. You can redraw the previous Bitmap by calling canvas.drawBitmap(prevBitmap);
You can save your old drawings on canvas and dont draw them again when adding new picture. Just call invalidate(x, y, x+sizeX, y+sizeY) when you need to add new image with left-top point's coordinates (x, y) and size (sizeX, sizeY) to the View's canvas. About to save all images in array you already got answer.
P.S. sorry for my english, hope it was helpfull
Related
I have created a custom view class to use in a project I'm working on. To put is simply, I'm displaying an image, then adding images on top of the original image (currently by clicking on the image, but that's not final).
I have these 2 methods in my custom view:
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
for (Drawable d : drawableList)
{
d.draw(canvas);
}
}
public void AddPoint(float x, float y)
{
Drawable tempDrawable = pin;
tempDrawable.setBounds((int)x, (int)y, (int)x + 50, (int)y + 50);
drawableList.add(tempDrawable);
invalidate();
}
The AddPoint() method is called in an OnTouchListener and is passes the coordinates of the touch event.
The way it currently works is it displays the main image, but will only display the most recent images where I clicked, previous ones just disappear.
Does anybody know what I am doing wrong here?
I've figured out what I was doing wrong.
The line of code:
Drawable tempDrawable = pin;
I changed to:
Drawable tempDrawable = mainRes.getDrawable(R.drawable.pin);
I got mainRes from the init(Context context) method I wrote in the custom View class.
I want to divide the image into sub images and when I click on a part of the image will give me the name of the region, for example, this is my question how to recognize a region from the image, or how to divide the image into sub-images and use it in imageViews
And thank you in advance
In my opinion #fractalwrench's idea is quite good for your case. Basic steps are listed below.
Subclass Android ImageView. For example, MultiRegionImageView.
Override its onTouchEvent method. (This method gets called whenever user touches the view)
User touches the image and thereby onTouchEvent is called and provides the exact touch point (x, y).
Declare another method or interface which determines at which region a given point is. For example, getRegionByPoint(int x, int y)
If you would like to highlight that region boundaries, you could use paths. First off, you should define paths and save them into a raw file (XML, for example), then using region ID, fetch its path and finally draw that path over the main image.
For drawing a path over the main image, you should also override onDraw method of ImageView class and use canvas.drawPath();
public class MultiRegionImageView extends ImageView {
RegionProvider mRegionProvider;
int mId = -1;
private Paint mPaint;
public MultiRegionImageView(Context context) {
super(context);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mId = mRegionProvider.getRegionIdByPoint(event.getX(), event.getY());
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mId != -1) {
canvas.drawPath(mRegionProvider.getRegionBoundaryPath(mId), mPaint);
}
}
public interface RegionProvider{
int getRegionIdByPoint(float x, float y);
Path getRegionBoundaryPath(int id);
}
}
You should only need one ImageView to display the map. If you override onTouchEvent(MotionEvent e), you can get the position which is being touched in the View. If you store the position and shape of each region in some sort of List, you can check whether a touch event is within a region (and display whatever text you need to).
currently I am trying to make an animation where some fish move around. I have successfully add one fish and made it animate using canvas and Bitmap. But currently I am trying to add a background that I made in Photoshop and whenever I add it in as a bitmap and draw it to the canvas no background shows up and the fish starts to lag across the screen. I was wondering if I needed to make a new View class and draw on a different canvas or if I could use the same one? Thank you for the help!
Here is the code in case you guys are interested:
public class Fish extends View {
Bitmap bitmap;
float x, y;
public Fish(Context context) {
super(context);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.fish1);
x = 0;
y = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, x, y, null);
if (x < canvas.getWidth())
{
x += 7;
}else{
x = 0;
}
invalidate();
}
}
You can draw as many bitmaps as you like. Each will overlay the prior. Thus, draw your background first, then draw your other images. Be sure that in your main images, you use transparent pixels where you want the background to show through.
In your code, don't call Invalidate() - that's what causes Android to call onDraw() and should only be called from somewhere else when some data has changed and needs to be redrawn.
You can do something like this, where theView is the view containing your animation:
In your activity, put this code in onCreate()
myAnimation();
Then
private void myAnimation()
{
int millis = 50; // milliseconds between displaying frames
theView.postDelayed (new Runnable ()
{
#Override public void run()
{
theView.invalidate();
myAnimation(); // you can add a conditional here to stop the animation
}
}, millis);
}
I want to develop a game that shoots bullets on every touch of the canvas.
It works but when I touch the canvas after shooting, he takes the bullet and restarts the shooting.
I just want the bitmap to create new bullet at every touch. Here is my code:
public class MainActivity extends Activity implements OnTouchListener {
DrawBall d;
int x ;
int y;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
d = new DrawBall(this);
d.setOnTouchListener(this);
setContentView(d);
}
public class DrawBall extends View {
Bitmap alien;
public DrawBall(Context context) {
super(context);
alien = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
startDraw(canvas);
}
public void startDraw(Canvas canvas){
Rect ourRect = new Rect();
ourRect.set(0,0, canvas.getWidth(), canvas.getHeight());
Paint blue = new Paint();
blue.setColor(Color.BLACK);
blue.setStyle(Paint.Style.FILL);
canvas.drawRect(ourRect, blue);
if(y < canvas.getHeight()){
y-=5;
}
canvas.drawBitmap(alien, x, y,new Paint());
invalidate();
}
}
public boolean onTouch(View v, MotionEvent event) {
x = (int) event.getX();
y = (int) event.getY();
return false;
}
}
I only superficially read the code. It seems that you are only keeping track of one bullet using the x y coordinates.The coordinates are resetting at every touch event, and thus you lose the previous bullet.
Use a dynamic array, or a linked list to keep track of all the bullets on the screen.
When there's a new touch, add the x,y to the array.
When drawing the bullet, iterate through your array to draw and update every bullet.
If the y-coordinate of any bullet goes out of the screen, delete the bullet from the array.
Each draw starts with a blank canvas. So to draw multiple bitmaps you need to keep track of where to draw each bullet and call drawBitmap multiple times.
Also, calling invalidate in onDraw is a bad idea- it will immediately invalidate, leading you to have performance issues. I'd suggest invalidating on a timer instead. Drawing too frequently will lead to performance issues.
I have drawn a bitmap image over a canvas.
Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.sq);
canvas.drawColor(color.black);
Rect dstRectForRender = new Rect(0,0,320,450);
canvas.drawBitmap(image, null,dstRectForRender,null);
The image gets displayed based on my screnn on a cnavs.
On my touch input, I need to pass the x and y co-ordinate position of the image and fill that pixel with a color to show that the image is painted on a drag event.
How can I pass the x and y coo-ordinate parameters? Which functions should I use to plot the pixels on the image?
I appreciate your help and sweet time.
I'm not sure if this is the best way to do this, but it would be much easier to do this if you defined your own subclass of ImageView and name it something like DrawableImageView. You'd have to make sure you implement all the basic constructors from ImageView, then override the onTouchEvent method. From that event you can get the touch coordinates and store them in an ArrayList<Point> and use that ArrayList by overriding the onDraw method and "painting" the image.
public class DrawableImageView extends ImageView {
ArrayList<Point> list = new ArrayList<Point>();
//constructors..
#Override
public boolean onTouchEvent (MotionEvent event) {
float x = event.getX();
float y = event.getY();
list.add(new Point(x,y));
invalidate();
}
This is just a very brief overview of how to start your class, and may not be the most accurate way of doing things (depending on your specific code). Now, instead of using <ImageView> tags in your xml (or, loading an ImageView programatically), you refer to your subclass like so:
<your.package.name.DrawableImageView
/>
Edit
In response to your comment, there is no predetermined way to draw over an image. You must implement this yourself, which is why I recommended storing Points in an ArrayList. I'm not really sure what you're trying to achieve here, but to draw (for example) black dots over an image you have to override onDraw:
public void onDraw(Canvas c) {
super.onDraw(c);
for(Point p : list) {
//Draw black point at x and y.. I'm posting from my cell so I can't go into much detail
}
}
Also, to force a View to redraw itself you need to use the invalidate() method in your onTouchEvent() (which I've added above).