Existe-t-il un moyen d'implémenter onBackPressed()
dans un fragment Android similaire à celui utilisé dans Android Activity?
Comme le cycle de vie d'un fragment n'a pas onBackPressed()
. Existe-t-il une autre méthode pour surpasser onBackPressed()
dans Android 3.0 fragments?
J'ai résolu de cette façon remplacer onBackPressed
dans l'activité. Tous les FragmentTransaction
sont addToBackStack
avant commit:
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getSupportFragmentManager().popBackStack();
}
}
Je pense que la meilleure solution est
Créer une interface simple:
public interface IOnBackPressed {
/**
* If you return true the back press will not be taken into account, otherwise the activity will act naturally
* @return true if your processing has priority if not false
*/
boolean onBackPressed();
}
Et dans ton activité
public class MyActivity extends Activity {
@Override public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
super.onBackPressed();
}
} ...
}
Enfin dans votre fragment:
public class MyFragment extends Fragment implements IOnBackPressed{
@Override
public boolean onBackPressed() {
if (myCondition) {
//action not popBackStack
return true;
} else {
return false;
}
}
}
interface IOnBackPressed {
fun onBackPressed(): Boolean
}
class MyActivity : AppCompatActivity() {
override fun onBackPressed() {
val fragment =
this.supportFragmentManager.findFragmentById(R.id.main_container)
(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
super.onBackPressed()
}
}
}
class MyFragment : Fragment(), IOnBackPressed {
override fun onBackPressed(): Boolean {
return if (myCondition) {
//action not popBackStack
true
} else {
false
}
}
}
Selon la réponse de @HaMMeRed, voici comment un pseudocode devrait fonctionner. Disons que votre activité principale s'appelle BaseActivity
et comporte des fragments enfant (comme dans l'exemple de lib SlidingMenu lib). Voici les étapes:
Nous avons d’abord besoin de créer une interface et une classe qui implémente son interface pour avoir une méthode générique
Créer une interface de classe OnBackPressedListener
public interface OnBackPressedListener {
public void doBack();
}
Créer une classe qui implémente les compétences de OnBackPressedListener
public class BaseBackPressedListener implements OnBackPressedListener {
private final FragmentActivity activity;
public BaseBackPressedListener(FragmentActivity activity) {
this.activity = activity;
}
@Override
public void doBack() {
activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Depuis, nous allons travailler sur notre code BaseActivity
et ses fragments
Créez un auditeur privé au-dessus de votre classe BaseActivity
protected OnBackPressedListener onBackPressedListener;
méthode create pour définir le programme d'écoute dans BaseActivity
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
en dérogation onBackPressed
implémenter quelque chose comme ça
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
dans votre fragment dans onCreateView
vous devriez ajouter notre auditeur
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
activity = getActivity();
((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
View view = ... ;
//stuff with view
return view;
}
Voila, maintenant quand vous cliquez en arrière dans le fragment, vous devriez attraper votre méthode personnalisée sur le dos.
Cela a fonctionné pour moi: https://stackoverflow.com/a/27145007/3934111
@Override
public void onResume() {
super.onResume();
if(getView() == null){
return;
}
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){
// handle back button's click listener
return true;
}
return false;
}
});
}
Si vous souhaitez ce type de fonctionnalité, vous devez la remplacer dans votre activité, puis ajouter une interface YourBackPressed
à tous vos fragments, que vous appelez sur le fragment approprié chaque fois que vous appuyez sur le bouton Précédent.
Edit: J'aimerais ajouter ma réponse précédente.
Si je devais le faire aujourd'hui, j'utiliserais une émission, ou éventuellement une émission ordonnée, si je m'attendais à ce que d'autres panneaux se mettent à jour à l'unisson avec le panneau de contenu principal/principal.
LocalBroadcastManager
dans la bibliothèque de support technique peut vous aider. Il vous suffit d'envoyer la diffusion au format onBackPressed
et de vous abonner aux fragments concernés. Je pense que la messagerie est une mise en œuvre plus découplée et qu'elle évoluerait mieux. Ce serait donc ma recommandation officielle pour la mise en œuvre maintenant. Utilisez simplement l’action Intent
comme filtre pour votre message. envoyez votre ACTION_BACK_PRESSED
nouvellement créé, envoyez-le depuis votre activité et écoutez-le dans les fragments appropriés.
Rien de tout cela n’est facile à mettre en œuvre et ne fonctionnera pas de manière optimale.
Les fragments ont une méthode appelée onDetach qui fera le travail.
@Override
public void onDetach() {
super.onDetach();
PUT YOUR CODE HERE
}
CECI FAIT LE TRAVAIL.
Ajoutez simplement addToBackStack
pendant que vous effectuez la transition entre vos fragments, comme ci-dessous:
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();
si vous écrivez addToBackStack(null)
, il le gérera tout seul, mais si vous attribuez une balise, vous devez le manipuler manuellement.
comme cette question et certaines des réponses ont plus de cinq ans, laissez-moi partager ma solution. Ceci est un suivi et une modernisation de la réponse de @oyenigun
UPDATE: Au bas de cet article, j'ai ajouté une implémentation alternative utilisant une extension de fragment abstraite qui n'impliquerait pas l'activité du tout, qui serait utile pour toute personne ayant une hiérarchie de fragments plus complexe impliquant des fragments imbriqués nécessitant un comportement arrière différent.
Je devais mettre cela en œuvre car certains fragments que j’utilise ont des vues plus petites que je voudrais rejeter avec le bouton Précédent, telles que de petites vues d’informations qui s’ouvrent, etc. le bouton de retour à l'intérieur des fragments.
Définissez d'abord une interface
public interface Backable {
boolean onBackPressed();
}
Cette interface, que j’appelle Backable
(je ne respecte pas les conventions de nommage), a une seule méthode onBackPressed()
qui doit renvoyer une valeur boolean
. Nous devons imposer une valeur booléenne, car nous devrons savoir si la pression du bouton Précédent a "absorbé" l'événement Back. Retourner true
signifie que c'est le cas et qu'aucune action supplémentaire n'est nécessaire, sinon, false
indique que l'action de retour par défaut doit toujours avoir lieu. Cette interface doit être son propre fichier (de préférence dans un paquet séparé nommé interfaces
). N'oubliez pas que séparer vos classes en packages est une bonne pratique.
Deuxièmement, trouvez le fragment supérieur
J'ai créé une méthode qui renvoie le dernier objet Fragment
de la pile arrière. J'utilise des balises ... si vous utilisez des identifiants, apportez les modifications nécessaires. J'ai cette méthode statique dans une classe d'utilitaire qui traite des états de navigation, etc., mais bien sûr, mettez-la où cela vous convient le mieux. Pour l'édification, j'ai mis le mien dans une classe appelée NavUtils
.
public static Fragment getCurrentFragment(Activity activity) {
FragmentManager fragmentManager = activity.getFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
String lastFragmentName = fragmentManager.getBackStackEntryAt(
fragmentManager.getBackStackEntryCount() - 1).getName();
return fragmentManager.findFragmentByTag(lastFragmentName);
}
return null;
}
Assurez-vous que le nombre de piles de retour est supérieur à 0, sinon une ArrayOutOfBoundsException
pourrait être émise au moment de l'exécution. Si ce n'est pas supérieur à 0, retourne null. Nous vérifierons une valeur nulle plus tard ...
Troisièmement, implémenter dans un fragment
Implémentez l'interface Backable
dans le fragment où vous devez remplacer le comportement du bouton Précédent. Ajoutez la méthode d'implémentation.
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
Dans la substitution onBackPressed()
, mettez la logique dont vous avez besoin. Si vous voulez que le bouton Précédent ne saute pas , la pile arrière (le comportement par défaut), renvoie true , que votre événement de retour a été absorbé. Sinon, retourne false.
Enfin, dans votre activité ...
Remplacez la méthode onBackPressed()
et ajoutez-lui cette logique:
@Override
public void onBackPressed() {
// Get the current fragment using the method from the second step above...
Fragment currentFragment = NavUtils.getCurrentFragment(this);
// Determine whether or not this fragment implements Backable
// Do a null check just to be safe
if (currentFragment != null && currentFragment instanceof Backable) {
if (((Backable) currentFragment).onBackPressed()) {
// If the onBackPressed override in your fragment
// did absorb the back event (returned true), return
return;
} else {
// Otherwise, call the super method for the default behavior
super.onBackPressed();
}
}
// Any other logic needed...
// call super method to be sure the back button does its thing...
super.onBackPressed();
}
Nous obtenons le fragment actuel dans la pile arrière, puis nous effectuons une vérification de null et déterminons s'il implémente notre interface Backable
. Si c'est le cas, déterminez si l'événement a été absorbé. Si c'est le cas, nous en avons terminé avec onBackPressed()
et nous pouvons revenir. Sinon, traitez-le comme une presse normale et appelez la super méthode.
Deuxième option pour ne pas impliquer l'activité
Parfois, vous ne voulez pas que l'activité gère cela du tout, et vous devez le gérer directement dans le fragment. Mais qui a dit que vous ne pouvez pas avoir des fragments avec une API de presse arrière? Étendez simplement votre fragment dans une nouvelle classe.
Créez une classe abstraite qui étend Fragment et implémente l'interface View.OnKeyListner
...
import Android.app.Fragment;
import Android.os.Bundle;
import Android.view.KeyEvent;
import Android.view.View;
public abstract class BackableFragment extends Fragment implements View.OnKeyListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(this);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackButtonPressed();
return true;
}
}
return false;
}
public abstract void onBackButtonPressed();
}
Comme vous pouvez le constater, tout fragment qui s'étend BackableFragment
capturera automatiquement les clics retour à l'aide de l'interface View.OnKeyListener
. Appelez simplement la méthode abstraite onBackButtonPressed()
à partir de la méthode implémentée onKey()
en utilisant la logique standard pour discerner une pression sur le bouton Précédent. Si vous devez enregistrer des clics sur les touches autres que le bouton Précédent, veillez simplement à appeler la méthode super
lorsque vous écrasez onKey()
dans votre fragment. Sinon, vous écraserez le comportement dans l'abstraction.
Simple à utiliser, il suffit d'étendre et d'implémenter:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
Comme la méthode onBackButtonPressed()
de la super-classe est abstraite, vous devez implémenter onBackButtonPressed()
une fois que vous étendez. Il retourne void
car il lui suffit d'exécuter une action dans la classe fragment et n'a pas besoin de relayer l'absorption de la presse à l'activité. Assurez-vous que vous appelez la méthode Activity onBackPressed()
si ce que vous faites avec le bouton Précédent ne nécessite aucune manipulation. Sinon, le bouton retour sera désactivé ... et vous ne voulez pas ça!
Mises en garde Comme vous pouvez le constater, l'écouteur de clé est défini sur la vue racine du fragment et nous devons le cibler. S'il y a des textes de modification impliqués (ou toute autre vue voleuse de focus) dans votre fragment qui étend cette classe (ou d'autres fragments internes ou vues ayant la même chose), vous devrez gérer cela séparément. Il existe un bon article sur extension d'un EditText pour perdre le focus sur une presse arrière.
J'espère que quelqu'un trouvera cela utile. Bonne codage.
La solution est simple:
1) Si vous avez une classe de fragments de base que tous les fragments étendent, ajoutez ce code à sa classe, sinon créez une telle classe de fragments de base
/*
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
// add code in super class when override
}
2) Dans votre classe d'activité, remplacez onBackPressed comme suit:
private BaseFragment _currentFragment;
@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
3) Dans votre classe Fragment, ajoutez le code souhaité:
@Override
public void onBackPressed()
{
setUpTitle();
}
onBackPressed()
provoque la séparation du fragment de l'activité.
Selon la réponse de @Sterling Diaz, je pense qu'il a raison. MAIS une situation sera fausse. (ex. Rotate Screen)
Je pense donc que nous pourrions détecter si isRemoving()
doit atteindre ses objectifs.
Vous pouvez l'écrire sous onDetach()
ou onDestroyView()
. C'est du travail.
@Override
public void onDetach() {
super.onDetach();
if(isRemoving()){
// onBackPressed()
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if(isRemoving()){
// onBackPressed()
}
}
Ceci est juste un petit code qui fera l'affaire:
getActivity().onBackPressed();
J'espère que ça aide quelqu'un :)
Eh bien je l'ai fait comme ça, et ça marche pour moi
Interface simple
FragmentOnBackClickInterface.Java
public interface FragmentOnBackClickInterface {
void onClick();
}
Exemple d'implémentation
MyFragment.Java
public class MyFragment extends Fragment implements FragmentOnBackClickInterface {
// other stuff
public void onClick() {
// what you want to call onBackPressed?
}
puis il suffit de remplacer onBackPressed dans l'activité
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
List<Fragment> frags = getSupportFragmentManager().getFragments();
Fragment lastFrag = getLastNotNull(frags);
//nothing else in back stack || nothing in back stack is instance of our interface
if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
super.onBackPressed();
} else {
((FragmentOnBackClickInterface) lastFrag).onClick();
}
}
private Fragment getLastNotNull(List<Fragment> list){
for (int i= list.size()-1;i>=0;i--){
Fragment frag = list.get(i);
if (frag != null){
return frag;
}
}
return null;
}
Vous devriez ajouter une interface à votre projet comme ci-dessous;
public interface OnBackPressed {
void onBackPressed();
}
Et ensuite, vous devez implémenter cette interface sur votre fragment;
public class SampleFragment extends Fragment implements OnBackPressed {
@Override
public void onBackPressed() {
//on Back Pressed
}
}
Et vous pouvez déclencher cet événement onBackPressed dans vos activités avec l'événement onBackPressed comme ci-dessous;
public class MainActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
if (currentFragment instanceof OnBackPressed) {
((OnBackPressed) currentFragment).onBackPressed();
}
super.onBackPressed();
}
}
c'est ma solution:
dans MyActivity.Java:
public interface OnBackClickListener {
boolean onBackClick();
}
private OnBackClickListener onBackClickListener;
public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
this.onBackClickListener = onBackClickListener;
}
@Override
public void onBackPressed() {
if (onBackClickListener != null && onBackClickListener.onBackClick()) {
return;
}
super.onBackPressed();
}
et dans Fragment:
((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
@Override
public boolean onBackClick() {
if (condition) {
return false;
}
// some codes
return true;
}
});
Si vous utilisez EventBus, c'est probablement une solution beaucoup plus simple:
Dans votre fragment:
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
EventBus.getDefault().register(this);
}
@Override
public void onDetach() {
super.onDetach();
EventBus.getDefault().unregister(this);
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
getSupportFragmentManager().popBackStack();
}
et dans votre classe d'activité, vous pouvez définir:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
super.onBackPressed();
}
@Override
public void onBackPressed() {
EventBus.getDefault().post(new BackPressedMessage(true));
}
BackPressedMessage.Java est juste un objet POJO
Ceci est super propre et il n'y a pas de problèmes d'interface/implémentation.
Que diriez-vous d'utiliser onDestroyView ()?
@Override
public void onDestroyView() {
super.onDestroyView();
}
@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) {
// handle back button
replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);
return true;
}
return false;
}
});
}
Selon les notes de version d'AndroidX , androidx.activity 1.0.0-alpha01
est publié et introduit ComponentActivity
, une nouvelle classe de base de FragmentActivity
et AppCompatActivity
existants. Et cette version nous apporte une nouvelle fonctionnalité:
Vous pouvez maintenant enregistrer un OnBackPressedCallback
via addOnBackPressedCallback
pour recevoir des rappels onBackPressed()
sans avoir à remplacer la méthode dans votre activité.
Il suffit de suivre ces étapes:
Toujours en ajoutant un fragment,
fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();
Ensuite, dans l'activité principale, remplacez onBackPressed()
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
finish();
}
Pour gérer le bouton de retour dans votre application,
Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
if (f != null)
getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()
}
C'est ça!
Dans le cycle de vie de l'activité, le bouton toujours Android précédent traite des transactions FragmentManager lorsque nous utilisons FragmentActivity ou AppCompatActivity.
Pour gérer le backstack, nous n’avons pas besoin de gérer son décompte ou de marquer quoi que ce soit, mais nous devons rester concentrés lors de l’ajout ou du remplacement d’un fragment. S'il vous plaît trouver les extraits suivants pour gérer les cas de bouton de retour,
public void replaceFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
transaction.replace(R.id.activity_menu_fragment_container, fragment).commit();
}
Ici, je n’ajouterai pas de pile de retour pour mon fragment home, car c’est la page d’accueil de mon application. Si vous ajoutez addToBackStack à HomeFragment, l'application attendra de supprimer toutes les alarmes de manière active, nous obtiendrons alors un écran vide. Je garde donc la condition suivante,
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
Maintenant, vous pouvez voir le fragment ajouté précédemment sur acitvity et l'application se fermera lorsque vous atteindrez HomeFragment. vous pouvez également consulter les extraits suivants.
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
closeDrawer();
} else {
super.onBackPressed();
}
}
Très courte et douce réponse:
getActivity().onBackPressed();
Explication de tout le scénario de mon cas:
J'ai FragmentA dans MainActivity, j'ouvre FragmentB à partir de FragmentA (FragmentB est un fragment enfant ou imbriqué de FragmentA).
Fragment duedateFrag = new FragmentB();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.container_body, duedateFrag);
ft.addToBackStack(null);
ft.commit();
Maintenant, si vous voulez aller à FragmentA à partir de FragmentB, vous pouvez simplement mettre getActivity().onBackPressed();
dans FragmentB.
N'appliquez pas la méthode ft.addToBackStack () afin que, lorsque vous avez appuyé sur le bouton Précédent, votre activité soit terminée.
proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Meilleure solution,
import Android.support.v4.app.Fragment;
import Android.support.v4.app.FragmentManager;
import Android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
for (Fragment frag : fm.getFragments()) {
if (frag == null) {
super.onBackPressed();
finish();
return;
}
if (frag.isVisible()) {
FragmentManager childFm = frag.getChildFragmentManager();
if (childFm.getFragments() == null) {
super.onBackPressed();
finish();
return;
}
if (childFm.getBackStackEntryCount() > 0) {
childFm.popBackStack();
return;
}
else {
fm.popBackStack();
if (fm.getFragments().size() <= 1) {
finish();
}
return;
}
}
}
}
}
Faites-le simplement dans onKeyUp ():
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// do something
return true; // return true if back handled, false otherwise
}
return super.onKeyUp(keyCode, event);
}
Vous pouvez enregistrer un fragment d’activité pour gérer la presse arrière:
interface BackPressRegistrar {
fun registerHandler(handler: BackPressHandler)
fun unregisterHandler(handler: BackPressHandler)
}
interface BackPressHandler {
fun onBackPressed(): Boolean
}
tilisation:
private val backPressHandler = object : BackPressHandler {
override fun onBackPressed(): Boolean {
showClosingWarning()
return false
}
}
override fun onResume() {
super.onResume()
(activity as? BackPressRegistrar)?.registerHandler(backPressHandler)
}
override fun onStop() {
(activity as? BackPressRegistrar)?.unregisterHandler(backPressHandler)
super.onStop()
}
class MainActivity : AppCompatActivity(), BackPressRegistrar {
private var registeredHandler: BackPressHandler? = null
override fun registerHandler(handler: BackPressHandler) { registeredHandler = handler }
override fun unregisterHandler(handler: BackPressHandler) { registeredHandler = null }
override fun onBackPressed() {
if (registeredHandler?.onBackPressed() != false) super.onBackPressed()
}
}
Je sais que c'est trop tard, mais j'ai eu le même problème la semaine dernière. Aucune des réponses ne m'a aidé. Je jouais alors avec le code et cela fonctionnait, car j'avais déjà ajouté les fragments.
Dans votre activité, définissez un OnPageChangeListener
pour le ViewPager
afin que vous sachiez à quel moment l'utilisateur se trouve dans la deuxième activité. S'il est dans la deuxième activité, créez un booléen true
comme suit:
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setCurrentItem(0);
mViewPager.addOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mSectionsPagerAdapter.instantiateItem(mViewPager, position);
if(position == 1)
inAnalytics = true;
else if(position == 0)
inAnalytics = false;
}
@Override
public void onPageScrolled(int position, float arg1, int arg2) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
});
Recherchez maintenant le booléen chaque fois que vous appuyez sur le bouton Précédent et définissez l'élément actuel sur votre premier fragment:
@Override
public void onBackPressed() {
if(inAnalytics)
mViewPager.setCurrentItem(0, true);
else
super.onBackPressed();
}
Ok les gars, j'ai finalement trouvé une bonne solution.
Dans votre activité onCreate () hébergeant vos fragments, ajoutez un auditeur de changement de pile comme ceci:
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
List<Fragment> f = fragmentManager.getFragments();
//List<Fragment> f only returns one value
Fragment frag = f.get(0);
currentFragment = frag.getClass().getSimpleName();
}
});
(L'ajout de mon fragmenManager est également déclaré dans les activités O Maintenant, chaque fois que vous modifiez un fragment, le fragment actuel devient le nom du fragment actuel. Dans les activités onBackPressed (), vous pouvez également contrôler les actions de votre bouton Précédent:
@Override
public void onBackPressed() {
switch (currentFragment) {
case "FragmentOne":
// your code here
return;
case "FragmentTwo":
// your code here
return;
default:
fragmentManager.popBackStack();
// default action for any other fragment (return to previous)
}
}
Je peux confirmer que cette méthode fonctionne pour moi.
C’est simple si vous avez une activité A et que vous créez 3 fragments tels que B, C et D. Maintenant, si vous êtes dans le fragment B ou C et onBackPressed
vous voulez passer au fragment D à chaque fois. Remplacez simplement la méthode onBackPressed()
dans l'activité principale A et lorsque vous passez à un fragment, puis passez un TAG ou nom de ce fragment par lequel vous avez reconnu ce fragment dans l'activité principale A.
Je donne l'exemple de celui-ci par lequel vous pouvez facilement comprendre que ...
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit();
}
ou si vous vous déplacez du fragment B au fragment C..et au dos de la presse, vous voulez voir le fragment D ... comme ci-dessous
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, new C_frament(), "xyz").commit();
((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Fragment C");
}
});
Maintenant, vous devez simplement remplacer la méthode onBackPressed () dans l'activité principale .... comme ci-dessous ..
@Override
public void onBackPressed() {
FragmentManager fragmentManager =getSupportFragmentManager();
if (((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")) != null && ((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")).isVisible()) {
Fragment fragment = new D_Fragment();
fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
getSupportActionBar().setTitle("D fragment ");
} else {
super.onBackPressed();
}
}
J'ai utilisé une autre approche comme suit:
Runnable
défini par le fragment appelant.onBackPressed
dans l'activité de contrôle, la dernière action personnalisée en retour apparaît et exécute sa Runnable
. S'il n'y a rien sur la pile, la valeur par défaut super.onBackPressed()
est appeléeL'approche complète avec exemple de code est incluse ici comme réponse à cette autre SO question .
public class MyActivity extends Activity {
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
@Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
}
dans votre fragment, ajoutez ce qui suit, n'oubliez pas d'implémenter l'interface de mainactivity.
public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((MyActivity) getActivity()).setOnBackPressedListener(this);
}
@Override
public void doBack() {
//BackPressed in activity will call this;
}
}
sur mainActivity
protected DrawerHomeActivity.OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(DrawerHomeActivity.OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null) {
onBackPressedListener.doBack();
} else {
super.onBackPressed();
}
}
sur le fragment implémenter l'activité de base/fragment comme
implements DrawerHomeActivity.OnBackPressedListener
DraweHomeActivity est mon activité de base écrire
((DrawerHomeActivity) getActivity()).setOnBackPressedListener(this);
et créer la méthode doBack
@Override
public void doBack() {
//call base fragment
}
Vous devez remplacer le onBackPressed () avec l'écouteur de fragment. Voici comment:
J'ai eu le même problème et j'ai créé un nouvel auditeur et utilisé dans mes fragments.
1 - Votre activité doit avoir une interface d’écoute et une liste des auditeurs.
2 - Vous devez implémenter des méthodes pour ajouter et supprimer les écouteurs
3 - Vous devez remplacer la méthode onBackPressed pour vérifier que les écouteurs utilisent ou non la presse arrière
public class MainActivity ... {
/**
* Back press listener list. Used for notifying fragments when onBackPressed called
*/
private Stack<BackPressListener> backPressListeners = new Stack<BackPressListener>();
...
/**
* Adding new listener to back press listener stack
* @param backPressListener
*/
public void addBackPressListener(BackPressListener backPressListener) {
backPressListeners.add(backPressListener);
}
/**
* Removing the listener from back press listener stack
* @param backPressListener
*/
public void removeBackPressListener(BackPressListener backPressListener) {
backPressListeners.remove(backPressListener);
}
// Overriding onBackPressed to check that is there any listener using this back press
@Override
public void onBackPressed() {
// checks if is there any back press listeners use this press
for(BackPressListener backPressListener : backPressListeners) {
if(backPressListener.onBackPressed()) return;
}
// if not returns in the loop, calls super onBackPressed
super.onBackPressed();
}
}
4 - Votre fragment doit implémenter l'interface pour la presse arrière
5 - Vous devez ajouter le fragment en tant qu'auditeur pour la presse arrière
6 - Vous devez retourner true à partir de onBackPressed si le fragment utilise cette dernière
7 - IMPORTANT - Vous devez supprimer le fragment de la liste onDestroy
public class MyFragment extends Fragment implements MainActivity.BackPressListener {
...
@Override
public void onAttach(Activity activity) {
super.onCreate(savedInstanceState);
// adding the fragment to listener list
((MainActivity) activity).addBackPressListener(this);
}
...
@Override
public void onDestroy() {
super.onDestroy();
// removing the fragment from the listener list
((MainActivity) getActivity()).removeBackPressListener(this);
}
...
@Override
public boolean onBackPressed() {
// you should check that if this fragment is the currently used fragment or not
// if this fragment is not used at the moment you should return false
if(!isThisFragmentVisibleAtTheMoment) return false;
if (isThisFragmentUsingBackPress) {
// do what you need to do
return true;
}
return false;
}
}
Il existe une pile utilisée à la place de ArrayList pour pouvoir démarrer à partir du dernier fragment. Il peut également y avoir un problème lors de l’ajout de fragments à la pile arrière. Donc, vous devez vérifier que le fragment est visible ou non tout en utilisant la presse arrière. Sinon, l'un des fragments utilisera l'événement et le dernier fragment ne sera pas fermé lors de la dernière publication.
J'espère que cela résout le problème pour tout le monde.
Manière facile de gérer onBackPressed () dans les fragments
Étape 1: Créez un booléen statique en activité.
public static Fragment_one;
Étape 2: Sur MainActivity (Activité contenant un fragment) dans la méthode On Create, déclarez
Fragment_one=true;
Étape 3: Remplacer onBackPressed () dans MainActivity
@Override
public void onBackPressed() {
if(Fragment_one) {
//Back key pressed on fragment one
}else {
//Back key pressed on fragment two
}
}
Étape 4: Sur la méthode fragment_one onCreateView declare
MainActivity.Fragment_one=true;
Étape 5 Sur la méthode fragment_two onCreateView declare
MainActivity.Fragment_one=false;
Note: Cette méthode ne peut être appliquée qu'à DEUX fragments.
Fragment: Créer un fragment de base plaçant une méthode:
public boolean onBackPressed();
Activité:
@Override
public void onBackPressed() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (!fragment.isVisible()) continue;
if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) {
return;
}
}
}
super.onBackPressed();
}
Votre activité passera sur les fragments attachés et visibles et appellera onBackPressed () sur chacun d'eux et abandonnera si l'un d'eux renvoie 'true' (ce qui signifie qu'elle a été traitée, donc pas d'autres actions). .
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if ((keyCode == KeyEvent.KEYCODE_BACK))
{
finish();
}
return super.onKeyDown(keyCode, event);
}
Il suffit de commenter n'importe quelle méthode associée à une touche vers le bas maintenant addToBackStack fonctionnera. Merci