In the Honeycomb sample gallery app, there's a layout that uses a two-fragment setup: one on the left of the screen showing titles, and one on the right showing the selected content. The titles fragment can be hidden with an animation.
During the hiding animation, the app asks the framework to recalculate the layout on every single frame. This way the content-fragment can take up the empty space that the titles-fragment leaves behind while it moves off-screen. This produces a great, dynamic effect, but is terribly inefficient I think.
I have fairly complex layouts, and I'd rather not ask the system to re-layout on every single frame. But I'd like a smooth transition animation like in the sample. Are there any alternative solutions to this problem?
P.s.: Just to be clear, I'm not asking how to do basic fragment-transaction animations. I know those, and AFAIK, those animations can't produce the behaviour found in that sample gallery app (another example would be the Honeycomb Gmail app, it has similar transitions that I'd like to achieve).
You can provide custom animations to the fragment system that do whatever you want. You can move the fragments around, fade them, etc. If these animations do not explicitly or implicitly cause layout (by changing properties that trigger a layout), then you should not get a layout on each animation frame. There maybe still be a layout call at the beginning/end as the fragments are added/removed, but the layout/invalidation process during the animation is up to your animations and what they do.
Related
I'm using a 3rd party drawer that allows bottom- and top-edge drawers (https://gist.github.com/patrickfav/6284130 MultipleOrientationSlidingDrawer).
When I animate opening of the drawer, I get display tearing but only under particular circumstances. When the drawer header is clicked, animation is smooth and beautiful.
I have a RecyclerView in the main window. If users click on an entry in the list view, the drawer slides open showing details of the entry selected (click on a track, slide the media controls up from the bottom). Part of the drawer animation is to fade the main window contents to black as the drawer opens. So there's heavy overdraw going on. Oddly, when the animation is triggered from clicking in the RecyclerView, I get tearing of the display during animation (serious flickering, occurring about 2/3 of the way down from the top of the screen).
I'm looking for advice as to how to proceed: how to debug, or theories as to what might be causing flickering of the display during animation.
Here's what I've tried so far.
Initially, I though this was caused by RippleDrawable animations in the RecyclerView entries (both on the press and an activition change that is used to indicate selection. To prevent this, I've tried to cancel the ripple animations by calling recylerView.jumpDrawablesToCurrentState() at various points (start of animation, as well as during every animation update). As far as I can tell, the RippleDrawable animations have been effectively cancelled. But the display ripping still occurs. Things are a bit complicated. State change animations don't get triggered until after a dispatch of some kind occurs; but the call to startAnimation also doesn't appear to occur until after drawable state changes are complete. So I think I've done this right. Just in case, I've tried calling recyclerView.jumpDrawablesToCurrentState during each animation pass, which certinly should cancel the drawable animations. Still no joy.
I have deferred responses to the click itself until the drawer open animation completes, so there are no major background or foreground operations going on while the animation occurs. Also no audio running, no service activity to speak of. Profiling indicates that there's no code running that isn't related to drawing while the animation runs.
Since everything happens relatively quickly, it's hard to tell exactly what's happening, other than that there's serious flickering going on. Since there's an animation involved, there's no way to break to the debugger in the middle of the animation to see what's going on. Once I break to the debugger, the next redraw will be fully-open state, since the animation positions derive from the current device uptimeMillis().
If I profile the animation, I see an awful lot of text layout operations, which kind of suggest that the recycler view entries might be constantly performing layout during the animation.. Which doesn't really make sense. There's no reason I can think of for layout to occur. It could just be that the text calls are related to onDraw operation. But I mention this because what I did see in profiling seems a bit odd. The majority of CPU time during the animation seems to be spent performing text measurement operations, presumably for content in the RecyclerView entries.
There is heavy overdraw occurring. The drawer itself has a large bitmap containing album artwork, And it's possible that I may have stacked up semi-opaque layers and backgrounds. e.g. the RippleDrawable backgrounds on individual entries in the RecyclerView could very well cause a complete overdraw pass for most of the screen. In addition, there is a complete overdraw pass for the view that dims out the background content as the drawer animates into open position. That being said, the drawer animates beautifully when the animation is triggered by clicking the header of the drawer. Just not when the click that starts the animation comes from the RecyclerView. So I don't think overdraw is really the problem.
For what its worth, the location of display ripping seems to be independent of where the selection and press occurs. Clicking first or last entries in the RecyclerView doesn't affect where the display-ripping occurs.
ADB shell dumpsys SurfaceFlinger indicates that hardware composition is being performed on three layers (status bar, navigaton bar, and main activity). So the drawer itself is not using SurfaceFlinger composition (which would, if it were happening at least point in the general direction of what's causing tearing of the display). However, I can't really get the SurfaceFlinger state while the animation is running. It's possible that hardware compositing is being used during the animation. It sure looks like display ripping, and I can't think of why ripping should occur if SurfaceFLinger isn't doing the compositing.
I'm completely mystified as to what the problem might be, or approaches to try and debug this. Any suggestions as to general debugging approach, or suggestions as to what the cause of the problem might would be much appreciated.
On what layer is the described tearing happening? Is it on the drawer itself, or on the layout behind the drawer?
Either way, I have a couple of suggestions:
Overdrawing can be glitchy at times, especially with complicated layouts - I have run into issues with it specifically on GoogleMaps Fragments. Something that resolved this in my case was creating a simple transparent overlay to cast the overdraw on, like so:
<FrameLayout for drawer....>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent" />
<LinearLayout w/ fragments etc..../>
</FrameLayout>
Drawer Animations are notoriously bad for their intended purpose... they will lag like crazy during layout transitions. I know you said you made sure the drawer animation finished before doing anything, but that is something worth double-checking. I personally put all of my navigation code in the OnDrawerClosed() method for this reason, and use the itemSelected() code to set a flag and close the drawer.
I am trying to figure out how to handle this UI feature where I want to make a ViewPager just appear over everything, scroll through the page items, and then when you press back it goes away. Normally I would just use a full screen dialog for this, but I want to apply a combination fade animation (fade in on appear and fade out on disappear) as well as a scale animation (scale up from nothing to fullscreen on appear and scale down from fullscreen to nothing on disappear).
Dialogs seem to be a lot less animation friendly based on the Dialog and Animation interfaces compared to Views. Then again, I don't know how to make a View just sit on top of everything since that's normally what Dialogs are for. Seems hard to tell which is the lesser evil, but I could potentially benefit more from having a full screen View over everything else. What would I need to do?
Edit: A point brought up by #sound-conception I should make clear, that sadly due to the application context for this feature, making this a separate activity is not an option right now.
You state in your question that the ViewPager will be a full screen view. In that case you could implement the ViewPager as a seperate Activity and use Activity Transitions.
Check out this Google I/O developer video on Activity Transitions.
There's also lots of info on the Developer Website
I need to design introduction walk-through screens when my app launches. It can be done by simple ViewPager or horizontal scroll view (?) but the additional requirements which are hindering me from using these are
A lot of animations on each screen
Animations will be bound to scroll position (i.e., current stage on an animation will be determined by how much user has scrolled, and it should roll back animation if user scrolls back without finish gesture)
Some items need to animate across different screens (e.g., There is a box on first screen, when user scrolls to the next screen, the box becomes larger without moving and a graph (a part of second screen) also comes into display under it)
I dont know if I explained the scenario well enough so please ask for clarification in comments. I need just a direction to control/approach/library.
Thanks
I'd recommend this library : ShowCase
In this way, you can make interactive tutorial and walkthrough your app.
You can also take this library and add some functionality.
Use viewpager, for each fragment you can use different animation inside that fragment, each fragment is independent from other views/fragments
You can use horizontal scroll view but it will take extra time and difficult to code
Seems like a ViewPager has everything you need.
I was recently using the app Secret and was observing the amazing user-interface that it has. If you are opening Secret's webpage, please scroll down a little to see the UI.
Being someone who is still a novice in Android and wants to learn, I would like to ask how that UI has been designed. I could ask a lot many questions in this one post but I will limit myself to just one for now.
Whenever you click on one of those tiles, it opens up and shows the comments for that particular tile. The other tiles below and above disappear. When you click on the tile again, it smoothly animates back to its position and the tiles above and below come into view. How is this achieved?
What have I tried so far? Nothing, because it is a "where do I begin?" question.
This is probably an instance of a custom activity transition (and a particularly well polished one).
In general, you can use the overridePendingTransition() to specify an animation that must be run when the current activity is changed (a classic example is sliding in a new Activity from a direction, while the previous Activity exits in the opposite direction). However, these transitions generally do not share UI elements.
Chet Haase has done a few DevBytes (in particular this one) to "simulate" an activity transition that shares an UI element (i.e. a view) between the caller and called activities. For example, if you have a Gallery, and you click on an image to show it full-screen, you would probably want the image to "grow" smoothly until it occupies this new position. The trick to achieve this is to actually disable the standard transitions entirely and include in the Intent used to start the activity the information about the current position and dimensions of the view that you want to "share":
Intent subActivity = new Intent(this, PictureDetailsActivity.class);
subActivity.putExtra(PACKAGE + ".left", screenLocation[0]);
subActivity.putExtra(PACKAGE + ".top", screenLocation[1]);
subActivity.putExtra(PACKAGE + ".width", v.getWidth());
subActivity.putExtra(PACKAGE + ".height", v.getHeight());
startActivity(subActivity);
overridePendingTransition(0, 0);
Therefore, the new activity can extract this data, and with this information and the knowledge of where on the screen the view should end up, can build and execute an animation that simulates the desired effect.
This technique can be difficult to implement if you want a complex animation, so in Android L this was baked into the platform itself: Activity Transitions can handle this automatically and provide a few built-in animations to act on the remaining (i.e. non shared) views. For example, the explode transition seems to be very much like the one you describe.
Regarding layouts:
You might find it helpful to use hierarchy viewer, which offers a function to capture the layers of the UI and store them in a Photoshop file. This gives you a good idea how the layout of a particular app you are was created and what kind of views were used.
Regarding animations:
Checkout videos by Chet Haase and Romain Guy who discuss graphics and animations in detail.
You can start with the Android training guides.
This one is an overview of designing with media and animation, but this one uses a ViewPager to achieve the effect you want.
I'm trying to find out what technique I have to use with my intended approach.
I have a layout that should consist of 3 parts: a top and right part that stay the same and a left part that can change in runtime. When the user decides to change this left part, it should display another layout at that location.
So far I've found these approaches:
ViewFlipper
Not really what I'm looking for since it's used by sliding your finger to the side instead of pressing a button
ViewPager
Seems to be pretty much the same as the ViewFlipper.
ViewStub
Can only be used once so not a viable option (I want the user to be able to change back and forth).
Sadly, none of them do the job (unless I have misinterpreted something). Is it even possible to do what I want?
If it's something not too complex, you could go with ViewAnimator.
For something more advanced Fragments are the solution.
Note: You could call setDisplayedChild() on a ViewFlipper to programmatically switch between views.
You could also call setCurrentItem() on a ViewPager (which by the way can use Fragments).