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
Related
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.
The mentioned class has got the following method:
protected void drawCompass(Canvas canvas, float bearing) {
int offset = Math.max(canvas.getHeight(), canvas.getWidth()) / 8;
Rect r = new Rect(0, 0, 2*offset, 2*offset);
canvas.drawBitmap(compassBase, null, r, paint);
canvas.rotate(-bearing, offset, offset);
canvas.drawBitmap(compassArrow, null, r, paint);
}
Link to the complete src: MyLocationOverlay
There they create a Rect r witch specifies where the both Bitmaps should be drawn on the canvas.
The java doc of drawBitmap says :"Draw the specified bitmap, scaling/translating automatically to fill the destination rectangle. If the source rectangle is not null, it specifies the subset of the bitmap to draw. "
Because both Bitmaps use the same Rect r and because they both are automatically scaled to fit the Rect, why is the result a perfect Compass when I activate the compass in the MapView.
To my mind the result should be crap, because the arrow of the compass is also scaled to fit the Rect.
So where is the error in reasoning?
They are scaled using the same proportion, not to absolute size. To answer your question, the canvas is drawn on using the bitmap as reference - think of it like a painter and a canvas painting one image on top of the other using two photo images as reference.
I need to make a thumbnail view with rounded corners and inner shadow. Usually I'm making ImageView frames with 9patches, which have served me well so far, but this time the effect I need requires drawing the inner shadow on top of the image (and not just around it). This lead me to extend the ImageView class and override the onDraw() method.
public class ThumbnailImageView extends ImageView {
After many tutorials (thanks StackOverflow!), I ended up with this code for the onDraw() method:
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
return;
}
int radius = 4;
int padding = 2;
int bleed = 2;
RectF frame = new RectF(padding, padding, getWidth() - padding, getHeight() - padding);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xFF000000);
canvas.drawRoundRect(frame, radius, radius, mPaint);
Shader bitmapShader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xFF000000);
mPaint.setMaskFilter(new BlurMaskFilter(bleed, Blur.INNER));
mPaint.setShader(bitmapShader);
canvas.drawRoundRect(frame, radius, radius, mPaint);
}
What I'm basically doing, is drawing a black rounded rectangle first and then drawing a rounded-corners bitmap with fading edges (with the BlurMaskFilter) on top of it. The result is what I want:
The mBitmap value is initialized in the ImageView constructor like this:
mDrawable = getDrawable();
if (mDrawable != null) {
mBitmap = ((BitmapDrawable) mDrawable).getBitmap();
}
The problem is that I am overriding onDraw() completely (no super.onDraw()) is called, so I have to pre-scale all images to the desired thumbnail size (e.g. 96x96) or else only the top-left corner of the image is drawn. What I want to be able to do is take advantage of all the scaling the framework is doing when I assign the following xml values to the ThumbnailImageView:
android:id="#+id/thumb"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
To do this, I thought I should somehow call super.onDraw() while getting the effects I need at the same time. I have managed to get the rounded rectange by adding a clipping path to the canvas, but I can't find a way to add the inner shadow. This is the new onDraw() code:
#Override
protected void onDraw(Canvas canvas) {
int radius = 4;
int padding = 4;
RectF frame = new RectF(padding, padding, getWidth() - padding, getHeight() - padding);
Path clipPath = new Path();
clipPath.addRoundRect(frame, radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
// add inner shadow
}
I can see two alternatives:
1) To properly pre-scale the ImageView's bitmap. But where is the best place to do it? In it's constructor? In the onDraw() method where the framework seems to be doing it? Is the framework even resizing any bitmap or is there another way to draw a scaled image on the canvas without being bad for performance?
2) To add the inner shadow layer on top of what the super.onDraw() is drawing so far, but I'm running out of ideas on how to do this.
Any help would be appreciated.
Thanks!
Take a look at Eric's (from squareup) presentation material from Oreilly's AndoridOpen Conference last year in his lecture titled Beautiful Android
It has a ton of info that should help you out.
I wish they had the video of his presentation somewhere. I could not find it. So sorry.
EDIT : Thanks to #mykola for the yt link
I am drawing a grid and I want it to be larger than the screen size so that a user can drag the screen left/right/up/down to get to the rest of the grid.
What is the best way to do that? I've tried drawing a larger bitmap to the canvas, but didn't get anywhere.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
Bitmap testBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888);
canvas.drawBitmap(testBitmap, 0, 0, paint);
canvas.drawPaint(paint);
//other grid drawing code here
}
I used the View's scrollBy() method in the onTouch method of the Activity. It worked.
You can probably use the canvas.translate(x, y) method. That will adjust the origin for your canvas in relation to the screen. So canvas.translate(10, 10) will make you canvas origin (0, 0) be at the point of (10, 10) on the screen. Use a negative translation to scroll the screen.
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.