barre d'action vers le haut de la navigation avec des fragments

88

J'ai une mise en page à onglets actionbar / viewpager avec trois onglets disent A , B et C . Dans l' onglet C onglet (fragment), j'ajoute un autre fragment dire fragment D . avec

 DFragment f= new DFragment();
 ft.add(android.R.id.content, f, "");
 ft.remove(CFragment.this);
 ft.addToBackStack(null);
 ft.commit();

Je modifie la barre d'action dans onResume de DFragment pour ajouter le bouton:

ActionBar ab = getActivity().getActionBar();
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
ab.setDisplayHomeAsUpEnabled(true);
ab.setDisplayShowHomeEnabled(true);

Maintenant dans DFragment, lorsque j'appuie sur le bouton Retour du matériel (téléphone), je reviens à la disposition originale avec onglets (ABC) avec CFragment sélectionné. Comment puis-je obtenir cette fonctionnalité avec le bouton haut de la barre d'action?

SohailAziz
la source
Double
Code-Apprentice

Réponses:

185

Implémentez OnBackStackChangedListeneret ajoutez ce code à votre activité Fragment.

@Override
public void onCreate(Bundle savedInstanceState) {
    //Listen for changes in the back stack
    getSupportFragmentManager().addOnBackStackChangedListener(this);
    //Handle when activity is recreated like on orientation Change
    shouldDisplayHomeUp();
}

@Override
public void onBackStackChanged() {
    shouldDisplayHomeUp();
}

public void shouldDisplayHomeUp(){
   //Enable Up button only  if there are entries in the back stack
   boolean canGoBack = getSupportFragmentManager().getBackStackEntryCount()>0;
   getSupportActionBar().setDisplayHomeAsUpEnabled(canGoBack);
}

@Override
public boolean onSupportNavigateUp() {
    //This method is called when the up button is pressed. Just the pop back stack.
    getSupportFragmentManager().popBackStack();
    return true;
}
Roger Garzon Nieto
la source
18
À propos de onSupportNavigateUp(), "La méthode ne remplace pas la méthode de sa superclasse".
Fred le
9
Si vous avez déjà un onOptionsItemSelected, il est également possible de vérifier le itemId android.R.id.homeau lieu d'ajouter onSupportNavigateUp.
domsom
1
Si la version de l'API> = 14, utilisez onNavigateUp au lieu de onSupportNavigateUp @Override public boolean onNavigateUp () {// Cette méthode est appelée lorsque le bouton haut est enfoncé. Juste la pile de dos pop. getFragmentManager (). popBackStack (); retourne vrai; }
Tejasvi Hegde
1
Est-il censé y avoir un curseur vers le haut qui s'affiche à côté de l'icône de votre application dans le ActionBar? Je n'en vois pas quand j'implémente ce code. Je ne peux que cliquer sur l'icône, mais cela ne fait rien. Android 4.0+.
Azurespot
3
Si onBackStackChanged () ne remplace pas, assurez-vous que votre activité implémente l'interface FragmentManager.OnBackStackChangedListener.
CBA110
40

J? ai compris. remplacez simplement onOptionsItemSelected dans l'activité d'hébergement et affichez le backstack, par exemple

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home: {
            FragmentManager fm = getSupportFragmentManager();
            if (fm.getBackStackEntryCount() > 0) {
                fm.popBackStack();
                return true;
            }
            break;
        }
    }
    return super.onOptionsItemSelected(item);
}

Appel getActionBar().setDisplayHomeAsUpEnabled(boolean);et getActionBar().setHomeButtonEnabled(boolean);en onBackStackChanged()comme expliqué dans une réponse ci - dessous.

SohailAziz
la source
3
vous devez également appeler getActivity (). getActionBar (). setDisplayHomeAsUpEnabled (false); pour retirer le bouton haut une fois que vous avez pop la pile arrière
JoP
Ce n'est pas la bonne façon de procéder. Il maintient activé le bouton haut.
Roger Garzon Nieto
1
Vous devriez mettre ce code dans l' switchinstruction avec le cas android.R.id.home.
Fred
18

Si vous avez une activité parentale et que vous souhaitez que ce bouton vers le haut fonctionne comme un bouton de retour, vous pouvez utiliser ce code:

ajoutez ceci à onCreate dans votre classe d'activité principale

getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            int stackHeight = getSupportFragmentManager().getBackStackEntryCount();
            if (stackHeight > 0) { // if we have something on the stack (doesn't include the current shown fragment)
                getSupportActionBar().setHomeButtonEnabled(true);
                getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            } else {
                getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                getSupportActionBar().setHomeButtonEnabled(false);
            }
        }

    });

puis ajoutez onOptionsItemSelected comme ceci:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            getSupportFragmentManager().popBackStack();
            return true;
     ....
 }

J'utilise généralement cela tout le temps et semble assez légitime

Daniel Jonker
la source
1
J'ai essayé d'utiliser ce code exactement, dans l'un Activitydes miens, dans l'espoir qu'il revienne au fragment dont il a commencé. Le bouton de retour apparaît près de l'icône de mon application lorsque je vais à mon Activity, mais je clique sur l'icône et rien ne se passe (il devrait revenir au fragment). Une idée pourquoi? Merci.
Azurespot
1
@Daniel votre code est légitime .. ça marche. Vous voudrez peut-être le contourner avec l'option try catch juste au cas où ... vous savez pour éviter toute exception imprévue et le plantage des applications
Olu Smith
1
@NoniA. Cela ne retournera qu'à un fragment précédent (par exemple, fragment B -> fragment A), si vous gonflez 1 fragment dans une nouvelle activité, cela ne reviendra pas à l'activité précédente.
Daniel Jonker
10

vous pouvez revenir en arrière avec le bouton haut comme le bouton retour;

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            super.onBackPressed();
            return true;
    }
    return super.onOptionsItemSelected(item);
}
Moaz Rashad
la source
8

Je sais que cette question est ancienne, mais peut-être que quelqu'un (comme moi) en a également besoin.

Si votre activité étend AppCompatActivity , vous pouvez utiliser une solution plus simple (en deux étapes):

1 - Chaque fois que vous ajoutez un fragment non d'origine, affichez simplement le bouton haut, juste après avoir validé la transaction de fragment. Comme ça:

    // ... add a fragment
    // Commit the transaction
    transaction.commit();

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

2 - Ensuite, lorsque vous appuyez sur le bouton UP, vous le masquez.

@Override
public boolean onSupportNavigateUp() {
    getSupportActionBar().setDisplayHomeAsUpEnabled(false);        
    return true;
}

C'est tout.

Martom
la source
7

J'ai utilisé une combinaison des réponses de Roger Garzon Nieto et sohailaziz . Mon application a une seule MainActivity et des fragments A, B, C qui y sont chargés. Mon fragment "home" (A) implémente OnBackStackChangedListener, et vérifie la taille du backStack; s'il est inférieur à un, il masque le bouton UP. Les fragments B et C chargent toujours le bouton de retour (dans ma conception, B est lancé à partir de A et C est lancé à partir de B). Le MainActivity lui-même affiche simplement la backstack en appuyant sur le bouton UP, et dispose de méthodes pour afficher / masquer le bouton, que les fragments appellent:

Activité principale:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        // Respond to the action bar's Up/Home button
        case android.R.id.home:
            getSupportFragmentManager().popBackStack();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

public void showUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(true); }
public void hideUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(false); }

fragmentA (implémente FragmentManager.OnBackStackChangedListener):

public void onCreate(Bundle savedinstanceSate) {
    // listen to backstack changes
    getActivity().getSupportFragmentManager().addOnBackStackChangedListener(this);

    // other fragment init stuff
    ...
}

public void onBackStackChanged() {
    // enable Up button only  if there are entries on the backstack
    if(getActivity().getSupportFragmentManager().getBackStackEntryCount() < 1) {
        ((MainActivity)getActivity()).hideUpButton();
    }
}

fragmentB, fragmentC:

public void onCreate(Bundle savedinstanceSate) {
    // show the UP button
    ((MainActivity)getActivity()).showUpButton();

    // other fragment init stuff
    ...
}
verboze
la source
5

Cela a fonctionné pour moi. Remplacez onSupportNavigateUp et onBackPressed, par exemple (code en Kotlin);

override fun onBackPressed() {
    val count = supportFragmentManager.backStackEntryCount
    if (count == 0) {
        super.onBackPressed()
    } else {
        supportFragmentManager.popBackStack()
    }
}

override fun onSupportNavigateUp(): Boolean {
    super.onSupportNavigateUp()
    onBackPressed()
    return true
}

Maintenant dans le fragment, si vous affichez la flèche vers le haut

activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)

Cliquer dessus vous ramène à l'activité précédente.

bebe
la source
5

Kotlin:

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        supportFragmentManager.addOnBackStackChangedListener { setupHomeAsUp() }
        setupHomeAsUp()
    }

    private fun setupHomeAsUp() {
        val shouldShow = 0 < supportFragmentManager.backStackEntryCount
        supportActionBar?.setDisplayHomeAsUpEnabled(shouldShow)
    }

    override fun onSupportNavigateUp(): Boolean = 
        supportFragmentManager.popBackStack().run { true }

    ...
}
fada21
la source
2

C'est une solution très bonne et fiable: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/

Le gars a créé un fragment abstrait qui gère le comportement de backPress et bascule entre les fragments actifs en utilisant le modèle de stratégie.

Pour certains d'entre vous, il y a peut-être un petit inconvénient dans la classe abstraite ...

En bref, la solution du lien va comme ceci:

// Abstract Fragment handling the back presses

public abstract class BackHandledFragment extends Fragment {
    protected BackHandlerInterface backHandlerInterface;
    public abstract String getTagText();
    public abstract boolean onBackPressed();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(!(getActivity()  instanceof BackHandlerInterface)) {
            throw new ClassCastException("Hosting activity must implement BackHandlerInterface");
        } else {
            backHandlerInterface = (BackHandlerInterface) getActivity();
        }
    }

    @Override
    public void onStart() {
        super.onStart();

        // Mark this fragment as the selected Fragment.
        backHandlerInterface.setSelectedFragment(this);
    }

    public interface BackHandlerInterface {
        public void setSelectedFragment(BackHandledFragment backHandledFragment);
    }
}   

Et utilisation dans l'activité:

// BASIC ACTIVITY CODE THAT LETS ITS FRAGMENT UTILIZE onBackPress EVENTS 
// IN AN ADAPTIVE AND ORGANIZED PATTERN USING BackHandledFragment

public class TheActivity extends FragmentActivity implements BackHandlerInterface {
    private BackHandledFragment selectedFragment;

    @Override
    public void onBackPressed() {
        if(selectedFragment == null || !selectedFragment.onBackPressed()) {
            // Selected fragment did not consume the back press event.
            super.onBackPressed();
        }
    }

    @Override
    public void setSelectedFragment(BackHandledFragment selectedFragment) {
        this.selectedFragment = selectedFragment;
    }
}
Amio.io
la source
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien pour référence. Les réponses aux liens uniquement peuvent devenir invalides si la page liée change.
bummi le
BTW: si vous identifiez des doublons, veuillez les signaler comme tels. THX.
bummi le
est-il important de setSelectedFragment dans onStart?
VLeonovs