I have an activity which starts with a number of invisible views. I then use handler.postDelayed to make every view visible again with a slide animation and the BeginDelayedTransition method. Normally all the views should slide in, one after another. Anyway i noticed that depending on the time interval between each runnable and even depending on the device i test the app on, some of the animations are totally skipped and the view just appears without any transition. I think it may be related to the time it takes to beginDelayedTransition to calculate the changes in the visibility thus instantiating the correct animation.
Is anyone experiencing the same problem? Is there any workaround for this, other than calling a TranslateAnimation every time?
Thanks in advance!
Related
I am working on animating custom Views for my Android app. I have accomplished this via Property Animations and calling invalidate() on the View in the onAnimationUpdate() callback, as per https://developer.android.com/guide/topics/graphics/prop-animation.html:
Depending on what property or object you are animating, you might need to call the invalidate() method on a View to force the screen to redraw itself with the updated animated values. You do this in the onAnimationUpdate() callback.
My problem is that when these animations are run at the beginning of a newly launched Activity, they skip frames at the beginning, causing them to jump very noticeably. I have tried both:
Starting the animation immediately from the Activity's onCreate() method
Starting the animation upon the OnGlobalLayout() callback using the ViewTreeObserver of the Activity's root view.
I did the latter since I thought maybe the animation was invoked before the layout had been finalized, but the result is the same.
With logs, I determined that the onAnimationUpdate() callback is called consistently throughout the animation (that is, every 10-20 ms or so, from start to end). onAnimationUpdate() simply calls invalidate(), which should force the View to redraw itself, ideally immediately (but the documentation only claims this happens "at some point in the future"). That seems to be precisely the problem: onDraw() is only called once or twice at the very start before not being called for about 250 ms. After this, it resumes being called every 10-20 ms, as it should have the whole time. But that block of time causes very noticeable lag in the animation.
To be clear, this problem only happens at the beginning of the Activity. If I simply set a 300 ms delay before starting the animation, it runs smoothly all the way through. But I don't like that solution, since it's hacky. It seems the problem is that onDraw() is not called immediately upon invalidate() near the beginning of the Activity. But, I can't figure out why this is, what's blocking onDraw(), or how to fix it at all.
I found only this StackOverFlow thread: Animation at the beginning of activity skips frames where the poster has the identical problem. The basic code is there and the videos make the problem clear. I can post my code too, but I think that the fact that the problem appears in the most basic test app shows that there's something else going on.
Since there are no codes attached, I'm assuming you have some transition animation to the activity. If this is the case, it might cause the problem.Since there are two animations running simultaneously. Disable the transition and give it try.
startActivity(intent);
getActivity().overridePendingTransition(0, 0);
It sounds like your draw loop UI thread is getting starved.
I'd use traceview to be sure that there aren't any methods blocking your draw calls. http://tools.android.com/tips/traceview
This should help you determine what's being invoked instead of the onDraw method.
So there are a few questions about animations not ending when using cancel() on them. You also need to call clearAnimation on the view. Can someone explain why is that? It's also very strange to me, that the View needs to know about what animates it.
You call clear animation to reset the transformation matrix that the view is using to transform its canvas during the animation. The main problem is that old Android animation system is a crap since it relied on animating a "snapshot" of the actual view.
As for the cancel, when you invoke cancel what happens is that you stop the runnable that is applying the steps of your Animation. Of course you cannot be sure in which state your animation is getting stopped
To be clear:
The View Animation Framework , a.k.a "old animation framework", only animates the translations of the view, and not the actual properties. So lets say you animate the view's location on the X dimention: the value of the view's X property remains the same.
In relevance to your question, this means that canceling the animation draws the view back in its original position. So it doesnt matter when did the animation was canceled.
Object animation, introduced in Android 3.0, animates the actual properties. This means that when you cancel the animation, the view remains in its relevant position. So you might not know exactly WHEN was the animation canceled, but you can clearly find out WHERE is it drawn right now.
If you need object animation for older versions of Android, and frankly why go any other way, you can use the 9OldAndroids library.
Mor on the difference between the animation frameworks here.
This has been bugging me for a few days now. I have a FrameLayout and one of the elements within the layout moves to reveal a menu. I can paste the code if requested, it's a bit long since it's my play code and I haven't used any styles. I digress...
When the user presses a particular button it calls a startAnimation on a custom LinearLayout which is layered on top of another stock LinearLayout. Pushing the button again will put the custom LinearLayout back to it's original location, thus hiding the menu.
I had to create a custom LinearLayout to override onAnimationEnd so the layout would stop and stay at the final animated position (I found this based on some other questions asked here on StackOverflow).
The problem arises when the user actually presses one of the visible menu items. One of the items, for example, sorts or reverse sorts the displayed list. It appears that right after I call notifyDataSetChanged on my BasicAdapter the screen redraws itself and my menu is hidden. I have no code that closes the menu, it's almost like the entire Activity is re-created or reset when the list is told to redraw.
I should also point out that I'm extending an Activity not a ListActivity. I'm targeting API 10 (Gingerbread, 2.3) and up.
If any one has any pointers, I would greatly appreciate it. I've been wracking my brain on this for days now and it's driving me crazy. Please let me know if I can provide any more info.
EDIT:
Here's the SO post about overriding the onAnimationEnd method.
Android TranslateAnimation resets after animation
Do you record which item's menu has been opened yourself? If not, then it means that you let the UI system do the remembering for you, which would mean that this information would be lost or rendered useless (since you have changed the item ordering), so all the items reverts to their initial states.
The solution is to associate the menu opened/closed state with each data in the list, then when the adapter's getView method is called, you can rebuild the correct UI state.
I have an AnimationSet that does 3 different animations.
After the animations end, I would like to pause the app for 3 secs, before everything snaps back to start position.
How do I do that ?
Well, there is a animation.hasEnded() function you could use to test if the animation has finished. When that returns true, you could use a java timer to schedule a task after however many milliseconds you want to wait. AnimationSet also has a function to get the duration of the Animations.
Take a look at...
Animation
and AnimationSet
I think you could probably achieve this effect somehow with an AnimationListener Set one to get a callback when your animation ends and add a delayed runnable that will move everything back to the proper position for you. However I think it might get somewhat convoluted to do it this way since it would require setting fillAfter to true, then manually placing your Views in their original position inside your Runnable thats gets posted with a delay.
I think a more straightforward solution to get the same effect is to simply add a 4th animation to your set that has a delay to make it start after all of the others are complete. Make this 4th animation last for 3 seconds, and make it have no visible effect (i.e. grow by 0%). That should build in a 3 second pause for you and still handle moving all of your Views back to their original position (without the need to do it manually). With this solution you'd leave fillAfter set to false, and that would cause your Views to "snap back". By adding another animation that lasts for 3 seconds but has no visible effect it will seem like a pause to the user.
I have implemented a ViewPager in my app, and aside from the swipe paging, I have buttons for "Next" and "Back", with a simple onClick method with the only line being a setCurrentItem for the ViewPager.
While the paging animation is completely smooth during swiping, it is more or less instantaneous (just flips instead of scrolling) when I click Next or Back. There is no visible "scrolling" motion, or sometimes barely visible, however not even close to smooth. It does not hurt the usability of the app in any way, since the transition still happens immediately, but visually it looks a lot less appealing, and the user experience suffers.
Now, I suspect it has something to do with the app drawing the next View and therefore "skipping" the animation. My instantiateItem uses LayoutInflater and a simple switch statement to inflate each view (4 pages at most), and I am loading custom ListViews inside each case in the switch statement. The custom ListViews are at most 3 items long, with a TextView and an ImageView in each row (ImageView resource is 5kb in size). To me it seems this amount of objects should not be reason enough to slow down the paging animation.
Aside from that, I also have a custom background assigned to my app in styles.xml, and this is the background used through every activity (160kb in size).
Those are the only things that I think could be slowing down the app, since the onClick method contains only one line (setCurrentItem), so nothing aside from going to the next view is happening in the app, and the instantiateItem is the simplest implementation of the method possible that I know of.
Things I've tried:
Setting the ViewPager's setOffScreenPageLimit to 4, which I thought would pre-load the views and eliminate any loading in between paging, but in the end setting it to 0 seemed to make the thing slightly more likely to show at least a frame of animation
Optimizing the custom ListViews by using convertView to reuse old views, while it did result in more of the animation being shown, it still wasn't completely smooth, varying from "almost perfect animation" to "instant flip"
Removing the custom background, which together with the above two fixes lead to an almost good enough solution, but still resulted in flips every few steps.
The tinkering described above leads me to believe it has something to do with the views being loaded, but I've not found a good solution for pre-loading these to the desirable effect.
Knowing my newbie programming skills, I know there is a sure fire way to solve this without resorting to gimping the design of the app itself, but reading through the documentation, Stack Overflow questions, Googling for advice, I've just ran out of places to look to.
To sum up this probably too verbally descriptive post my main questions are:
Is there a way to ensure the animation of the ViewPager is executed smoothly? A separate thread perhaps? As I understand though, UI stuff should only be on the main thread, where it already is, and nothing else aside from the view loading is executed anywhere in the code when paging.
Should I be using a different way to load the pages? Would Fragments help?
Thank you for any advice.
ps. The lack of code is due to the methods in question being the most basic implementations possible, but I will provide the code if necessary.