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

前端 未结 3 792
感情败类
感情败类 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条回答
  • 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!

    0 讨论(0)
  • 2020-12-13 23:12

    Partial answer to the animation part: You can do animations with the FragmentTransaction:

    ft.setCustomAnimations(android.R.anim.slide_in_left, 
        android.R.anim.slide_out_right);
    

    Update: see this answer from Reto Meier himself about fragment animation: https://stackoverflow.com/a/4819665/1007169

    0 讨论(0)
  • 2020-12-13 23:24

    We ran into the same problem with our app. The constraints we gave ourselves:

    • Dynamic numbers of panes
    • Each pane can be differently sized
    • Fragments inside of panes must be correctly retained on orientation changes.

    In light of those constraints, we built a new layout we call PanesLayout. You can check it out here:

    https://github.com/cricklet/Android-PanesLibrary

    It basically allows you to easily add any number of dynamically sized panes and attach fragments to those panes. Hope you find it useful! :)

    0 讨论(0)
提交回复
热议问题