While replacing fragment, I am using Slide animation available for android lollipop version. It works as expected for this particular replacement, but on pressing back button it first pops back current fragment & then reverse of enter animation (slide out) is executed.
private void replaceContentFrameByFragment(Fragment replaceBy, String replaceByFragmentTag) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Slide slide = new Slide(Gravity.BOTTOM);
slide.setDuration(1000);
replaceBy.setEnterTransition(slide);
}
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, replaceBy, replaceByFragmentTag);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commitAllowingStateLoss();
}
So, how to force fragment to pop back only after reverse animation of slide is finished? I noticed that activity has method finishAfterTransition() provided. Is there something similar for frgament?
I had the same issue, onReturn from Fragment B -> A, Fragment B seem to be doing an extra slide transition. To get around it, I put in a fade transition for setReturnTransition() of a shorter time than the slide which looks quite good (as it dissolves into previous fragment). The code for this is:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Slide slideRight = new Slide(Gravity.RIGHT);
slideRight.setDuration(200);
fragment.setEnterTransition(slideRight);
Fade fade = new Fade();
fade.setDuration(100);
fragment.setReturnTransition(fade);
}
I was having the same issue with roughly the same pattern and was able to get around it by posting my fragments transition:
new Handler().post(new Runnable() {
#Override
public void run() {
page.setEnterTransition(new Slide());
getFragmentManager()
.beginTransaction()
.replace(R.id.root_layout, page, "current")
.commit();
}
});
Not sure why this resolves the issue (or if this is the absolute correct solution), but it worked for me.
Related
I want to show a Dialogfragment that appear from a SharedElement of my Activity. I tried SharedElementTransition and that not working. Here is the code:
FragmentManager fm = this.getSupportFragmentManager();
AddHistoryFragment mAddHistoryFragment = new AddHistoryFragment();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mAddHistoryFragment.setSharedElementReturnTransition(TransitionInflater.from(
this).inflateTransition(R.transition.change_image_trans));
mAddHistoryFragment.setExitTransition(TransitionInflater.from(
this).inflateTransition(android.R.transition.fade));
mAddHistoryFragment.setSharedElementEnterTransition(TransitionInflater.from(
this).inflateTransition(R.transition.change_image_trans));
mAddHistoryFragment.setEnterTransition(TransitionInflater.from(
this).inflateTransition(android.R.transition.fade));
fm.beginTransaction().add(mAddHistoryFragment,"add History")
.addSharedElement(ivAddExpense, ivAddExpense.getTransitionName()).commit();
}else {
mAddHistoryFragment.show(fm, "History");
}
Thanks
Sadly it won't work. Shared element transitions only work with replace fragment transaction, but DialogFragment.show() uses add transaction.
Also, see this question, maybe its solution will work for you
Android - Shared Element Transition In Dialog
I faced a very stranger problem. My situation is:
I built an application contain many pages, each page is a Fragment. And i used RecyclerView and CardView inside each page. My home page's layout look like:
When i click on a image item to navigate to detail page then press back button right after that, my home page is show up but:
As you can see, all shadow and corner effect disappeared, scroll didn't work, when i touch an item it take a few second before navigate detail page. When detail page shown, every things back to normal. Here is my replace fragment method:
public void replaceBackgroundFragment(Fragment mf, String tag, boolean addBackStack) {
if (mf != null && (currentFragmentTag == null || !currentFragmentTag.equals(tag))) {
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
R.anim.slide_in_left, R.anim.slide_out_right);
ft.replace(R.id.rl_background, mf, tag);
if (addBackStack) {
mf.setCanBack(true);
ft.addToBackStack(tag);
}
ft.commit();
pendingFragment = null;
pendingTag = null;
}
}
When click on an item:
public void onItemClick(MainBanner item) {
MoviePlayerFragment fragment = MoviePlayerFragment.newInstance(item.getItemID());
activity.replaceBackgroundFragment(fragment, "movie_player_fragment" + item.getItemID(), true);
}
EDIT
I used setRetainInstance(true); in my Fragment
Can anybody let me know what is happening?
you may use ft.add(R.id.rl_background, mf, tag); instead of ft.replace(R.id.rl_background, mf, tag);
So basically what I'm working on is very similar to Instagram application, where there're a number of tabs and users can switch to any tab without any delay no matter what there's anything going on, such as refreshing, reloading, and etc. It also uses back button to go back to the previous preserved tab.
In order to achieve this, I've used FragmentManager with FragmentTransaction to show and hide each fragment which represents each tab. I didn't use replace or attach / detach because they destroy view hierarchy of previous tab.
My implementation works pretty well except that showing and hiding fragments are not committed (I highly doubt that this is a right word to say but so far that's how I understood the flow.), or don't occur immediately when SwipeRefreshLayout is refreshing on the fragment (to be hidden) which was added to FragmentManager later than the one to show.
My implementation follows the rules like these. Let's say we have 4 tabs and my MainActivity is showing the first tab, say FirstFragment, and the user selects the second tab, SecondFragment. Because SecondFragment had never been added before, I add it to FragmentManager by using FragmentTransaction.add and hide FirstFragment by using FragmentTransaction.hide. If the user selects the first tab again, because FirstFragment was previously added to FragmentManager, it doesn't add but only show FirstFragment and just hide SecondFragment. And selecting between these two tabs works smoothly.
But when the user "refreshes" SecondFragment's SwipeRefreshLayout and selects the first tab, FragmentTransaction waits for SecondFragment's refresh to be finished and commits(?) the actual transaction. The strange thing is that the transaction is committed immediately the other way around, from FirstFragment's refresh to SecondFragment.
Because this occurs by the order of addition to FragmentManager, I doubt that the order of addition somehow affects backstack of fragments and there might exists something like UI thread priority so that it forces the fragment transaction to be taken place after later-added fragment's UI transition finishes. But I just don't have enough clues to solve the issue. I've tried attach / detach and backstack thing on FragmentTransaction but couldn't solve the issue. I've tried both FragmentTransaction.commit and FragmentTransaction.commitAllowingStateLoss but neither solved the issue.
These are my MainActivity's sample code.
private ArrayList<Integer> mFragmentsStack; // This is simple psuedo-stack which only stores
// the order of fragments stack to collaborate
// when back button is pressed.
private ArrayList<Fragment> mFragmentsList;
#Override
protected void onCreate() {
mFragmentsStack = new ArrayList<>();
mFragmentsList = new ArrayList<>();
mFragmentsList.add(FirstFragment.newInstance());
mFragmentsList.add(SecondFragment.newInstance());
mFragmentsList.add(ThirdFragment.newInstance());
mFragmentsList.add(FourthFragment.newInstance());
mMainTab = (MainTab) findViewById(R.id.main_tab);
mMainTab.setOnMainTabClickListener(this);
int currentTab = DEFAULT_TAB;
mFragmentsStack.add(currentTab);
getSupportFragmentManager().beginTransaction().add(R.id.main_frame_layout,
mFragmentsList.get(currentTab), String.valueOf(currentTab)).commit();
mMainTab.setCurrentTab(currentTab);
}
// This is custom interface.
#Override
public void onTabClick(int oldPosition, int newPosition) {
if (oldPosition != newPosition) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
// First hide the old tab.
fragmentTransaction.hide(mFragmentsList.get(oldPosition));
// Recalculate the fragment stack.
if (mFragmentsStack.contains(newPosition)) {
mFragmentsStack.remove((Integer) newPosition);
}
mFragmentsStack.add(newPosition);
// Add new fragment if it's not added before, or show new fragment which was already hidden.
Fragment fragment = getSupportFragmentManager().findFragmentByTag(String.valueOf(newPosition));
if (fragment != null) {
fragmentTransaction.show(fragment);
} else {
fragmentTransaction.add(R.id.main_frame_layout, mFragmentsList.get(newPosition),
String.valueOf(newPosition));
}
// Commit the transaction.
fragmentTransaction.commitAllowingStateLoss();
}
}
// It mimics the tab behavior of Instagram Android application.
#Override
public void onBackPressed() {
// If there's only one fragment on stack, super.onBackPressed.
// If it's not, then hide the current fragment and show the previous fragment.
int lastIndexOfFragmentsStack = mFragmentsStack.size() - 1;
if (lastIndexOfFragmentsStack - 1 >= 0) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.hide(mFragmentsList.get(mFragmentsStack.get(lastIndexOfFragmentsStack)));
fragmentTransaction.show(mFragmentsList.get(mFragmentsStack.get(lastIndexOfFragmentsStack - 1)));
fragmentTransaction.commitAllowingStateLoss();
mMainTab.setCurrentTab(mFragmentsStack.get(lastIndexOfFragmentsStack - 1));
mFragmentsStack.remove(lastIndexOfFragmentsStack);
} else {
super.onBackPressed();
}
}
Just faced the same issue with only difference - I'm switching fragments on toolbar buttons click.
I've managed to get rid of overlapping fragments overriding onHiddenChanged:
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) {
yourSwipeRefreshLayout.setRefreshing(false);
}
}
in my fragment, I have a layout.when click the button,show it.and when i click it again I set the visibility to Gone.
but I set the layout visible and gone don't work when I jump to an activity and back to the fragment.then I getVisibility() == View.VISIBLE and ==View.GONE, the layout really is visible and gone. but the fragment can't show it.
private void beginTransaction(Fragment fragment) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
I doubt my fragment have some problem because when I try to use Fragment.replace to replace difference fragment, the fragment can't load some data. but I copy the replace code form my last project and the old project don't have any problem.
I use these code to solve the old problem.
bottomBar.post(new Runnable() {
#Override
public void run() {
startHomeFragment();
}
});
but I don't know how to solve the new problem now
I've followed instructions from dmanargias answer here: Android Fragments and animation
The animations themselves work, however the initial animation when adding a fragment is doing something strange. The initial fragment appears to be replaced with the new fragment before the animation is started.
e.g. One would expect an animation of
A <- B (B sliding from right to cover A)
However as soon as the action starts A instantly becomes B and you get an animation of
B <- B.
When popping the stack you get a correct animation of A -> B (B sliding away revealing A)
This is the code that adds a fragment:
CategoryFragment newFragment = CategoryFragment.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit);
fragmentTransaction.replace(R.id.fragment, newFragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Any ideas why this would happen and if there's a way to fix it?
Try this:
final CategoryFragment newFragment = CategoryFragment.newInstance();
final View container = findViewById(R.id.fragment);
container.postDelayed(new Runnable() {
#Override
public void run() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit);
transaction.replace(container.getId(), newFragment).commit();
currentFragment = cardFragment;
}
}, 0);
I was having exactly the same problem, but with different animations.
Check that android:shareInterpolator is not set to true in your xml animations.