Animating fragments and the back stack - android

I am having trouble using or understanding how popping
FragmentTransactions off of the back stack handles the custom
animations. Specifically, I expect it to call the "out" animation, but
it doesn't seem to.
I have a simple method to handle a fragment transaction
(FragmentTransaction) where I add a fragment and apply a custom
transition so that it will fade-in/fade-out. I am also adding this to
the back stack so that the user can undo that transaction with the
back button, essentially navigating to the state before the fragment
was added.
protected void changeFragment() {
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
ft.add(R.id.fragment_container, new TestFragment());
ft.addToBackStack(null);
ft.commit();
}
Everything works great moving forward, but when the user clicks the
back button, the transition animations do not reverse. What I expected
was that when the fragment got removed, it would use the fade out
animation. Instead it seems to pop out (without animation) and then
the container seems to fade in. I'm not sure that this is exactly what
is happening, but the fragment is definitely not fading out.
My application uses the compatibility library to add fragment support,
but I assume this to be applicable to Honeycomb (android-11) as well.
Does anyone know if I am just doing something wrong here or if I am
just expecting too much? Ideally, I would like to animate the
fragments similarly to how Gmail (on the Xoom) does in regards to
moving forward by clicking a message and then back by using the back
button. Preferably not having to override the back button
functionality and keep up with my own fragment state since I could
have several "transactions" that I would want to back out of and I am
not a fan of re-inventing wheels.
Also asked on the Android Developers Group: http://groups.google.com/group/android-developers/browse_thread/thread/1136a3a70fa0b6e9

I use this:
ft.setCustomAnimations(R.anim.slide_in, R.anim.hyperspace_out, R.anim.hyperspace_in, R.anim.slide_out);
and the transitions work in reverse when the back button is presses.

The bug was fixed in the 3.2 release with the addition of the following new api:
http://developer.android.com/reference/android/app/FragmentTransaction.html#setCustomAnimations(int, int, int, int)
It's to be noted that it has not yet been back-ported to the compatibility library (as mentioned in the bug report).

It's a bug, look at bug report 15623. One of the Android project members commented that the fix was too late for release 3.1 but it should make it into the next release.
The same member goes on to say that...
The problem is that the same
animations are run on a pop operation
as were run to put the fragments in
their current places. For example, in
the sliding example above, on a
forward operation (pushing the old
fragment onto the stack and moving the
new fragment into view), we slide the
old fragment out from the center to
the left and slide the new fragment in
from the right to the center. When the
stack is popped, these same animations
are run: the most recent fragment is
animated 'out' by sliding it in from
the right to the center (after which
it disappears, since it's being
removed). The old fragment is popped
off the stack and animated from teh
center to the left ... right off the
screen.

Related

Android Studio multiple fragments

I'm designing a music player app and this is my second time working with android studio and fragments in general. I've watched a lot of tutorial videos on this but I'm having trouble getting multiple fragments to show. Maybe using fragments isn't the way of going about this. But basically what I have right now is a fixed menu at the top and 5 fragments just below it (on top of each other).
What I was hoping to do was by clicking each button one fragment would load so you would have one activity but 5 fragments that load when buttons are pressed. But the issue i'm having right now is instead of stopping one fragment and loading another one, they're being loaded on top of each other. Is there a way to go about doing this?
Below is an image of the design I had in mind. The blue box is where the five fragments are and right now they're overlapping. Any help would be appreciated :)
EDIT: Turns out the answer was I needed to define one layout for all of the fragments. Thanks everyone.
Please post code. But here's what I can make out so far from your problem,
I assume you are just using FragmentManager.beginTransaction.add() again and again.
If it is the case please change your code to
FragmentManager.beginTransaction().replace(
containerViewID,
new FragmentYouWantToReplace
);
What this does is removes previous fragment and adds this new fragment.
So you can have your default fragment using add() during activity load, but for each button click you use replace().
When you call a new fragment you should replace always the same layout, the one you want to show the information, like this:
frag_results frag_results = new frag_results();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.framelayout_secundary, frag_results, frag_results.getTag()).commit();

Android Fragment Transitions with GLSurfaceView

I have a GLSurfaceView in a fragment, with this being my main fragment. When I do the transition from the fragment with my GLSurfaceView to another fragment without a GLSurfaceView, the GLSurfaceView moves up a little bit before the transition starts.
I have tried setting the GLSurfaceView.setZOrderOnTop(true), it doesn't work, and it actually does more harm then good in this situation since my ads and navigation drawer becomes obscured.
I have tried hiding the Fragment hosting the GLSurfaceView, still has no effect.
I tried pausing the fragment hosting the GLSurfaceView , thus pausing the GLSurfaceView at the same time, has no effect.
When the GLSurfaceView moves up then the screen is black where the GLSurfaceView is suppose to be. It seems like the black area on the screen is specific to the fragment transitions, since if I remove the transition and simple do the replace with the fragment transaction then the glsurfaceview movement is gone. This isn't a solution though because I want the transitions in my app from one fragment to another.
Lastly, I realize that ondestroyview is being called on the fragment with the GLSurfaceView, thus destroying the view before animating the transition to the next fragment, and I think this may be the problem.
Here is some code...
Adding fragment with glsurfaceview
//clear all fragments from the back stack if there are any
getSupportFragmentManager()
.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
//start a new deploy fragment
getSupportFragmentManager()
.beginTransaction()
.add(R.id.container, new DeployFragment(), "Main Fragment")
.commit();
replacing glsurfaceview fragment with the preference list fragment
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left,
R.anim.enter_from_left, R.anim.exit_to_right)
.replace(R.id.container, new SettingsFragment(), "Settings Fragment")
.addToBackStack(null)
.commit();
When transitioning from the DeployFragment (glsurfaceview fragment) to the SettingsFragment (regular list fragment) the GLSurfaceView moves up a little, maybe about the size of the height of 2 actionbars stacked on top of each other. The glsurfaceview moving up also displays a black area on the screen where the GLSurfaceView is suppose to be, but it is not.
Any ideas how to fix this issue?
VIDEO OF PROBLEM
http://youtu.be/RUSNBd9iuXs
right after choosing an option you see GLSurfaceView move up, revealing black space
The only way to animate transition for SurfaceView is to draw before content to bitmap and set it as source of imageview on top of the layout with surface. But note, because it is big bitmap if it is full screen layout for android 2.x this approach can crash your app due to lack of native heap(not java) so I recommend doing this only for ics+
I think I figured it out. I wrapped my head around this for hours, so I will post what I believe to be a fix, but maybe not the BEST answer. What I found out is that if I use support fragments with the glsurfaceview, and try to animate transition to another fragment then I get the weird problem I describe above in the question and shown on the video.
If I use non support fragments, then this problem doesn't exist there. Using non support fragments comes with a whole lot of other problems so if anyone comes up with a fix to this problem while using support fragments then I am all ears.
problems with using non support fragments
i must at least target api 11 (honeycomb) or higher, as time goes on this will become less of a problem
i am using nested fragments, so I have a choice of mixing support with non support fragments which is nasty, or targeting api 19 or higher to use getChildFragmentManager() with non support fragments, which is also nasty.
i am using the view pager, so looks like I have to again mix support with non support or import fragmentpageradapter for v13, which is compatible for api 13 and up.
Thanks!

Facing issue with setCustomAnimations() while replacing fragments

I have 2 fragments A and B. I am replacing the fragment B with A, and setting setCustomAnimations(right_to_left, fadein, fadeout, left_to_right). Fragment B is behaving correctly like it is coming from right to left and on pressing Back button and do pop back stack it is leaving from left to right. But no animation happens to the fragment A its doesn't fade in and fade out.
Note: I have tried it with creating the sample application and it works perfectly fine but when I implement the same thing into my project it behaves as above. What mistake am I making while implementing the setCustomAnimation() in the my project?
I have already tried:
have a latest support library
hardwareAccelarated="true" in the manifest file
add setCustomAnimation() before replace() method
compile it with above 3.0
I doubt there can be an issue with the framework my app is built on but not sure. Can anyone please let me know what else I can check to make it work?

Android - Temporal & Ancestral Navigation with ViewPager & Fragments

I'm trying to work out the best way to implement the 'ancestral' and 'temporal' navigation (utilising the up button and back buttons), for a music player I'm working on.
Currently, the user is presented with a viewpager, and can page between three main fragments (ArtistMain, AlbumMain and SongMain). Upon choosing an item inside that view, a fragment transaction occurs, and the viewpager goes out of view, replaced by a new fragment (AlbumSub, Songsub or player, depending on where the user came from). The user can then navigate deeper, until a song is chosen, and then they are taken to the 'player' screen.
I guess the question is: How do I implement all of this conditional navigation?
I'm fairly new to android and programming in general, and I just can't seem to come up with an efficient way to achieve this. At the moment, as each fragment is brought into view, the app is checking to see where the user just came from, and then determines where the user should be taken if back or home is called. This means I have a booleans like "fromArtistMain", "fromAlbumSub", and I'm checking for things like "fromSongSub && fromPlayer".. it's all turning into a bit of a mess.
I've drawn a diagram (in paint, sorry!!), to depict the navigation I'm trying to achieve. The yellow represents the 'up' button press, the red is the 'back' button press, and blue is just normal navigation. The green arrows are meant to represent the view paging:
Any advice is welcome. It might take something really simple that I've just overlooked.
Thanks for your time.
Edit:
I have been adding fragments to the backstack, and using popBackStack() calls, the problem is that popping the backstack is not necessarily the correct option in each case.
I've currently got a whole mess of code trying to determine whether a transaction should be added to the backstack in the first place.
Consider the following:
User chooses a song straight from 'SongMain', and is taken to 'Player'. Now using the home button should (in my mind), take the user to SongSub (the list of songs from the album that the chosen song belongs to). Now if the user navigates up again, they will be taken to 'AlbumSub', the list of Albums by that artist. This is a fragment transaction, but adding to the backstack would mean the user would be taken down a level on back press (which I think would be unexpected). So in this case I don't add that particular transaction to the backstack - seems fine, but there are quite a few different cases, and combined with a viewpager at the top which needs to come in and out of visibility, the code gets really messy.
All of this means a whole bunch of conditionals determining where the user came from and which path they took to get there..
Would it be wise to have a bunch of booleans in the host activity which get set depending on where the user has navigated, and then checking those booleans to see if a transaction should be added tot he backstack? This is kind of what I already have, but it seems really inefficient.
What you're looking into is called the Back stack. You can read more about it here at developer.android.com.
If you use a single Activity to host each of these Fragments then you can modify your code to explicity add your Fragments to the Fragment Back stack using code like so:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, fragment);
transaction.addToBackStack("NameOfFragment");
transaction.commit();
So, if you do the above code with Fragments like so:
Fragment1 -> Fragment2 -> Fragment3 -> Fragment4
Then from Fragment4 if you call this method:
getSupportFragmentManager().popBackStackImmediate();
Then Fragment4 will be finished and Fragment3 will restart. Simple. You can have this line called from a button click or you can override the behaviour of the back button to call it.
Please note in the examples I've used the function getSupportFragmentManager() which is a method name in the Compatibility Package. If you're not using the Compatibility Package then you can instead call getFragmentManager().
EDIT
The problem with the navigation you envisage is that breaking out of the backstack paradigm half way through means that your app will "Act Differently" than the rest of the OS. This is by and large discouraged by Google. But then again, saying that, I do exactly the same in my app for very similar reasons :).
When you navigate "up", along one of your yellow lines, you are following a discrete link (so, startActivity(new Intent(this, SongSub)); or whatever) and you want this to "break" the backstack.
It's at this stage you can make a decision about how you want to go forward:
You can start a Task (backstack) using SongSub as 0th item. This is from memory what the Google Music app does and you're right, it's annoying. When you press back it should technically exit the app. Yuk. IMO if you're in an obvious page hierarchy, back should always navigate down the hierarchy over exiting the app.
You can start a new Task using ArtistMain as the 0th element and layer fragments discretely ontop before commiting your transaction, in effect creating a new backstack each time you go "up" rather than "back" (your backstack would now be ArtistMain->ArtistSub->SongSub). This is what I think your trying to ask here. It's possible but it's messy.
You can create a more linear structure (probably the best idea if possible). Ignore the backstack paradigm, make "back" and "up" always go up a level no matter where you came from (Player always goes to SongSub, SongSub always goes to AlbumSub). This will give the user the least confusing and most transparent (as well as easiest to implement) experience - the user will learn quickly how to navigate (and how many "backs" to press) to get to where they want to be.

android fragment animation using compatibility package

How can I use animation for transitions between fragments ? I tried
FragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
FragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left,
android.R.anim.slide_out_right);
changing the animation to different kind of animations, but it always seems to animate like fading-in while pushing fragment and fading out while popping fragment.
I know this question is very old, but I stumbled upon it while looking for an answer to this myself.
I'm currently using animations in my compatibility package, fragment based app, and it's actually quite simple.
Add this before actually adding / replacing the fragments:
FragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left,
android.R.anim.slide_out_right, android.R.anim.slide_in_left,
android.R.anim.slide_out_right);
Your new fragment will slide in from the left on push, and slide out to the right on pop.
Of course this also works for other default animations, or custom animations.

Categories

Resources