I have a SurfaceView which is currently drawing a series of Bitmaps. These bitmaps can easily be manipulated geometrically (scale/rotate/translate/etc). An example would be a ball which is bouncing, which may just use translate/rotate operations. The ball is just a single bitmap.
I wish to replace this 'ball' Bitmap with a sequence of Bitmaps, for example if the ball were to explode in a flurry of fireworks, I have the individual frames and I wish to string them together.
Without having to manually cycle through them on each onDraw() call in my SurfaceView, how can I go about this? I know in normal conditions I can just make an AnimationDrawable using the frames in an XML file, bind it to an ImageView (set as background) then call it. However, I am using a SurfaceView for displaying all my graphics on screen, not ImageViews. I have read you can overlay other views on top of SurfaceViews, but I am unsure that I could get the exact position required. For example, the ball may explode at X=65 Y=21 on my SurfaceView, how could I translate this exact co-ordinate to my ImageView?
Any help or tips on alternative methods would be greatly appreciated.
If you want to keep it more separated, you can create another class that handles this animation and keeps track of which frame it's on and the bitmaps to use then delegate drawing of the sprite to this class in your SurfaceView's onDraw.
Related
Use case:
I need to draw hundred lines and a few pieces of text on my view. I need to give a scrolling effect, for which I capture the ACTION_MOVE event and redraw all the lines with the updated points. To get the desire result I tried with different approaches but none works as intended.
Approach 1
I made a custom class which extends View. All the drawing and calculation is done directly in my onDraw() method. Since there is so much of operation done in onDraw() method, the performance of the app is very poor. I even checked the performance using Profile GPU rendering and I can see the lines are very tall.
Approach 2
I created a Bitmap and after drawing all the lines onto my bitmap in another thread, I used postInvalidate() to draw the bitmap in onDraw() method:
mBufferedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mBufferedBitmap.eraseColor(Color.TRANSPARENT);
Canvas mBufferedCanvas = new Canvas(mBufferedBitmap);
drawLines(mBufferedCanvas)
postInvalidate();
Since I erase all the previous drawing on the bitmap and draw new lines with updated points, there is a flickering on the screen.
Approach 3
I tried extending my custom class to SurfaceView and performing all the operations on canvas object in another thread. But since SurfaceView uses CPU for drawing operations, the performance will be poor in low configuration mobiles.
Can anyone guide me how to achieve this task with better performance?
It is possible to use your approach 1 to achieve good performance.
An example that sounds close to your use case (drawing lines, a little text and having these update on gesture movement) is MPAndroidChart. This is an open source library that achieves high performance (see the following comparison if you want stats)
The classes to examine are the Renderer classes as these contain code draw in the onDraw(Canvas c) of the chart subtypes. You can see some of the tricks used to achieve high performance there:
Don't allocate in a render loop. Instead, allocate outside the loop and reuse/recycle variables. See LineChartRenderer line 199
Use buffering. For example, in MPAndroidChart, the points for the four corners of the bars in the bar chart are buffered and the buffer array is reused. See the BarBuffer class.
Use the native Canvas drawing functions (drawPath, drawLine etc.)
A complete list of tips for optimising rendering can be found in the Android Performance Slow Rendering Guide
Approach 2 is the best one. If you see flickering, it means that the bitmap is drawn to screen after you erase it and before you draw all the lines. If this is the case use another bitmap and do double buffering:
ScreenBitmap is what is drawn to screen
OffScreenBitmap is used for drawing in background.
Draw all your lines and text to OffScreenBitmap, and once finished, copy it to ScreenBitmap.
in onDraw, draw the ScreenBitmap.
Create these bitmaps once (typically in onSizeChanged), so that there is no alloocation in onDraw
I'm building an android game and this is more of just best practices and performance question.
For the bitmaps that I have that the user interacts with, should I place them in an imageView and set an onTouchListener for each of them individually or should I just draw them onto the canvas and use the custom view's onTouch method to obtain the x and y of the touch and see if it falls in the range of any of the bitmaps to detect a touch.
My custom view takes up the entire screen, and I don't know how if it is even possible to draw an imageview onto the screen using a canvas which is why as of now I just use the onTouch method.
Thanks for any insight.
Depending on how dynamic your bitmaps render will be, you should go for either GLSurfaceView or SurfaceView, for something simple as just bitmaps i would recommend you to use SurfaceView as "renderer" where you can get the canvas from and of course you can draw on the whole screen if your surfaceview match the screen size.
TouchListener should be completely separated handled on its own listener promoting encapsulation and reuse of code for future apps that you want to do. I've found this quiet helpful for the last games i've developed asingning a surface view as renderer and just creating Objects which takes the canvas as parameter and drawing them self into it, the only thing you have to take on count is the bitmap resource management, but if you are careful of releasing and creating them when is proper, you should have no problems...
Regards!
I want to be able to dynamically place image(s) over another image in my app.
Consider the first image as background and the other images to be on top level, I will also need to move those top level images (change their x and y on the screen) by code too.
Imagine, for example, a sea in which the user places fish and sea animals, then those sea animals start to move here and there on the screen: it will be like that.
How can I do this? If you don't know but remember any simple program or demo that does that, it will be also very welcome!
Thank you!
There is, of course, more than one way to do this, but I would say that the best way to do it would be to create a custom View (class that derives from View) and have this handle your bitmap drawing and all of your touch events.
There's a lot of code to write for loading the Bitmaps and keeping track of all of their positions (and then drawing them to the canvas in onDraw), but if you start really small by just allowing one image to be drawn and dragged around the screen, you can build on that and keep your code organized.
You would need to override onDraw(Canvas) and onTouchEvent(MotionEvent) in your custom View. You'll load your bitmaps with BitmapFactory (decodeResource method if you're including your images as resources in your project) and you'll need to remember to call recycle on your bitmaps when you're no longer using them.
In onDraw, you draw your bitmaps to the canvas at a specific location using Canvas.drawBitmap. There are two overloads of this method you can choose from, one that takes the top and left coordinates of the bitmap as floats (and therefore performs no scaling or stretching) and one that takes a destination and source rectangle to perform scaling, stretching and placement.
I always use the latter as it gives me finer tuned control. If you choose this route, you'll want to keep two Rect instances and a Bitmap instance for each image being drawn, update them in the touch events and draw them to the canvas in the draw event.
When something changes inside your view (as in the case of a touch event), call invalidate() method and the framework will know to redraw everything which triggers your onDraw method.
What I'm trying to do is have a background image, for sake of simplicity, lets say it's a picture of the front of a house. Then, I want to have a red ball move from window to window.
**I want to have a background picture, and a picture on top of it.
**I then want to be able to tell the top picture EXACTLY where to go.
How can I do this?
I'm just beginning to learn about animations in Android, and have not yet run across any way to do this.
There are two routes to animation in android: Canvas and OpenGL ES.
I would recommend OpenGL for anything requiring smoothness and speed, like a moving ball.
You should create a view using the helper class GLSurfaceView
http://android-developers.blogspot.com/2009/04/introducing-glsurfaceview.html, and implement a Renderer.
I assume you have the images saved in your res/drawable folders, in a format like png and the ball file contains an alpha channel.
You can see many tutorials online, but basically you need to load your background image and your ball resource at onSurfaceCreated and store it in a texture using GLUtils.texImage2D.
In the onDrawFrame method, you should set up a 2D projection such as glOrtho2D, then draw the background.
Then just before you draw the ball texture, you can use the glTranslate(x,y,0) function to move the ball over the house. Use an alpha blend for the ball:
glBlendFunc(GL_SRC_ALPHA, GL_SRC_ONE_MINUS_ALPHA);
glEnable(GL_BLEND);
Unfortunately writing in OpenGL isn't as straightforward as you might hope. Everything is done with 3D coordinates, despite the fact you want only a 2D image. But hopefully this gives you enough info to google for good exmaples, which are abundant!
I want to draw something at about 30 frames per seconds on Android Canvas or other convenient object for this purpose. In my application different graphic objects are drawn and if any of the graphic object is touched, the graphic object changes its shape. I looked at the
onDraw(Canvas canvas) callback of View subclass but calling invalidate() does not help here: first I cannot control the frame rate and second if the objects are moving too fast, the motion appears jerky.
I personally dislike Android's built-in Animation classes, so I tend to do all animations with Canvas by hand. I have found the most luck with creating a list of the images you want to use in your animation and then an int variable to store the current "frame" you are on. To advance the frame, I create a thread that sleeps for, say, 30 ms and then update the frame variable accordingly. Then in whatever update handler you are using, you can just create a switch statement or something of the like, and draw the respective frame.
It may seem like a lot of work, but it really isn't. Shove it all into a class and you will love yourself for many animations to come.