I'm currently experimenting with shared element transitions with fragments and have the basic idea working. I have two very similar screens (see screenshots), and the shared transition works for the form, but the two buttons (login/social) do not gracefully transition, they just disappear when exiting, and reappear when entering. Is it possible to specify to these two view items to fade out and fade in during transitions?
Fragment A
getActivity().getSupportFragmentManager().beginTransaction()
.addSharedElement(btn_next, ViewCompat.getTransitionName(btn_next))
.addSharedElement(et_email, ViewCompat.getTransitionName(et_email))
.addSharedElement(ll_form, ViewCompat.getTransitionName(ll_form))
.replace(R.id.fl_content, new LoginFragment())
.addToBackStack(null)
.commit();
Fragment B
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
So after a bit more digging, I've learned that the non-shared views are referred to as transitioning views as stated here at AndroidDesignPatterns.com
A content transition determines how an activity’s non-shared views (also called transitioning views) enter or exit the activity scene.
and found on another article from the same website
setExitTransition() - A’s exit transition animates transitioning views out of the scene when A starts B.
setEnterTransition() - B’s enter transition animates transitioning views into the scene when A starts B.
setReturnTransition() - B’s return transition animates transitioning views out of the scene when B returns to A.
setReenterTransition() - A’s reenter transition animates transitioning views into the scene when B returns to A.
So this simple one line solved my problem.
setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.fade));
Related
My main fragment has too many views to load because the lines of code in the file are increasing. To avoid this I decide to separate views using a child fragment. So now upper views are in the child fragment and the remaining bottom views are in the main fragment. Till this ok.
Now I am opening a new fragment by clicking one view from the main fragment. When I came back to the main fragment it is reloading the child fragment because of that I am getting NullPointerException and the app crashed.
Following is the way I am adding child fragments.
childFragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commitAllowingStateLoss()
For more understanding.
I am using Navigation with BottomNavigationBar.
How to avoid this?
In some cases, fragment views are flickering when back to that fragment. How to avoid that?
For your first question you want to avoid putting the fragment in the backstack.
childFragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)//<-- Here
.commitAllowingStateLoss()
For your second question Fragments are destroyed to conserve memory,typically happens when you can't see it. As such the recreation process could take some time, depending on how heavy the view is, thus the blinking.
The only way to stop it from blinking is to make sure the Fragment isn't doing so much that it can't seamlessly load back in.
You could do this by lazy loading your more heavy views, like lists, videos, and large images.
You could also look into Fragment transitions. These could visually smooth out the process of loading.
Here is a great source for some standard animations.
Fragment transaction animation: slide in and slide out
I'm attempting to implement a shared element transition where I share some text from one fragment to another. The actual shared element animation worked fine until I attempted to combine it with a Fade transition. Now the shared element is being hidden behind the other fading content and is only visible once the fade finishes.
I'm animating from fragment A to fragment B.
In fragment A, I'm setting the exitTransition property in onCreate like so:
exitTransition = Fade()
In fragment B, I'm setting the enterTransition property in onCreate as well:
enterTransition = Fade()
The actual shared element transition is being triggered in the containing activity:
supportFragmentManager.commit {
replace(R.id.fragmentContainer, FragmentB.newInstance())
addSharedElement(sharedView, "transition_name")
setReorderingAllowed(true)
addToBackStack(null)
}
The animation used for the shared element is being set in onCreate of fragment B:
TransitionSet set = new TransitionSet();
set.setOrdering(TransitionSet.ORDERING_TOGETHER);
Transition changeBounds = new ChangeBounds();
changeBounds.addTarget(R.id.logo);
changeBounds.addTarget("logo_transition_name");
set.addTransition(changeBounds);
ChangeTransform changeTransform = new ChangeTransform();
changeTransform.addTarget(R.id.logo);
changeTransform.addTarget("logo_transition_name");
set.addTransition(changeTransform);
Transition textSize = new TextSizeTransition();
textSize.addTarget(R.id.logo);
textSize.addTarget("logo_transition_name");
set.addTransition(textSize);
sharedElementEnterTransition = set;
What am I missing?
Here's a gif for reference:
Ultimately I managed to fix this issue by setting a scale on the logo TextView that was transitioning.
To elaborate, my understanding from previous stack overflow answers written by George Mount is that the ChangeTransform transition will (kind of magically) handle reparenting a shared element view such that it won't get drawn over by another view.
After debugging the ChangeTransform transition, I found that its createAnimator method was never being called. It looks like that's because the view being shared didn't have any scale or rotation changes between the fragment A and fragment B.
Setting a scale of 0.99 on the logo TextView in fragment A lead to the createAnimator method being called and the view properly transitioning over other views instead of under them.
I suspect that since people are normally sharing imageviews that theres normally a scale difference between the two images so this problem doesn't show up as much. I could be wrong about that.
I have two fragments - A and B - both fragments take up the entire screen. When I load my activity I show the user fragment A while in the background I load fragment B (in the fragmentmanager I do replace on fragment A and then on fragment B I do add and hide). Both fragments have relatively similar layouts (or at least it would be fair to say that the layout of A just before the transition is similar to the starting layout of B - views move around) and when I want to move from A to B I do a "show" on B and "hide" on A. It almost works perfectly, but you can still see a short flash of white in between, before B is shown, and it ruins the illusion that both are the same fragment. How can I transition without the user noticing?
A couple of words of explanation as to why there are two fragments and not one - the business logic is separate. Each fragment deals with a different part of the flow and it wouldn't make any sense to combine them.
Things I've tried so far:
• as I said above, I tried adding B in the background and only doing a "show" on it when it's needed - to save any setup time
• I tried overriding the pending transition and putting a fadeout/fadein, but it made no difference
• I tried hiding fragmentA instead of removing it when showing fragmentB, but it made no difference
• I tried overriding pending transition with 0,0 (getting rid of transitions entirely) but it's still the same
Code:
getSupportFragmentManager().beginTransaction()
.replace(R.id.contentBlock, fragmentA, "FRAGMENTA")
.add(R.id.contentBlock, fragmentB)
.hide(fragmentB)
.commit();
and later:
getSupportFragmentManager().beginTransaction()
.show(fragmentB)
.remove(fragmentA)
.commit();
mMapFragment = new MapFragment();
ft.beginTransaction(mMapFragment)
.detach(getactivity)
.attach(mMapFragment)
.commit();
I am implementing Fragment transition animations between items in a RecyclerView, and a Fragment showing details of the clicked item. In other words the relatively common...
"Click on a Card in a list and it expands to a detailed view while the rest of the list disappears"
...kind of thing.
The transition from the RecyclerView item to the detailed view is working fine. The shared elements of the item are transitioning to their new state while the rest of the RecyclerView items fade away.
However, when the BackStack is popped the shared elements transition back to their old state, but the other RecyclerView items do not fade back in. They appear instantly at the start of the animation instead, as you can see in this Screen Video
The activity handles quite a few fragments, so I do the transaction in the following generalized method:
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setFragment(int fragId, Bundle args, List<Pair> transitionViews,
String tag, int containerId) {
// Setup the new fragment and transaction
Fragment newFragment = FragmentFactory.newFragment(fragId, args);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(containerId, newFragment, tag);
fragmentTransaction.addToBackStack(tag);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && transitionViews != null) {
// Add the shared elements
for (int i = 0; i < transitionViews.size(); i++) {
final Pair pair = transitionViews.get(i);
fragmentTransaction.addSharedElement((View) pair.first, (String) pair.second);
}
// Setup the transitions
Transition transitionMove = TransitionInflater.from(this).inflateTransition(android.R.transition.move);
Transition transitionFade = TransitionInflater.from(this).inflateTransition(android.R.transition.fade);
// transitionFade.setDuration(500); // Slow down the transition to help see what's happening
// Apply the relevant transitions to each fragment
newFragment.setSharedElementEnterTransition(transitionMove);
newFragment.setEnterTransition(transitionFade);
newFragment.setExitTransition(transitionFade);
mCurrentFragment.setExitTransition(transitionFade);
mCurrentFragment.setReenterTransition(transitionFade);
mCurrentFragment.setSharedElementReturnTransition(transitionMove);
}
fragmentTransaction.commit();
}
I have tried playing with allowing/disallowing transition overlap on Enter/Return.
I have tried playing with the various transition setting methods for Fragments.
I have read through loads of blogs and SO questions on this topic.
I found http://www.androiddesignpatterns.com/2014/12/activity-fragment-transitions-in-android-lollipop-part1.html blog on this topic, and brockoli's sample code very helpful, but have been unable to solve the problem.
Perhaps it is a problem with my understanding of what each transition is for?
Here's how I understand it.
My mCurrentFragment and newFragment have 5 different transition setters each:
setSharedElementEnterTransition Sets the Transition that will be used for shared elements transferred into the content Scene.
setSharedElementReturnTransition Sets the Transition that will be used for shared elements transferred back during a pop of the back stack.
setEnterTransition Sets the Transition that will be used to move Views into the initial scene.
setExitTransition Sets the Transition that will be used to move Views out of the scene when the fragment is removed, hidden, or detached when not popping the back stack.
setReenterTransition Sets the Transition that will be used to move Views in to the scene when returning due to popping a back stack.
When my setFragment method is called, an animation is played transitioning from mCurrentFragment to newFragment with the following properties:
The newFragment SharedElementEnterTransition defines how the shared elements will transition into newFragment.
(In my case the clicked item's CardView expands and one of the TextView's it contains is moved)
The newFragment EnterTransition defines how the remaining newFragment child views which are not shared elements will transition onto the screen.
(In my case a ToolBar fades in at the bottom of the screen. Actually the ToolBar is fading in behind the exiting RecyclerView. Is there any way to swap it so it's in front?)
The mCurrentFragment ExitTransition defines how the mCurrentFragment child views which are not shared elements will transition off of the screen.
(In my case mCurrentFragment only contains the RecyclerView, so the effect is that the rest of the RecyclerView elements fade away in the background)
When the BackStack is popped I would expect the following to occur:
The SharedElementReturnTransition for mCurrentFragment defines how the shared elements will transition back into mCurrentFragment.
(In my case the CardView contracts back down to RecyclerView item size and the TextView it contains is moved back).
The ExitTransition for newFragment defines how the newFragment child views which are not shared elements will transition off of the screen.
(In my case the bottom ToolBar fades out)
The ReenterTransition for mCurrentFragment defines how the remaining mCurrentFragment child views which are not shared elements will transition back onto the screen.
(In my case the other RecyclerView items should fade back in, but this is not happening. They are instantly visible behind the transitioning shared elements).
Have I misunderstood anything?
I was playing around with Lollipop's Activity Transition.
I have a button in Activity A which when clicked calls Activity B. In the Activity B, I am overriding onBackPressed() and calling finishAfterTransition()
Activity B just has two relative layout blocks with the background color. I have put a shared element transition from the Button to one of the blocks and it works perfectly. Even the return transition works.
But the problem I am having is that I am not able to cancel the shared element return transition and implement a normal exit transition.
The intent was to slide the two blocks off the screen, top one off the top and bottom one off the bottom. That's not working if I have a shared element transition enabled.
I tried setting the exit transition and setting null to sharedElementReturn transition on Activity B. Not working.
I tried setting the reenter transition on Activity A with the slide transition, but still, the shared element transition is reversed on the back press.
If I turn off the shared element transition, the desired effect is perfect on return from Activity B to A.
Any ideas?