2017-10-03 5 views
2

J'ai passé toute la journée à chercher une réponse et je n'ai trouvé aucune solution adaptée à cette question.Comment implémenter une navigation de retour correcte pour Android BottomNavigation

Je cherche un moyen de créer une utilisation de BottomNavigation similaire à celle de l'application Instagram ou PlayKiosk. Les fragments ne doivent être ajoutés à la pile arrière qu'une seule fois. Lorsque j'appuie sur le bouton de retour, je m'attends à ce que l'application revienne au dernier fragment visité et au bouton de la BottomNavigation correspondant à ce fragment.

Actuellement, j'utiliser le code suivant:

//BottomNavigationListener 
private BottomNavigationView.OnNavigationItemSelectedListener buttonNavigationItemSelectedListener 
     = new BottomNavigationView.OnNavigationItemSelectedListener() { 

    @Override 
    public boolean onNavigationItemSelected(@NonNull MenuItem item) { 
     FragmentManager fragmentManager = getSupportFragmentManager(); 
     switch (item.getItemId()) { 
      case R.id.navigation_game: 
       currentFragment = GameFragment.newInstance(); 
       fragmentManager.beginTransaction() 
         .addToBackStack(TAG_FRAGMENT_GAME) 
         .replace(R.id.content_frame, currentFragment, TAG_FRAGMENT_GAME) 
         .commit(); 
       break; 
      case R.id.navigation_tournament: 
       currentFragment = TournamentFragment.newInstance(); 
       fragmentManager.beginTransaction() 
         .addToBackStack(TAG_FRAGMENT_TOURNAMENT) 
         .replace(R.id.content_frame, currentFragment, TAG_FRAGMENT_TOURNAMENT) 
         .commit(); 
       break; 
      case R.id.navigation_history: 
       break; 
     } 
     return true; 
    } 

}; 

Mais cela conduit au problème que je pouvais appuyer sur le bouton de mon BottomNavigation deux ou trois fois et pour chacun de ces clics serait instancié un nouveau fragment. Les boutons BottomNavigation ne sont pas non plus définis en fonction des fragments.

Je trouve cette réponse, mais ça n'a pas Prevent The Same Fragment From Stacking More Than Once (addToBackStack)

+0

Vous pouvez gérer la méthode onBackPressed? Gardez le dernier fragment quand il s'est ouvert et quand vous appuyez sur le bouton de retour, il suffit de remplacer le dernier fragment que vous avez visité. –

Répondre

0

Vous pouvez utiliser la structure suivante pour avoir la même logique de travail de Instagram.

Commencez par créer une classe de file d'attente unique limitée personnalisée. Il ne contient que les N derniers éléments, où N est le nombre limite (ou le nombre maximum d'éléments) passé à son constructeur. De plus, ce type de file d'attente ne conserve qu'une seule instance d'une classe. Si une instance de la classe A est déjà dans la file d'attente et qu'une autre instance de la classe A doit être ajoutée à la file d'attente, l'ancienne instance est supprimée en premier, puis le nouvel objet est inséré.

public class LimitedUniqueQueue<E> extends LinkedList<E> { 

    private int limit; 

    public LimitedUniqueQueue(int limit) { 
     this.limit = limit; 
    } 

    @Override 
    public boolean add(E o) { 
     // For uniqueness 
     for (int i = 0; i < super.size(); i++) { 
      E item = super.get(i); 
      if (item.getClass() == o.getClass()) { 
       super.remove(i); 
       break; 
      } 
     } 
     boolean added = super.add(o); 
     // For size limit 
     while (added && size() > limit) { 
      super.remove(); 
     } 
     return added; 
    } 
} 

jour Ensuite, votre activité comme suit:

public class MainActivity extends AppCompatActivity { 

    private BottomNavigationView navigation; 
    private LimitedUniqueQueue<Fragment> queue; 
    ... 
    private BottomNavigationView.OnNavigationItemSelectedListener onNavigationItemSelectedListener 
       = new BottomNavigationView.OnNavigationItemSelectedListener() { 

     Fragment gameFragment; 
     Fragment tournamentFragment; 
     Fragment profileFragment; 

     @Override 
     public boolean onNavigationItemSelected(@NonNull MenuItem item) { 
      FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 
      switch (item.getItemId()) { 
       case R.id.navigation_game: 
        if (gameFragment == null) { 
         gameFragment = new GameFragment(); 
        } 
        transaction.replace(R.id.content, gameFragment).commit(); 
        queue.add(gameFragment); 
        return true; 
       case R.id.navigation_tournament: 
        if (tournamentFragment == null) { 
         tournamentFragment = new TournamentFragment(); 
        } 
        transaction.replace(R.id.content, tournamentFragment).commit(); 
        queue.add(tournamentFragment); 
        return true; 
       case R.id.navigation_profile: 
        if (profileFragment == null) { 
         profileFragment = new ProfileFragment(); 
        } 
        transaction.replace(R.id.content, profileFragment).commit(); 
        queue.add(profileFragment); 
        return true; 
      } 
      return false; 
     } 

    }; 

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

     navigation = (BottomNavigationView) findViewById(R.id.navigation); 
     queue = new LimitedUniqueQueue<>(navigation.getMenu().size()); 

     navigation.setOnNavigationItemSelectedListener(onNavigationItemSelectedListener); 
     navigation.setSelectedItemId(R.id.navigation_game); 
     ... 
    } 

    @Override 
    public void onBackPressed() { 
     if (queue.size() > 1) { 
      queue.removeLast(); 
      Fragment previousFragment = queue.getLast(); 
      if (previousFragment instanceof GameFragment) { 
       navigation.setSelectedItemId(R.id.navigation_game); 
      } else if (previousFragment instanceof TournamentFragment) { 
       navigation.setSelectedItemId(R.id.navigation_tournament); 
      } else if (previousFragment instanceof ProfileFragment) { 
       navigation.setSelectedItemId(R.id.navigation_profile); 
      } 
     } else { 
      super.onBackPressed(); 
     } 
    } 

    ... 
} 
+0

Quelqu'un a essayé cela? Je me demande si cela fonctionne pour vous. – Mehmed

+0

Juste testé maintenant et cela fonctionne très bien pour moi. Merci beaucoup. Le seul ajout que j'ai fait était d'ajouter déjà un nouveau GameFragment à la file d'attente dans onCreate pour l'avoir déjà dans la file d'attente au démarrage et en tant que retour par défaut sur le bouton de retour en appuyant sur. –

+0

Vous êtes les bienvenus. J'appelle 'navigation.setSelectedItemId (R.id.navigation_game)' dans la méthode 'onCreate()' pour afficher GameFragment au lancement et l'ajouter implicitement 'la queue' dans' onNavigationItemSelected() '. En tout cas, je suis content que ça a marché. – Mehmed