5

Wdrażam BottomNavigationView do nawigacji w aplikacji na Androida. Używam Fragments, aby ustawić zawartość dla każdej karty.Oddzielny stos tylny dla każdej karty w BottomNavigationView Android przy użyciu fragmentów

Wiem, jak skonfigurować jeden fragment dla każdej karty, a następnie przełączać fragmenty po kliknięciu karty. Ale w jaki sposób mogę mieć osobny tylny stos dla każdej karty? Oto kod ustawić jeden fragment o

Fragment selectedFragment = ItemsFragment.newInstance(); 
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 
transaction.replace(R.id.content, selectedFragment); 
transaction.commit(); 

Na przykład, Fragment A i B będzie pod języczek 1 i Fragment C i D na karcie 2. Gdy aplikacja jest uruchomiona, fragment A jest przedstawione i Wybrano kartę 1. Wtedy Fragment A może zostać zastąpione Fragmentem B. Po zaznaczeniu Tab 2 powinien zostać wyświetlony Fragment C. Jeśli wybrana zostanie wówczas Tab 1, należy ponownie wyświetlić Fragment B. W tym momencie powinno być możliwe użycie przycisku Wstecz, aby pokazać fragment A.

I Oto kod założyć następny fragment w tej samej zakładce:

Fragment selectedFragment = ItemsFragment.newInstance(); 
FragmentTransaction ft = getFragmentManager().beginTransaction(); 
ft.replace(R.id.content, selectedFragment); 
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); 
ft.addToBackStack(null); 
ft.commit(); 
+1

Niestety, trzeba będzie wdrożyć tego rodzaju przekroju zachowania backstack siebie ... przynajmniej ja tak myślę. – Shark

+0

Zrobiłeś to już wcześniej? –

+0

Nie, moi klienci nigdy nie chcieli tak zepsutego UX, ale mam pomysł. Coś pomiędzy obecnym backstackiem a https: //en.wikipedia.org/wiki/Command_pattern Zasadniczo zachowaj 'HashMap ' i dodaj/usuń ze swojego backstacku. Będzie wymagał modyfikacji 'onBackPressed()' i być może/prawdopodobnie nie używając 'addToBackstack()'. – Shark

Odpowiedz

8

Wreszcie znalazłem rozwiązanie, został zainspirowany poprzedniej odpowiedzi na StackOverflow: Separate Back Stack for each tab in Android using Fragments
ja tylko zastąpiły TabHost z BottomNavigationView i Oto kod:
Główna działalność

public class MainActivity extends AppCompatActivity { 

private HashMap<String, Stack<Fragment>> mStacks; 
public static final String TAB_HOME = "tab_home"; 
public static final String TAB_DASHBOARD = "tab_dashboard"; 
public static final String TAB_NOTIFICATIONS = "tab_notifications"; 

private String mCurrentTab; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation); 
    navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener); 

    mStacks = new HashMap<String, Stack<Fragment>>(); 
    mStacks.put(TAB_HOME, new Stack<Fragment>()); 
    mStacks.put(TAB_DASHBOARD, new Stack<Fragment>()); 
    mStacks.put(TAB_NOTIFICATIONS, new Stack<Fragment>()); 

    navigation.setSelectedItemId(R.id.navigation_home); 
} 

private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener 
     = new BottomNavigationView.OnNavigationItemSelectedListener() { 

    @Override 
    public boolean onNavigationItemSelected(@NonNull MenuItem item) { 
     switch (item.getItemId()) { 
      case R.id.navigation_home: 
       selectedTab(TAB_HOME); 
       return true; 
      case R.id.navigation_dashboard: 
       selectedTab(TAB_DASHBOARD); 
       return true; 
      case R.id.navigation_notifications: 
       selectedTab(TAB_NOTIFICATIONS); 
       return true; 
     } 
     return false; 
    } 

}; 

private void gotoFragment(Fragment selectedFragment) 
{ 
    FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 
    fragmentTransaction.replace(R.id.content, selectedFragment); 
    fragmentTransaction.commit(); 
} 

private void selectedTab(String tabId) 
{ 
    mCurrentTab = tabId; 

    if(mStacks.get(tabId).size() == 0){ 
     /* 
     * First time this tab is selected. So add first fragment of that tab. 
     * Dont need animation, so that argument is false. 
     * We are adding a new fragment which is not present in stack. So add to stack is true. 
     */ 
     if(tabId.equals(TAB_HOME)){ 
      pushFragments(tabId, new HomeFragment(),true); 
     }else if(tabId.equals(TAB_DASHBOARD)){ 
      pushFragments(tabId, new DashboardFragment(),true); 
     }else if(tabId.equals(TAB_NOTIFICATIONS)){ 
      pushFragments(tabId, new NotificationsFragment(),true); 
     } 
    }else { 
     /* 
     * We are switching tabs, and target tab is already has atleast one fragment. 
     * No need of animation, no need of stack pushing. Just show the target fragment 
     */ 
     pushFragments(tabId, mStacks.get(tabId).lastElement(),false); 
    } 
} 

public void pushFragments(String tag, Fragment fragment, boolean shouldAdd){ 
    if(shouldAdd) 
     mStacks.get(tag).push(fragment); 
    FragmentManager manager = getSupportFragmentManager(); 
    FragmentTransaction ft = manager.beginTransaction(); 
    ft.replace(R.id.content, fragment); 
    ft.commit(); 
} 

public void popFragments(){ 
    /* 
    * Select the second last fragment in current tab's stack.. 
    * which will be shown after the fragment transaction given below 
    */ 
    Fragment fragment = mStacks.get(mCurrentTab).elementAt(mStacks.get(mCurrentTab).size() - 2); 

    /*pop current fragment from stack.. */ 
    mStacks.get(mCurrentTab).pop(); 

    /* We have the target fragment in hand.. Just show it.. Show a standard navigation animation*/ 
    FragmentManager manager = getSupportFragmentManager(); 
    FragmentTransaction ft = manager.beginTransaction(); 
    ft.replace(R.id.content, fragment); 
    ft.commit(); 
} 

@Override 
public void onBackPressed() { 
    if(mStacks.get(mCurrentTab).size() == 1){ 
     // We are already showing first fragment of current tab, so when back pressed, we will finish this activity.. 
     finish(); 
     return; 
    } 

    /* Goto previous fragment in navigation stack of this tab */ 
    popFragments(); 
} 

}

przykład fragment Home

public class HomeFragment extends Fragment { 
@Nullable 
@Override 
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
    View view = inflater.inflate(R.layout.fragment_home, container, false); 
    Button gotoNextFragment = (Button) view.findViewById(R.id.gotoHome2); 

    gotoNextFragment.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      ((MainActivity)getActivity()).pushFragments(MainActivity.TAB_HOME, new Home2Fragment(),true); 
     } 
    }); 
    return view; 
} 

}

+0

Ale jak zapisać stan HashMap na rotacji ekranu? –

0

Zamiast zastąpić metodę użyj dodaj fragmentu,

Zamiast tej metody ft.replace (R.id.content, selectedFragment);

Użyj tego ft.add (R.id.content, selectedFragment);

Fragment selectedFragment = ItemsFragment.newInstance(); 
    FragmentTransaction ft = getFragmentManager().beginTransaction(); 
    ft.(R.id.content, selectedFragment); 
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); 
    ft.addToBackStack(null); 
    ft.commit(); 
+1

używając opcji dodawania zamiast zamiany nie działa – Hanady

1

Warto zauważyć, że opisane zachowanie jest niezgodne z wytycznymi Google. https://material.io/guidelines/components/bottom-navigation.html#bottom-navigation-behavior

Nawigacja przez dolny pasek nawigacji powinna przywrócić stan zadania.

Innymi słowy, mając Fragment A i Fragment B "wewnątrz" Tab 1 jest w porządku, ale jeśli użytkownik otworzy Fragment B, klika kartę 2, a następnie ponownie kliknie kartę 1, powinni zobaczyć Fragment A.

+0

Instagram doesn ' sprawiają, że zachowują nienaruszony pancerz, jeśli przejdziesz od jednej karty do drugiej. –