How to write an Android multi-pane app with very deep navigation

前端 未结 3 804
感情败类
感情败类 2020-12-13 22:30

TL;DR: How should multi-pane apps with deep navigation similar to the Spotify iPad app look and work on Android, and how to implement this?

3条回答
  •  萌比男神i
    2020-12-13 23:11

    I had some research time and came up with a solution to this question (a question that I've wanted to see the solution for LONG time, even before you asked it). I can't really show the whole code as there's some IP boundaries, but I'll put it here the main parts for this animation to works.

    There're two key tools: setCustomAnimations and LayoutTransition Yes, as far as I've been able to do it, you need to separate set animations to make it work.

    So let's get to some code, you'll define your XML with a horizontal LinearLayout and make sure to include the following line on it.

    android:animateLayoutChanges="true"
    

    this will auto-generate a standard LayoutTransition which does translate the fragment/view that is staying in the layout and alpha (in or out) the fragment/view that is being included or removed from the layout. Give it a try.

    So after this layout is inflated we gonna capture this LayoutTransition and trick it out to our needs:

    LayoutTransition lt = myLinearLayout.getLayoutTransition();
    lt.setAnimator(LayoutTransition.APPEARING, null);
    lt.setAnimator(LayoutTransition.DISAPPEARING, null);
    lt.setStartDelay(LayoutTransition.CHANGE_APPEARING, 0);
    lt.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
    

    with that code, we're removing the alpha animations and removing any delay from the transition (because we want all the translations to fire together).

    And now it's just a few simple fragment transactions to make it work, during initialisation we inflate that layout and put a few fragments on it:

    setContentView(R.layout.main); // the layout with that Linear Layout
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.add(R.id.main, frag1, FRAG_1_TAG); // it's good to have tags so you can find them later
    ft.add(R.id.main, frag2, FRAG_2_TAG);
    ft.add(R.id.main, frag3, FRAG_3_TAG);
    ft.hide(frag3);
    ft.commit();
    

    now on the transaction it's a simple:

    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.setCustomAnimations(R.anim.push_left_in, R.anim.push_left_out, R.anim.push_right_in, R.anim.push_right_out);
    Fragment left = getFragmentManager().findFragmentByTag(FRAG_1_TAG);
    Fragment right = getFragmentManager().findFragmentByTag(FRAG_3_TAG);
    
    ft.hide(left);
    ft.show(right);
    
    ft.addToBackStack(null);
    ft.commit();
    

    final notes:

    to make deeper navigation it's just a matter of firing FragmentTransactions to add fragments to the LinearLayout and hide or detach the left side fragment.

    Also to make the fragments work on the linear layout is important to set their LinearLayout.LayoutParams.weight during runtime, something similar to the following code applied to the fragment view

    ((LinearLayout.LayoutParams) view.getLayoutParams()).weight = 1;
    

    to make it work on phones as well it's just a matter of applying the common multiple screen support patterns.

    last note, be careful on proper managing the layout status during device rotation because it's not all automagically handled by the system.

    Happy coding!

提交回复
热议问题