web-dev-qa-db-fra.com

Android appui du bouton de retour de la poignée de fragment

J'ai des fragments dans mon activité

[1], [2], [3], [4], [5], [6]

Et sur le bouton Précédent Appuyez sur I pour revenir de [2] à [1] si le fragment actif actuel est [2], ou ne faites rien sinon.

Quelle est la meilleure pratique pour le faire?

EDIT: L'application ne doit pas retourner à [2] à partir de [3] ... [6]

295
skayred

Lorsque vous passez d'un fragment à un autre, appelez addToBackStack() dans le cadre de votre FragmentTransaction:

FragmentTransaction tx = fragmentManager.beginTransation();
tx.replace( R.id.fragment, new MyFragment() ).addToBackStack( "tag" ).commit();

Si vous avez besoin d’un contrôle plus détaillé (c’est-à-dire que lorsque certains fragments sont visibles, vous souhaitez supprimer la clé de retour), vous pouvez définir un OnKeyListener sur la vue parent de votre fragment:

//You need to add the following line for this solution to work; thanks skayred
fragment.getView().setFocusableInTouchMode(true);
fragment.getView().requestFocus();
fragment.getView().setOnKeyListener( new OnKeyListener()
{
    @Override
    public boolean onKey( View v, int keyCode, KeyEvent event )
    {
        if( keyCode == KeyEvent.KEYCODE_BACK )
        {
            return true;
        }
        return false;
    }
} );
370
Mark Allison

Je préfère faire quelque chose comme ça:

private final static String TAG_FRAGMENT = "TAG_FRAGMENT";

private void showFragment() {
    final Myfragment fragment = new MyFragment();
    final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT);
    transaction.addToBackStack(null);
    transaction.commit();
}

@Override
public void onBackPressed() {
    final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);

    if (fragment.allowBackPressed()) { // and then you define a method allowBackPressed with the logic to allow back pressed or not
        super.onBackPressed();
    }
}
259
saulobrito

si vous écrasez la méthode onKey pour la vue fragmentée, il vous faudra:

    view.setFocusableInTouchMode(true);
    view.requestFocus();
    view.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                Log.i(tag, "keyCode: " + keyCode);
                if( keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
                    Log.i(tag, "onKey Back listener is working!!!");
                    getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                    return true;
                } 
                return false;
            }
        });
105
ANemati

Utilisation addToBackStack méthode lors du remplacement d'un fragment par un autre:

getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).addToBackStack("my_fragment").commit();

Ensuite, dans votre activité, utilisez le code suivant pour revenir d’un fragment à un autre (le précédent).

@Override
public void onBackPressed() {
    if (getFragmentManager().getBackStackEntryCount() > 0) {
        getFragmentManager().popBackStack();
    } else {
        super.onBackPressed();
    }
}
78
shimatai

Si vous souhaitez gérer un événement de clé matérielle arrière, vous devez suivre le code de votre méthode onActivityCreated () de Fragment.

Vous devez également vérifier l'événement Action_Down ou Action_UP. Si vous ne voulez pas vérifier alors onKey () Method appellera 2 fois.

De plus, si votre rootview (getView ()) ne contiendra pas le focus, cela ne fonctionnera pas. Si vous avez cliqué sur un contrôle, vous devez à nouveau mettre en évidence rootview à l'aide de getView (). RequestFocus (); Après cela, seul onKeydown () appellera.

getView().setFocusableInTouchMode(true);
getView().requestFocus();

getView().setOnKeyListener(new OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (keyCode == KeyEvent.KEYCODE_BACK) {
                        Toast.makeText(getActivity(), "Back Pressed", Toast.LENGTH_SHORT).show();
                    return true;
                    }
                }
                return false;
            }
        });

Travaille très bien pour moi.

43
Tejas Mehta

Le moyen le plus idéal de faire cela se trouve ici: Fragment: quel rappel invoqué lorsque vous appuyez sur le bouton de retour et le personnalisez

public class MyActivity extends Activity
{
    //...
    //Defined in Activity class, so override
    @Override
    public void onBackPressed()
    {
        super.onBackPressed();
        myFragment.onBackPressed();
    }
}

public class MyFragment extends Fragment
{
    //Your created method
    public static void onBackPressed()
    {
        //Pop Fragments off backstack and do your other checks
    }
}
25
kakoma

Créer des interfaces:

BackButtonHandlerInterface

public interface BackButtonHandlerInterface {
    void addBackClickListener (OnBackClickListener onBackClickListener);
    void removeBackClickListener (OnBackClickListener onBackClickListener);
}

OnBackClickListener

public interface OnBackClickListener {
     boolean onBackClick();
}

Dans Activité:

public class MainActivity extends AppCompatActivity implements BackButtonHandlerInterface {

    private ArrayList<WeakReference<OnBackClickListener>> backClickListenersList = new ArrayList<>();

    @Override
    public void addBackClickListener(OnBackClickListener onBackClickListener) {
        backClickListenersList.add(new WeakReference<>(onBackClickListener));
    }

    @Override
    public void removeBackClickListener(OnBackClickListener onBackClickListener) {
        for (Iterator<WeakReference<OnBackClickListener>> iterator = backClickListenersList.iterator();
         iterator.hasNext();){
            WeakReference<OnBackClickListener> weakRef = iterator.next();
            if (weakRef.get() == onBackClickListener){
                iterator.remove();
            }
        }
    }

    @Override
    public void onBackPressed() {
        if(!fragmentsBackKeyIntercept()){
            super.onBackPressed();
        }
    }

    private boolean fragmentsBackKeyIntercept() {
        boolean isIntercept = false;
        for (WeakReference<OnBackClickListener> weakRef : backClickListenersList) {
            OnBackClickListener onBackClickListener = weakRef.get();
            if (onBackClickListener != null) {
                boolean isFragmIntercept = onBackClickListener.onBackClick();
                if (!isIntercept) isIntercept = isFragmIntercept;
            }
        }
        return isIntercept;
    }
}

Dans fragment:

public class MyFragment extends Fragment implements OnBackClickListener{

    private BackButtonHandlerInterface backButtonHandler;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        backButtonHandler = (BackButtonHandlerInterface) activity;
        backButtonHandler.addBackClickListener(this);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        backButtonHandler.removeBackClickListener(this);
        backButtonHandler = null;
    }

    @Override
    public boolean onBackClick() {
        //This method handle onBackPressed()! return true or false
        return false;
    }

}
19
krawa
 @Override
    public void onResume() {

        super.onResume();

        getView().setFocusableInTouchMode(true);
        getView().requestFocus();
        getView().setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {

                if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){

                    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)){
                        mDrawerLayout.closeDrawer(GravityCompat.START);
                    }
                    return true;
                }

                return false;
            }
        });
    }
10
Ranjit Kathiriya

Si vous gérez le flux des ajouts à chaque pile de transaction, vous pouvez procéder de la sorte pour afficher le fragment précédent lorsque l'utilisateur appuie sur le bouton précédent (vous pouvez également mapper le bouton principal).

@Override
public void onBackPressed() {
    if (getFragmentManager().getBackStackEntryCount() > 0)
        getFragmentManager().popBackStack();
    else
        super.onBackPressed();
}
5
Joaquin Iurchuk

Ou vous pouvez utiliser getSupportFragmentManager().getBackStackEntryCount() pour vérifier quoi faire:

@Override
    public void onBackPressed() {

        logger.d("@@@@@@ back stack entry count : " + getSupportFragmentManager().getBackStackEntryCount());

        if (getSupportFragmentManager().getBackStackEntryCount() != 0) {

            // only show dialog while there's back stack entry
            dialog.show(getSupportFragmentManager(), "ConfirmDialogFragment");

        } else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {

            // or just go back to main activity
            super.onBackPressed();
        }
    }
5
Robert

Nous avons créé une petite bibliothèque pour la gestion de la presse arrière sur plusieurs fragments et/ou dans Activity. L'utilisation est aussi simple que d'ajouter une dépendance dans votre fichier gradle:

compile 'net.skoumal.fragmentback:fragment-back:0.1.0'

Laissez votre fragment implémenter l'interface BackFragment:

public abstract class MyFragment extends Fragment implements BackFragment {

    public boolean onBackPressed() {

        // -- your code --

        // return true if you want to consume back-pressed event
        return false;
    }

    public int getBackPriority() {
        return NORMAL_BACK_PRIORITY;
    }
}

Avertissez vos fragments au sujet des presses à l'envers:

public class MainActivity extends AppCompatActivity {

    @Override
    public void onBackPressed() {
        // first ask your fragments to handle back-pressed event
        if(!BackFragmentHelper.fireOnBackPressedEvent(this)) {
            // lets do the default back action if fragments don't consume it
            super.onBackPressed();
        }
    }
}

Pour plus de détails et d’autres cas d’utilisation, visitez la page GitHub:

https://github.com/skoumalcz/fragment-back

5
gingo

Code de travail:

package com.example.keralapolice;

import Android.app.Fragment;
import Android.app.FragmentManager;
import Android.app.FragmentManager.OnBackStackChangedListener;
import Android.content.Intent;
import Android.os.Bundle;
import Android.util.Log;
import Android.view.Gravity;
import Android.view.KeyEvent;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;
import Android.widget.Toast;

public class ChiefFragment extends Fragment {
    View view;

    // public OnBackPressedListener onBackPressedListener;

    @Override
    public View onCreateView(LayoutInflater inflater,
            ViewGroup container, Bundle args) {

        view = inflater.inflate(R.layout.activity_chief, container, false);
        getActivity().getActionBar().hide();
        view.setFocusableInTouchMode(true);
        view.requestFocus();
        view.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                Log.i(getTag(), "keyCode: " + keyCode);
                if (keyCode == KeyEvent.KEYCODE_BACK) {
                    getActivity().getActionBar().show();
                    Log.i(getTag(), "onKey Back listener is working!!!");
                    getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                    // String cameback="CameBack";
                    Intent i = new Intent(getActivity(), home.class);
                    // i.putExtra("Comingback", cameback);
                    startActivity(i);
                    return true;
                } else {
                    return false;
                }
            }
        });
        return view;
    }
}
4
Android

Je travaille avec SlidingMenu et Fragment, présente mon cas ici et espère aider quelqu'un.

Logique lorsque la touche [Retour] est enfoncée:

  1. Lorsque SlidingMenu affiche, fermez-le, plus rien à faire.
  2. Ou lorsque le 2e fragment (ou plus) est affiché, revenez au fragment précédent et ne plus rien faire.
  3. SlidingMenu non affiché, le fragment actuel est n ° 0, la touche [Back] d'origine fait-elle.

    public class Main extends SherlockFragmentActivity
    {
      private SlidingMenu menu=null;
      Constants.VP=new ViewPager(this);
    
      //Some stuff...
    
      @Override
      public void onBackPressed()
      {
        if(menu.isMenuShowing())
        {
          menu.showContent(true); //Close SlidingMenu when menu showing
          return;
        }
        else
        {
          int page=Constants.VP.getCurrentItem();
          if(page>0)
          {
            Constants.VP.setCurrentItem(page-1, true); //Show previous fragment until Fragment#0
            return;
          }
          else
          {super.onBackPressed();} //If SlidingMenu is not showing and current Fragment is #0, do the original [Back] key does. In my case is exit from APP
        }
      }
    }
    
4
RRTW

Après avoir examiné toutes les solutions, j’ai réalisé qu’il existe une solution beaucoup plus simple.

Dans votre activité onBackPressed () hébergeant tous vos fragments, recherchez le fragment que vous souhaitez empêcher de revenir en arrière. Ensuite, si trouvé, retournez juste. Alors popBackStack ne se produira jamais pour ce fragment.

  @Override
public void onBackPressed() {

        Fragment1 fragment1 = (Fragment1) getFragmentManager().findFragmentByTag(“Fragment1”);
        if (fragment1 != null)
            return;

        if (getFragmentManager().getBackStackEntryCount() > 0){
            getFragmentManager().popBackStack();

        }
}
3
Harry Aung

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

Je pense que le moyen le plus simple est de créer une interface et de vérifier dans l'activité si le fragment est du type interface et, le cas échéant, d'appeler sa méthode pour gérer le pop. Voici l'interface à implémenter dans le fragment.

public interface BackPressedFragment {

    // Note for this to work, name AND tag must be set anytime the fragment is added to back stack, e.g.
    // getActivity().getSupportFragmentManager().beginTransaction()
    //                .replace(R.id.fragment_container, MyFragment.newInstance(), "MY_FRAG_TAG")
    //                .addToBackStack("MY_FRAG_TAG")
    //                .commit();
    // This is really an override. Should call popBackStack itself.
    void onPopBackStack();
}

Voici comment l'implémenter.

public class MyFragment extends Fragment implements BackPressedFragment
    @Override
    public void onPopBackStack() {
        /* Your code goes here, do anything you want. */
        getActivity().getSupportFragmentManager().popBackStack();
}

Et dans votre activité, lorsque vous gérez le pop (probablement à la fois dans onBackPressed et onOptionsItemSelected), ouvrez le pile en utilisant cette méthode:

public void popBackStack() {
    FragmentManager fm = getSupportFragmentManager();
    // Call current fragment's onPopBackStack if it has one.
    String fragmentTag = fm.getBackStackEntryAt(fm.getBackStackEntryCount() - 1).getName();
    Fragment currentFragment = getSupportFragmentManager().findFragmentByTag(fragmentTag);
    if (currentFragment instanceof BackPressedFragment)
        ((BackPressedFragment)currentFragment).onPopBackStack();
    else
        fm.popBackStack();
}
3
Matt Koala
            rootView.setFocusableInTouchMode(true);
            rootView.requestFocus();
            rootView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event)   {
            if (keyCode == KeyEvent.KEYCODE_BACK) {


                Fragment NameofFragment = new NameofFragment;

                FragmentTransaction  transaction=getFragmentManager().beginTransaction();
                transaction.replace(R.id.frame_container,NameofFragment);

                transaction.commit();

                return true;
            }
            return false;
        }
    });

    return rootView;
3
Ashish Soni

Vous pouvez utiliser à partir de getActionBar().setDisplayHomeAsUpEnabled():

@Override
public void onBackStackChanged() {
    int backStackEntryCount = getFragmentManager().getBackStackEntryCount();

    if(backStackEntryCount > 0){
        getActionBar().setDisplayHomeAsUpEnabled(true);
    }else{
        getActionBar().setDisplayHomeAsUpEnabled(false);
    }
}
2
user4501847

Pour ceux qui utilisent des fragments statiques

Dans le cas où vous avez un fragment statique, cela serait préférable. Faire un objet d'instance de votre fragment

private static MyFragment instance=null;

dans onCreate () de MyFragment initialise cette instance

  instance=this;

aussi faire une fonction pour obtenir l'instance

 public static MyFragment getInstance(){
   return instance;
}

aussi faire des fonctions

public boolean allowBackPressed(){
    if(allowBack==true){
        return true;
    }
    return false;
}


 //allowBack is a boolean variable that will be set to true at the action 
 //where you want that your backButton should not close activity. In my case I open 
 //Navigation Drawer then I set it to true. so when I press backbutton my 
 //drawer should be get closed

public void performSomeAction(){
    //.. Your code
    ///Here I have closed my drawer
}

Dans ton activité tu peux faire

@Override
public void onBackPressed() {

    if (MyFragment.getInstance().allowBackPressed()) { 
        MyFragment.getInstance().performSomeAction();
    }
    else{
        super.onBackPressed();
    }
}
2
Muhammad Adil

si vous utilisez FragmentActivity. alors fais comme ça

premier appel Ceci à l'intérieur de votre fragment.

public void callParentMethod(){
    getActivity().onBackPressed();
}

puis appelez la méthode onBackPressed à côté de votre classe parent FragmentActivity.

@Override
public void onBackPressed() {
  //super.onBackPressed();
  //create a dialog to ask yes no question whether or not the user wants to exit
  ...
}
1
hash

dans la classe fragment, mettez ce code pour l'événement précédent:

 rootView.setFocusableInTouchMode(true);
        rootView.requestFocus();
        rootView.setOnKeyListener( new OnKeyListener()
        {
            @Override
            public boolean onKey( View v, int keyCode, KeyEvent event )
            {
                if( keyCode == KeyEvent.KEYCODE_BACK )
                {
                    FragmentManager fragmentManager = getFragmentManager();
                    fragmentManager.beginTransaction()
                            .replace(R.id.frame_container, new Book_service_provider()).commit();

                    return true;
                }
                return false;
            }
        } );
1
tej shah

Ajouter ce code dans votre activité

@Passer outre

public void onBackPressed() {
    if (getFragmentManager().getBackStackEntryCount() == 0) {
        super.onBackPressed();
    } else {
        getFragmentManager().popBackStack();
    }
}

Et ajoutez cette ligne dans votre fragment avant commit ()

ft.addToBackStack ("Tout nom");

1
Ravi

Ajoutez addToBackStack () pour fragmenter la transaction, puis utilisez le code ci-dessous pour la mise en oeuvre de la navigation arrière pour les fragments.

getSupportFragmentManager().addOnBackStackChangedListener(
    new FragmentManager.OnBackStackChangedListener() {
        public void onBackStackChanged() {
            // Update your UI here.
        }
    });
1
Lalit Sharma

Vérification du backstack fonctionne parfaitement


@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
    if (keyCode == KeyEvent.KEYCODE_BACK)
    {
        if (getFragmentManager().getBackStackEntryCount() == 1)
        {
            // DO something here since there is only one fragment left
            // Popping a dialog asking to quit the application
            return false;
        }
    }
    return super.onKeyDown(keyCode, event);
}
0
Devrath