I'm doing a Live Wallpaper. I have a Runnable (which is updated every 5 seconds) where I call a draw() method which draws something on a Canvas. It calls a method in another class which is supposed to draw a series of bitmaps (with a delay, so it's animated). How would I change the code below, so that the next bitmap would be drawn with a delay?
int imageToDraw = 10;
while(imageToDraw>=0)
{
Bitmap b = BitmapFactory.decodeResource(mContext.getResources(), mContext.getResources().getIdentifier("image_"+imageToDraw, "raw", mContext.getPackageName()));
float centerX = (width - b.getWidth())/2;
float centerY = (height - b.getHeight())/2;
Paint p = new Paint();
p.setColor(Color.BLACK);
mCanvas.drawRect(0f, 0f, (float)width, (float)height, p); //draws a rectangle to clear the screen
mCanvas.drawBitmap(b, centerX, centerY, new Paint());
--imageToDraw;
b.recycle();
}
From Android's API Guide on Canvas and Drawables:
Draw your graphics directly to a Canvas. This way, you personally call
the appropriate class's onDraw() method (passing it your Canvas), or
one of the Canvas draw...() methods (like drawPicture()). In doing so,
you are also in control of any animation.
This means you have to perform the animation yourself, frame by frame. If you don't actually need to draw complex graphics, consider switching back to standard views so you can use help class like AnimationDrawable. Check here for an example of how to do your own animation in Canvas.
Related
I am trying to animate a circle that is drawn onto a canvas:
Paint pCirclePink = new Paint();
pCirclePink.setColor(Color.parseColor("#ff0000"));
pCirclePink.setAntiAlias(true);
if (userPlaceBeacon != null){
c.drawCircle((float) userPlaceBeacon.getPlacement_x() + offsetX, (float) userPlaceBeacon.getPlacement_y() + offsetY, 30, pCirclePink);
Bitmap bmpUserDestination = ((BitmapDrawable) drawableUserMarker).getBitmap();
bmpUserDestination = Bitmap.createScaledBitmap(bmpUserDestination, 28, 28, false);
c.drawBitmap(bmpUserDestination, (float) userPlaceBeacon.getPlacement_x() + offsetX - 14, (float) userPlaceBeacon.getPlacement_y() + offsetY - 14, null);
}
c.save();
When 'c.drawCircle' is called, I want the circle to have a pulse animation.
The circle shows the users current location on a panable map (which is a Bitmap that is injected using the Glide library).
I am having trouble because most libraries/methods I find online all derive from a View or ViewGroup class; whereas I am trying to draw onto an BitMap that is pan-able and scalable.
Here is more of the code I am working with:
There are two approaches:
1) You can create your own custom view by extending View class and draw circle in onDraw(Canvas canvas) method. To imitate a pulse animation you have to call postInvalidate method to force view call onDraw(Canvas canvas) method again and again and draw your increased or decreased circle.
2) You can use simple scale animation
I have an Activity in which the user touches the eye positions on a picture, and this is supposed to draw a little white circle over each. I have a working bit of code that, using the Android FaceDetector tools, finds the eye positions and facial midpoint and draws a rectangle. The drawing part of that code, for reference, is this:
private void drawRectangles(){
Canvas canvas = new Canvas(mBitmap);
Paint paint = new Paint();
paint.setStrokeWidth(2);
paint.setColor(Color.BLUE);
paint.setStyle(Style.STROKE);
for (int i=0; i < faceFrames.length; i++) {
RectF r = faceFrames[i];
if (r != null){
canvas.drawRect(r, paint);
Log.d(TAG, "Drew rectangle");
}
}
mImageView.setImageResource(0);
mImageView.setImageBitmap(mBitmap);
mImageView.draw(canvas);
}
That part's fine. I figured, as a method that is called from onTouchEvent, that I could use the following to draw a circle:
private void makeDrawableLayer(int x, int y, int touchCount){
if (touchCount == 1){
Bitmap eyeOneBmp = Bitmap.createBitmap(mBitmap);
Canvas c1 = new Canvas(eyeOneBmp);
c1.drawCircle(x, y, 5, eyePaint);
mImageView.setImageResource(0);
mImageView.setImageBitmap(eyeOneBmp);
mImageView.draw(c1);
}
}
Here are screen shots showing the result of each code snippet. The first picture is the rectangle drawn on the face. The second picture shows the very strange result I get when I attempt to draw using the second code snippet. Note, however, that I had specified x and y as 10, 10 for the circle's position when drawing the second output. It's the same thing when I give it the passed-in eye position coordinates, just with the pixelated circle coming from wherever the eye is.
Does anyone have any idea what the heck is going on with this behavior?
Thanks so much.
So I found that you can basically only draw one time to the canvas before needing to make a class that extends View to start calling methods from. What I ended up needing to do was: customView.prepareCircle(), customView.invalidate(), and then parentView.addView(customView). And actually, I could only prepare, invalidate, and re-add the modified custom view to the canvas once before having to make any subsequent calls from a Runnable on the UI thread. I am not under the impression this is an ideal way to do it (certainly doesn't feel elegant), but it is giving me the results I want:
I'm basically trying to implement something similar to this. Sadly, it's an iOS tutorial.
I have googled in most possible keywords to move something in circular manner, but couldn't find any to start off. Can any one atleast provide any hints on how this can be hacked on android? Please.
Thanks.
i used rotate animation to rotate an image about a point.
double r = Math.atan2(evt.getX() - turntable.getWidth() / 2, turntable.getHeight() / 2 - evt.getY());
rotation = (int) Math.toDegrees(r);
if (evt.getAction() == MotionEvent.ACTION_MOVE)
{
x= (int)evt.getX();
y = (int)evt.getY();
rotateAnim = new RotateAnimation(angle,rotation-50,200,100);
rotateAnim.setFillAfter(true);
ImageView.setanimation(rotateAnim );
ImageView.startAnimation(rotateAnim);
}
you can also use matrix
float newRot = new Float(rot);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.disc);
Matrix matrix = new Matrix();
matrix.postRotate(newRot - 50);
Bitmap redrawnBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
turntable.setImageBitmap(redrawnBitmap);
This would be pretty easy to do in a custom control. Just create a class that extends View and override the draw() method. Then you can listen for touches and calculate how far the user has rotated the control. Then you just need to use that data to rotate the canvas and draw the numbers on it.
-= Update =-
When you override the draw method you get a Canvas object. That object lets you draw to it what ever you want. It would look something like this:
#Override
public void draw(Canvas c)
{
c.rotate(amount);
c.drawBitmap(myImage);
}
This is a link to the full Canvas Documentation.
I am learning android Live wallpaper development. I found an awesome template in the AndEngine Forums
In this template I found an overridable method OnTab which provides 2 parameters i.e x coordintate & y coordinate .
protected void onTap(final int pX, final int pY)
{
SurfaceHolder holder= //Get current surface holder object
Paint paint = new Paint();
Canvas canvas= holder.lockCanvas();
paint.setColor(Color.WHITE);
canvas.drawCircle(20, 50, 25, paint);
}
I want to draw a circle when user tabs or touches the screen but i am finding it difficult to get the sufaceholder object which will let me draw a circle on the canvas Or can i achieve this some other way?
You need to do the drawing within the onDraw() method. When a touch is occurring you should save the X and Y location and then in the onDraw() method draw the circle.
I have this sprite rotating algorithm (its poorly named and just used for testing). It is so close, sprites drawn with it do rotate. Everyframe I can add +5 degrees to it and see my nice little sprite rotate around. The problem is, the other stuff drawn to the canvas now flickers. If I don't do the rotation the regular drawn sprites work great. I think I am close but I just don't know what piece I am missing. Below is my two "Draw_Sprite" methods, one just draws the previously resource loaded bitmap to the canvas passed in. The other one, does some rotation the best I know how to rotate the sprite by so x many degrees..and then draw it. If I have a nice game loop that draws several objects, one type is the rotated kind. Then the non-rotated sprites flicker and yet the rotated sprite never does. Though if I draw the non-rotated sprites first, all is well, but then the Z-Ordering could be messed up (sprites on top of UI elements etc)... The method definitions:
/*************************************************
* rotated sprite, ignore the whatever, its for ease of use and testing to have this argument list
* #param c canvas to draw on.
* #param whatever ignore
* #param rot degrees to rotate
* #return
*/
public int Draw_Sprite(Canvas c, int whatever, int rot) {
//rotating sprite
Rect src = new Rect(0, 0, width, height);
Rect dst = new Rect(x, y, x + width, y + height);
Matrix orig = c.getMatrix();
mMatrix = orig;
orig.setTranslate(0, 0);
orig.postRotate(rot, x+width/2, y+height/2);
c.setMatrix(orig);
c.drawBitmap(images[curr_frame], src, dst, null);
c.setMatrix(mMatrix); //set it back so all things afterwards are displayed correctly.
isScaled=false;
return 1;
}
/********************************************************
* draw a regular sprite to canvas c
* #param c
* #return
*/
public int Draw_Sprite(Canvas c) {
Rect src = new Rect(0, 0, width, height);
Rect dst = new Rect(x, y, x + width, y + height);
c.drawBitmap(images[curr_frame], src, dst, null);
isScaled=false;
return 1;
}
And now the usage:
void onDraw(Canvas c)
{
canvas.drawRect( bgRect, bgPaint); //draw the background
//draw all game objects
// draw the normal items
for (GameEntity graphic : _graphics) {
graphic.toScreenCoords((int)player_x, (int)player_y);
if(graphic.getType().equals("planet")) //draw planets
graphic.Draw_Sprite(canvas); //before the rotation call draws fine
else
{
//rotate all space ships every frame so i see them spinning
//test rotation
mRot +=5;
if(mRot>=360)
mRot=0;
graphic.Draw_Sprite(canvas, 0, mRot); //yes function name will be better in future. this rotates spins draws fine
}
}
thePlayer.Draw_Sprite(canvas); //FLICKERS
drawUI(canvas);//all things here flickr
}
So it does do it, things after a call to a rotational draw are drawn correctly. But the problem is it flickrs. Now One could say I should just do all my non rotational stuff and save that last, but the zordering would be off.... suggestions as to how to tackle this issue of zordering or the flickering?
Just for the next guy who may read this. You can do this with only a few lines of code:
canvas.save();
canvas.rotate(rotation_angle, x + (widthofimage / 2), y + (heightofimage / 2));
canvas.drawBitmap(bitmap, x, y, null);
canvas.restore();
Try using canvas.save() before the rotation and canvas.restore() after manipulation is complete.
When performing manipulations on the canvas in order to change the way an object is drawn you have to remember the manipulations set how the canvas handles origins etc... So if you translate or rotate the canvas, that will be set for the lifetime of that canvas. In order to avoid this you first call save, which saves a snapshot of the canvas matrix before you manipulate it, then you run all your changes, then call restore which will restore the canvas back to the last saved point. Otherwise all your changes build up and you get unintended results.