web-dev-qa-db-fra.com

barre de navigation avec des fragments

J'ai une mise en page Actionbar/viewpager à onglets avec trois onglets dire A , B , et C . Dans l'onglet C onglet (fragment), j'ajoute un autre fragment, disons 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 le résumé de DFragment pour ajouter le bouton:

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

Désormais, dans DFragment, lorsque j'appuie sur le bouton Précédent du matériel (téléphone), je reviens à la présentation d'origine à onglets (ABC) avec CFragment sélectionné. Comment puis-je obtenir cette fonctionnalité avec le bouton d'action de la barre d'action?

82
SohailAziz

Implémentez OnBackStackChangedListener et 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;
}
182
Roger Garzon Nieto

J? ai compris. écrasez simplement onOptionsItemSelected dans l’activité d’hébergement et affichez le backstack, par ex.

public boolean onOptionsItemSelected(MenuItem item) {

  switch (item.getItemId()) {
   case Android.R.id.home:
     FragmentManager fm = getSupportFragmentManager();
     if (fm.getBackStackEntryCount() > 0) {
          fm.popBackStack();
        }
        return true;
    default:
        return super.onOptionsItemSelected(item);;
    }
}

Appelez getActionBar().setDisplayHomeAsUpEnabled(boolean); et getActionBar().setHomeButtonEnabled(boolean); dans onBackStackChanged() comme expliqué dans la réponse ci-dessous.

37
SohailAziz

Si vous avez une activité parent et que vous voulez que ce bouton haut fonctionne comme un bouton Précédent, 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;
     ....
 }

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

18
Daniel Jonker

vous pouvez revenir 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);
}
10
Moaz Rashad

Je sais que cette question est ancienne, mais il se peut que quelqu'un (comme moi) en ait également besoin.

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

1 - Chaque fois que vous ajoutez un fragment non-home, affichez simplement le bouton haut, juste après la validation de 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 ça.

8
Marcos Tomasello

J'ai utilisé une combinaison de réponses Roger Garzon Nieto et sohailaziz . Mon application a une seule activité principale et les fragments A, B et 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, le bouton UP est masqué. 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). La MainActivity elle-même fait simplement apparaître le backstack lorsque vous appuyez sur le bouton UP, et a des méthodes pour afficher/masquer le bouton appelé par les fragments:

MainActivity:

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
    ...
}
6
verboze

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 }

    ...
}
5
fada21

Cela a fonctionné pour moi. Remplacez onSupportNavigateUp et onBackPressed, par exemple (code dans 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)

En cliquant dessus, vous revenez à l'activité précédente.

4
bebe

C'est une très bonne solution 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 à l'aide du 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 se présente comme suit:

// 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;
    }
}
2
Amio.io