I'm having an issue transitioning between fragment. There transition between fragment A to B is very choppy as seen in this GIF: https://i.stack.imgur.com/Gt8d3.jpg. If you notice, when I click the fab button, the transition stops in the middle of the screen. I tried to debug it slowing down the animation and this is the result ( with sideways transition): https://i.stack.imgur.com/ABgbn.jpg
I have a NavigationBar fragment which has a FrameLayout, in which I add my recyclerViewFragment (which inherits from a BaseFragment). My goal is really to smoothen the transition to have no "choppiness" between fragment A ( no paired device) to B which contains a recycler view as shown in the first GIF link,
For reference:
An example NavigationController ( which inherits from my NavBar fragment):
public class ExampleController extends NavBarFragment {
public static ExampleController newInstance() {
ExampleController fragment = new ExampleController();
fragment.setArguments(fragment.createInitBundle());
return fragment;
}
@Override
protected BaseFragment rootFragment() {
return RecyclerViewFragment.newInstance();
}
@Override
public Bundle createInitBundle() {
return new Bundle();
}
}
The rootFrament() method is called in the initializeLayout method found in the NavBarFragment(which is called in the OnCreateView() ) -- this is just to give some context:
@Override
protected void initializeLayout(View view) {
super.initializeLayout(view);
this.toolbar.setNavigationOnClickListener(this::navigationButtonClick);
this.toolbar.setOnMenuItemClickListener(this::navigationMenuClick);
progressBar.getLayoutParams().height = 0;
progressBar.requestLayout();
this.setContentFragment(view, this.rootFragment());
}
and the setContentFragment calls the Transaction manager:
private void setContentFragment(View view, BaseFragment frag) {
Context context = getActivity() != null ? getActivity().getApplicationContext() : null;
if (frag == null || view == null || context == null) {
return;
}
this.currentFragment = frag;
configureUIComponents(context, frag, 0);
getChildFragmentManager().beginTransaction()
.replace(view.findViewById(R.id.main_container).getId(), frag, createFragmentTag(0))
.commit();
}
An example of RecyclerViewFragment:
public class RecyclerViewFragment extends BaseRecyclerViewFragment {
public static RecyclerViewFragment newInstance(){
//navbar implement
Bundle args = new Bundle();
args.putString(NavigationBarConfig.KEY_NAV_BAR_TITLE, "Paired Devices");
args.putBoolean(NavigationBarConfig.KEY_SHOW_NAV_BAR, true);
args.putBoolean(FloatingActionButtonConfig.KEY_SHOW_FAB_BUTTON, true);
RecyclerViewFragment fragment = new RecyclerViewFragment();
fragment.setArguments(args);
return fragment;
}.
I have tried a few things: 1) I have tried using listeners for the "end" of the transition to wait to load the data. This was based on this stack overflow question: Nested fragments transitioning incorrectly. I implemented as follows ( I won't share the whole code for, well ,reasons). The method didDisappear / didAppear() is then use when I load it my model:
@Override
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
Animator animator = null;
// Check for "Show" Transition ids
if (showTransitionAnimationIds.contains(nextAnim)) {
animator = AnimatorInflater.loadAnimator(getActivity(), nextAnim);
if (animator != null && enter) {
animator.addListener(new TransitionAnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
if (previousFragment != null) {
previousFragment.willDisappear();
}
willAppear();
}
@Override
public void onAnimationEnd(Animator animation) {
transitionDone.set(true);
if (previousFragment != null) {
previousFragment.didDisappear();
}
didAppear();
}
});
}
} else if (hideTransitionAnimationIds.contains(nextAnim)) {
animator = AnimatorInflater.loadAnimator(getActivity(), nextAnim);
if (animator != null && !enter) {
animator.addListener(new TransitionAnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
if (previousFragment != null) {
previousFragment.willAppear();
}
willDisappear();
}
@Override
public void onAnimationEnd(Animator animation) {
if (previousFragment != null) {
previousFragment.didAppear();
}
didDisappear();
}
});
}
}
I use this method for the model loading:
protected void waitForTransition() {
if (transitionDone != null) {
try {
transitionDone.get();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Which usually helps me "wait" on the animation to end before I load my models. I thought this was the issue.
My goal is really to smoothen out the animation. I'm aware of the trick to "provide an image" ( to paraphrase) shown in this question: Nested fragments disappear during transition animation but I was looking for something a little bit cleaner. I was thinking a possibility could be to create two fragments on the fly? I.e: have an empty layout with 2 frameLayout in which I could just inject two fragments at run-time. Although I haven't tried that, it doesn't seem very modular.