I'm working on an app where I must have on a part of the screen an animated music staff. That's:
5 static lines
A dozen of music notes (each one is basically an oval and a line)
A few additional symbols (clefs)
I must have a precise control of the size of each element, and have to smoothly animate position and alpha of the notes and clefs so the notes are moving right to left (disappearing when on the left of the screen, and appearing when on the right, hence the alpha). I also have to change sometimes the color of the notes.
I think I can't use standard "Animations" class, as it's an endless animation with the speed and the notes depending on real time factors.
So what is/are the best way(s) to do that and to achieve a smooth animation?
Different Views? (VectorDrawables?) Single SurfaceView where I manually draw each shape at each frame? (or TextureView?)
(Note: minimum API is set to 15)
Thank you for helping me choosing the right technique.
So you're wrong about the Animations class being infinite. It doesn't need to be. However EVERYTHING in Android will depend on real life factors- Android is not a RTOS (real time OS), there is no guarantee of execution time.
However, if you absolutely need total control, I would just jump to total control- hook the Choreographer so you get a call every 1/60th of a second, and each frame invalidate your view(s) that need to change and redraw them. If the phone is running slow for some reasons like other apps you may drop a frame or run slightly slower than 1/60th of a second, but this is as close as you can get (and what Animation classes use behind the scenes).
With animators you can animate smoothly around 5 different views on average phone. So in your case (with dozen of notes and so on) it will have around 10fps. So slightly better will be SurfaceView and handdrawing all that you want. Maybe GLSurfaceView worth considering.
In order to test this I recommend you to create some test app first, where will be 10 views flying around, and look at performance.
Related
I have a base layout that holds several views. I need to translate them along the x axis. Basically there are 2 types of translations happening the one that follows the finger all the way and the one that stops after certain threshold which gives a nice parallax-like effect.
So is it better to put the group of views that share same translation logic inside another container and translate the container or translate each view individually?
I know this might sound weird but Google always recommends to use flat view hierarchy because nested layouts are expensive to redraw, so does it mean that keeping just one layer of nesting and translating each view by hand is better?
Also this translation is applied to all the views in the RecyclerView, not just one.
I think you should keep a flat layout as Google recommends, and translate each view individually. I would create a custom view were you can set a threshold. And once set, you can simply pass the x position of the finger to them all, and they'll decide if they should move or not.
How to implement it requires more input or requirements before giving any suggestion. Besides performance problem, code maintainable should be considered too.
Base on my experience. With high-end phone and high API level (about >= 21), they have better hardware, effective way to manage memory and background task. The problem expensive to redraw you mentioned seems not too important with some simple animation. In this situation, code maintainability has higher priority, I will decide to have an extra FrameLayout container, wrap the View which have the same animation because you have less code => less logic. 0 or 2 FrameLayout have no noticeable difference in performance in this case
About low-end devices, if you want to target lower API users, performance becomes a top priority. Now both cases you mentioned have the effect on performance, one requires more memory to store more View and one requires more CPU to run animation. It's time for a trade-off. In your case when you have 2 translate animations run on any item in RecyclerView, I prefer to create 2 separate animations run on 2 View. This way I can save a bunch of extra containers => save memory, the animation is not run for all of the items so it only affects the CPU for a small amount of time during animation.
So to sum up, You have a different approach for each case, choose a top-priority for the case you choose, improve it, sacrifice the others that have less effect on the overall problem. No solution is 100% perfect, trade-off situation always happens when coding
I am using LibGdx to develop a game. For Now I am not using scene2D. I am struck up in increasing the levels of the game as I do not have the scrolling screen.
I like to design a a scrolling screen as it is in many games which are level based (for ref, lets say Candy crush). Could you please point me a example on how to have such a scrolling screen to show a bigger area where I can show many levels.
Thanks is Advance !
Using the Scene2D function is not necessary for this and is more for GUI implementation and different screens. The Scroll pane really shines when creating reading content that does not fit your phone. I do advice to start learning Scene2D to create MenuScreens and UI though.
What Candy Crush "simply" does is having multiple backgrounds that are placed next to each other and tile seamlessly. They use buttons in the correct place for levels. By dragging a finger across the screen the camera will move in that direction. For the movement from one level to the next there is probably something like a spline in play.
It is important only to draw the background tiles and buttons that are actually visible on the screen if you have many. Since these have fixed positions and you know your camera area and position you can calculate what to draw and what not. Just drawing everything each frame is likely to slow down your fps.
You can do a search on:
Tilemaps, for you backgrounds but you probably want them in just one direction so a simple 1D array would suffice.
Dragging, to move your camera. Here I gave a basic explanations on how I do it.
Splines, are a bit tougher and you do not really need them. They could be used to animate or move something along a curve.
Thats all, expecting you know how to create something like a button (click a sprite).
Currently I am doing app allowing user to draw. Simple think, just extend Canvas class and most of the thing is done.
That was my initial thinking and idea. But as the canvas is rather small because this is only what user see on the screen there is not much possible space to draw. Going through documentation I found translate() method allowing me to move canvas. What I did find out is when I move it, there is some kind of blank space just as you would move piece of paper. I understand that this is totally normal, as I've said before - canvas is only "the screen".
My question is - is there a possibility to make something like infinite canvas so you can make a huge painting and move everything around?
Before this question I was thinking about two things how something like this can be done:
Move all objects on canvas simultaneously - bad idea, because if you have a lot of them then the speed of moving is very bad.
Do something similar as it is done in ListView when you move it (or better see on the screen) only views that are on the screen together with one before and one after are loaded to memory and rest is uploaded dynamically when needed. I think this is the best option to achieve this goal.
EDIT:
Question/answer given by Kai showed me that it is worth to edit my question to clarify some of the things.
Basic assumptions about what can be done by user:
User is given opportunity to draw only circles and rectangles with some (around 80%) having drawable (bitmap) on them on canvas.
I assume that on all screens there will be maximum 500-800 rectangles or circles.
First of all thinking about infinity I was thinking about quite big number of screens - at least 30 on zoom 1x in each side. I just need to give my users bigger freedom in what they are doing.
On this screen everything can be done as on normal - draw, scale (TouchListener, ScaleListener, DoubleTapListener). When talking about scaling, there is another thing that has to be concerned and connected with "infinity" of canvas. When user is zooming out then screens, or more precise objects on the invisible "neighbours" should appear with proper scaling as you would zoom out camera in real life.
The other thing that I've just realised is possibility of drawing at small zoom level - that is on two or three screens and then zooming in - I suppose it should cut and recalculate it as a smaller part.
I would like to support devices at least from API 10 and not only high-end.
The question about time is the most crucial. I want everything to be as smooth as possible, so user wouldn't know that new canvas is being created each time.
I think it really depends on a number of things:
The complexity of this "infinite canvas": how "infinite" would it really be, what operations can be done on it, etc
The devices that you want to support
The amount of time/resource you wish to spend on it
If there are really not that many objects/commands to be drawn and you don't plan to support older/lower end phones, then you can get away with just draw everything. The gfx system would do the checking and only draws what would actually be shown, so you only waste some time to send commands pass JNI boundary to the gfx system and the associated rect check.
If you decided that you needs a more efficient method, you can store all the gfx objects' positions in 4 tree structures, so when you search the upper-left/upper-right/lower-left/lower-right "window" that the screen should show, it'll fast to find the gfx objects that intersects this window and then only draw those.
[Edit]
First of all thinking about infinity I was thinking about quite big
number of screens - at least 30 on zoom 1x in each side. I just need
to give my users bigger freedom in what they are doing.
If you just story the relative position of canvas objects, there's practically no limit on the size of your canvas, but may have to provide a button to take users to some point on canvas that they are familiar lest they got themselves lost.
When talking about scaling, there is another thing that has to be
concerned and connected with "infinity" of canvas. When user is
zooming out then screens, or more precise objects on the invisible
"neighbours" should appear with proper scaling as you would zoom out
camera in real life.
If you store canvas objects in a "virtual space", and using a "translation factor" to translate objects from virtual space to screen space then things like zoom-in/out would be quite trivial, something like
screenObj.left=obj.left*transFactor-offsetX;
screenObj.right=obj.right*transFactor-offsetX;
screenObj.top=obj.top*transFactor-offsetY;
screenObj.bottom=obj.bottom*transFactor-offsetY;
//draw screenObj
As an example here's a screenshot of my movie-booking app:
The lower window shows all the seats of a movie theater, and the upper window is a zoomed-in view of the same theater. They are implemented as two instances of the same SurfaceView class, besides user input handling, the only difference is that the upper one applies the above-mentioned "translation factor".
I assume that on all screens there will be maximum 500-800 rectangles
or circles.
It is actually not too bad. Reading your edit, I think a potentially bigger issue would be if an user adds a large number of objects to the same portion of your canvas. Then it wouldn't matter if you only draw the objects that are actually shown and nothing else - you'd still get bad FPS since the GPU's fill-rate is saturated.
So there are actually two potential sources of issues:
Too many draw commands (if drawing everything on canvas instead of just drawing visible ones)
Too many large objects in the same part of the screen (eats up GPU fill-rate)
The two issues requires very different strategy (1st one using tree structures to sort objects, 2nd one using dynamically generated Bitmap cache). Since how users use your app are likely to different than how you envisioned it to be, I would strongly recommend implementing the functions without the above optimizations, try to get as many people as possible to do testing, and then apply optimizations to each of the bottlenecks you encounter until the satisfactory performance is achieved.
[Edit 2]
Actually with just 500~800 objects, you can just calculate the position of all the objects, and then check to see if they are visible on screen, you don't even really need to use some fancy data structures like a tree with its own overheads.
Basically, I am making a rectangle that represents charge on your weapon. I want a green rectangle to advance over a red one after a certain amount of time. My issue is the timing. I have no clue how to do any timing anything in android.I'm fairly new so don't use too many things I might not understand. All of this is within a view. I researched threading and handlers, but just got confused.
Check out View Animations if you want to support pre 3.0 without using a library. OR Property Animations if targetting 3.0+ is ok.
I have more experience with the View Animations and I can tell you that the Scale animation is the one you'd be looking for. Make your X scale to 100% its size perhaps would get the job done.
Currently I have a cartoon character that takes up almost the full screen of a surfaceview, and my little app is only to animate this 2D character during ontouch event at different coordinates.
What I am doing now is to redraw the whole character every single time, and this way I need to have a specific graphic for every single frame.
I am just wondering if its better to split the character into different parts, e.g. heads, hands, legs, and whenever a ontouch event happens, I only need to re-draw the specific part?
What do you think the pros and cons would be? Is it less CPU intensive?
This really comes down to how your images are set up.
Having a single image taking up the whole screen means that every frame has to redraw the whole screen, something which an android device should be capable of doing. If you break your character into different parts it may look as if you only have to redraw a small part of the screen but if you just redraw one part around then it will still be in its old position unless you draw over it meaning you may have to do a full redraw anyway. Sometimes you can be clever and work out what areas of the screen need to be redrawn and then only redraw those but this can get very complicated.
Another think worth thinking about is memory usage though, if you have a large number of full screen images in memory some phones may not have enough available memory and may crash. By breaking the image up into small parts you should reduce the chance of this.