I am trying to set a png image to fill the background of my canvas while still maintaining its aspect ratio. I start by converting it to a Bitmap:Then set the back ground using the setBitmap method from the Canvas class:
http://developer.android.com/reference/android/graphics/Canvas.html#Canvas(android.graphics.Bitmap)
public class PlayOn extends View{
Bitmap board;
public PlayOn(Context gamecontext) {
super(gamecontext);
board=BitmapFactory.decodeResource(getResources(),R.drawable.board_rev1);
}
#Override
protected void onDraw(Canvas mycanvas) {
super.onDraw(mycanvas);
mycanvas.setBitmap(board);
}
}
But once I go to the Activity that calls this extended View class I get an error saying my application stopped unexpectedly.
I've also tried playing around with some of the other functions in the Canvas and Bitmap class but nothing seems to work.
Please what is the best way to do this? I read on the android developer site that there is a way to set an image so that it is the canvas and other images can then be drawn inside it but I wasn't able to figure out how to do that.
Thanks!
You might want to add a Log.d to check that the board bitmap returned from
BitmapFactory.decodeResource(getResources(),R.drawable.board_rev1);
isn't null. But I am using the following to draw bitmaps to full screen views in onDraw in several applications, so if the bitmap is non-null that should work fine.
canvas.drawBitmap(mBitmap, 0, 0, null);
And there's a version of drawBitmap which scales, namely
void canvas.drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)
Draw the specified bitmap, scaling/translating automatically to fill the
destination rectangle.
You might want to try that?
Related
I would like to show a picture (for example a house) from its various parts like its door, window, roof etc (different images of various part saved in asset folder). i am totally in dark from where and how to start to make this. If any idea or any library please help.
you can load the images from resource on to a bitmap like so:
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.place_drawable_name_here)
then use a custom view, on its onDraw method you can draw all you bitmaps one by one, the door,roof etc... so it will eventually look like a house.
public class MyCustomView extends View{
#Override
protected void onDraw(Canvas canvas) {
...
canvas.drawBitmap(bmp, 0, 0, paint);
}
}
this is of course not a fully working code but it should give you pretty good idea of how you could implement what you wanted.
I have an image with different frame to be displayed, like the following:
As you can see that image has three frames, the full heart, half heart and empty space.
Now i need to only one frame of the three. I'm just wondering if there is a method to do that using a single gif in android sdk.
For example in several language there is a method like:
canvas.drawImage(xpos,ypos,xwidth,xheight,gifx,gify,gifwidth,gifheight)
where gifx,gify,gifwidth,gifheight are the coordinates and size of the selected frame.
Ok i answer myself, i just found a solution.
In order to draw a multiframe image the following method can be used:
public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
Where:
Bitmap bitamp is the Bitmap resource obtained with BitmapFactory.decodeResource (or via your preferred method).
Rect src is the frame to be shown (it can be null)
Rect dst rhe rectangle that the bitmap will be scaled/translated to fit into (it can be null)
Paint paint used to draw the bitmap (it can be null)
Another way (that i didn't tested) could be using BitmapRegionDecoder first of all a new instance of the object must be created using BitmapRegionDecoder.newInstance(...)
and then the selected region of bitmap to be shown could be obtained with the method:
public Bitmap decodeRegion (Rect rect, BitmapFactory.Options options)
Where rect is the selected region to be shown. For more info on BitmapRegionDecoder:
http://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html
I'm trying to drop a smooth shadow under a view element. Here's is what I've done so far:
Subclass FrameLayout (my ShadowViewport), which overrides dispatchDraw(...) and does:
Call dispatchDraw of superclass and save output as bitmap
Extract alpa from this bitmap
Blur
Draw blurred extracted alpha with some offset
Draw original view bitmap
#Override
protected void dispatchDraw(Canvas canvas) {
Log.d("ShadowViewport", "dispatchDraw");
final Bitmap output = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
final Canvas sCanvas = new Canvas(output);
// Draw internal view in canvas
super.dispatchDraw(sCanvas);
final Bitmap original = output.copy(Config.ARGB_8888, true);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(0x55000000);
paint.setMaskFilter(new BlurMaskFilter(SHADOW_SIZE, Blur.NORMAL));
canvas.drawBitmap(output.extractAlpha(), 0, SHADOW_SIZE, paint);
canvas.drawBitmap(original, 0, 0, null);
}
Result
Find image here.
As you can see, the left box has a nice generated shadow, even for rounded corners ;)
The question
The on dispatchDraw function is called very often, for example while scrolling. Is there any way for caching?
Enabling the android:hardwareAccelerated="true" attribute in the AndroidManifest will enable automatic caching of the image. Ithe dispatchDraw method is not called for example, during scrolling.
I also think it is possible to use the setDrawingCacheEnabled on your Layout Class. To make that work you should call getDrawingCache first, and the the returned bitmap if it is not null. This seems a bit like a "poor man's" optimization, but is probably a good idea to get performance out of older phones.
I have a widget which looks like this:
Every cone is a "touchable element". Now I want to put a bitmap texture above each cone. However, bitmap images are all rectangular, so a bitmap texture above one cone would interfere with the bitmap texture above another cone.
I'm wondering what is the best solution to this approach. Should I just create an image which fits (as a rectangle) exactly above the cone and make the non used areas transparent?
A second question is, how do bitmap textures work with stretching? Because this whole circle draws itself to fit the whole screen size, while bitmap textures are pretty much one size.
Offhand I can't think of a better way to draw bitmaps over those cones than your own suggestion of using transparent zones.
However, I can help with your second question as stretching bitmaps is not hard. You've got a few options in the Canvas class. For example:
canvas.save();
canvas.scale(xRatio, yRatio);
canvas.drawBitmap(....);
canvas.restore();
You can also use a Matrix, using matrix.postScale(xRatio, yRatio), to then generate either a larger bitmap and draw it normally, or pass the matrix in to your canvas.drawBitmap(....) command to make it scale while it draws.
All of these methods assume you have access to the drawing canvas itself. If you are using a view, you can subclass it and override the onDraw(Canvas canvas) method to grab the canvas before it starts drawing it. If you're using a SurfaceHolder, then you should already know how to get the canvas.
Edit: I forgot the third method I was going to describe. You can use the canvas.drawBitmap(bitmap, srcRect, dstRect, paint) to also make the canvas scale the bitmap to fit the destination rectangle. In short, there are lots of methods to do this - pick the one that's easiest based on your application!
I'm used to handle graphics with old-school libraries (allegro, GD, pygame), where if I want to copy a part of a bitmap into another... I just use blit.
I'm trying to figure out how to do that in android, and I got very confused.
So... we have these Canvas that are write-only, and Bitmaps that are read-only? It seems too stupid to be real, there must be something I'm missing, but I really can't figure it out.
edit: to be more precise... if bitmaps are read only, and canvas are write only, I can't blit A into B, and then B into C?
The code to copy one bitmap into another is like this:
Rect src = new Rect(0, 0, 50, 50);
Rect dst = new Rect(50, 50, 200, 200);
canvas.drawBitmap(originalBitmap, src, dst, null);
That specifies that you want to copy the top left corner (50x50) of a bitmap, and then stretch that into a 150x150 Bitmap and write it 50px offset from the top left corner of your canvas.
You can trigger drawing via invalidate() but I recommend using a SurfaceView if you're doing animation. The problem with invalidate is that it only draws once the thread goes idle, so you can't use it in a loop - it would only draw the last frame. Here are some links to other questions I've answered about graphics, they might be of use to explain what I mean.
How to draw a rectangle (empty or filled, and a few other options)
How to create a custom SurfaceView for animation
Links to the code for an app with randomly bouncing balls on the screen, also including touch control
Some more info about SurfaceView versus Invalidate()
Some difficulties with manually rotating things
In response to the comments, here is more information:
If you get the Canvas from a SurfaceHolder.lockCanvas() then I don't think you can copy the residual data that was in it into a Bitmap. But that's not what that control is for - you only use than when you've sorted everything out and you're ready to draw.
What you want to do is create a canvas that draws into a bitmap using
Canvas canvas = new Canvas(yourBitmap)
You can then do whatever transformations and drawing ops you want. yourBitmap will contain all the newest information. Then you use the surface holder like so:
Canvas someOtherCanvas = surfaceHolder.lockCanvas()
someOtherCanvas.drawBitmap(yourBitmap, ....)
That way you've always got yourBitmap which has whatever information in it you're trying to preserve.
In android you draw to the canvas, and when you want it to update you call invalidate which will the redraw this canvas to the screen. So I'm guessing you have overridden the onDraw method of your view so just add invalidate();
#Override
public void onDraw(Canvas canvas) {
// Draw a bitmap to the canvas at 0,0
canvas.drawBitmap(mBitmap, 0, 0, null);
// Add in your drawing functions here
super.onDraw(canvas);
// Call invalidate to draw to screen
invalidate();
}
The above code simply redraws the bitmap constantly, of course you want to add in extra thing to draw and consider using a timing function that calls invalidate so that it is not constantly running. I'd advice having a look at the lunarlander sources.