android - how - ¿Cómo implementar onBackPressed() en fragmentos?
onbackpressed activity (30)
¿Qué hay de usar onDestroyView ()?
@Override
public void onDestroyView() {
super.onDestroyView();
}
¿Hay alguna manera en la que podamos implementar onBackPressed()
en Android Fragment de manera similar a la forma en que implementamos en Android Activity?
Como el ciclo de vida del fragmento no tiene onBackPressed()
. ¿Hay algún otro método alternativo para pasar por encima de onBackPressed()
en los fragmentos de Android 3.0?
Creo que la mejor solución es
SOLUCIÓN DE JAVA
Crear una interfaz 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();
}
Y en tu actividad
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();
}
} ...
}
Finalmente en tu Fragmento:
public class MyFragment extends Fragment implements IOnBackPressed{
@Override
public boolean onBackPressed() {
if (myCondition) {
//action not popBackStack
return true;
} else {
return false;
}
}
}
SOLUCIÓN KOTLIN
1 - Crear interfaz
interface IOnBackPressed {
fun onBackPressed(): Boolean
}
2 - Prepare su actividad
class MyActivity : AppCompatActivity() {
override fun onBackPressed() {
val fragment = this.supportFragmentManager.findFragmentById(R.id.main_container)
if ((fragment as? IOnBackPressed)?.onBackPressed()!!.not()) {
super.onBackPressed()
}
}
}
3 - Implementar en tu Fragmento objetivo.
class MyFragment : Fragment(), IOnBackPressed {
override fun onBackPressed(): Boolean {
return if (myCondition) {
//action not popBackStack
true
} else {
false
}
}
}
Dado que esta pregunta y algunas de las respuestas tienen más de cinco años, permítanme compartir mi solución. Este es un seguimiento y modernización de la respuesta de @oyenigun.
ACTUALIZACIÓN: En la parte inferior de este artículo, agregué una implementación alternativa utilizando una extensión de Fragmento abstracto que no involucrará a la Actividad en absoluto, lo que sería útil para cualquier persona con una jerarquía de fragmentos más compleja que involucre fragmentos anidados que requieran un comportamiento de espalda diferente.
Necesitaba implementar esto porque algunos de los fragmentos que uso tienen vistas más pequeñas que me gustaría descartar con el botón Atrás, como pequeñas vistas de información que aparecen, etc., pero esto es bueno para cualquier persona que necesite anular el comportamiento de El botón de atrás dentro de fragmentos.
Primero, define una interfaz
public interface Backable {
boolean onBackPressed();
}
Esta interfaz, que yo llamo Backable
(soy un stickler para las convenciones de nombres), tiene un solo método onBackPressed()
que debe devolver un valor boolean
. Necesitamos imponer un valor booleano porque necesitaremos saber si la pulsación del botón Atrás ha "absorbido" el evento Atrás. Devolviendo true
significa que sí, y no se necesita ninguna otra acción, de lo contrario, false
dice que la acción de retroceso predeterminada todavía debe tener lugar. Esta interfaz debe ser su propio archivo (preferiblemente en un paquete separado llamado interfaces
). Recuerde, separar sus clases en paquetes es una buena práctica.
Segundo, encuentra el fragmento superior.
Creé un método que devuelve el último objeto Fragment
en la pila trasera. Yo uso etiquetas ... si usa ID, haga los cambios necesarios. Tengo este método estático en una clase de utilidad que se ocupa de los estados de navegación, etc ... pero, por supuesto, colóquelo donde mejor le convenga. Para la edificación, he puesto el mío en una clase llamada 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;
}
Asegúrese de que el recuento de la pila trasera sea mayor que 0, de lo contrario, se podría ArrayOutOfBoundsException
una ArrayOutOfBoundsException
en tiempo de ejecución. Si no es mayor que 0, devuelve nulo. Verificaremos un valor nulo más tarde ...
Tercero, implementar en un fragmento
Implemente la interfaz de Backable
en el fragmento en el que necesite anular el comportamiento del botón de retroceso. Agregue el método de implementación.
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
En la onBackPressed()
, ponga la lógica que necesite. Si desea que el botón Atrás no haga estallar la pila trasera (el comportamiento predeterminado), devuelva verdadero , que su evento de respaldo ha sido absorbido. De lo contrario, devuelve falso.
Por último, en tu actividad ...
Reemplace el método onBackPressed()
y agregue esta lógica:
@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();
}
Obtenemos el fragmento actual en la pila trasera, luego realizamos una comprobación nula y determinamos si implementa nuestra interfaz Backable
. Si lo hace, determine si el evento fue absorbido. Si es así, hemos terminado con onBackPressed()
y podemos regresar. De lo contrario, trátelo como un respaldo normal, presione y llame al súper método.
Segunda opción para no involucrar la actividad.
A veces, no desea que la Actividad maneje esto en absoluto, y necesita manejarlo directamente dentro del fragmento. Pero, ¿quién dice que no puedes tener fragmentos con una API de prensa inversa? Solo extiende tu fragmento a una nueva clase.
Cree una clase abstracta que amplíe Fragmento e implemente la interfaz 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();
}
Como puede ver, cualquier fragmento que extienda BackableFragment
capturará automáticamente los clics hacia atrás utilizando la interfaz View.OnKeyListener
. Simplemente llame al onBackButtonPressed()
abstracto onBackButtonPressed()
desde el método implementado onKey()
usando la lógica estándar para discernir la presión del botón Atrás. Si necesita registrar clics de tecla distintos al botón de retroceso, solo asegúrese de llamar al super
método al anular onKey()
en su fragmento, de lo contrario, anulará el comportamiento en la abstracción.
Fácil de usar, solo extender e implementar:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
Dado que el método onBackButtonPressed()
en la súper clase es abstracto, una vez que lo extienda, debe implementar onBackButtonPressed()
. Devuelve void
porque solo necesita realizar una acción dentro de la clase de fragmento y no necesita transmitir la absorción de la prensa a la Actividad. Asegúrese de llamar al onBackPressed()
Activity onBackPressed()
si lo que está haciendo con el botón de retroceso no requiere manejo, de lo contrario, el botón de retroceso se desactivará ... ¡y no quiere eso!
Advertencias Como puede ver, esto establece la escucha clave en la vista raíz del fragmento, y debemos enfocarlo. Si hay textos de edición involucrados (o cualquier otra vista de robo de enfoque) en su fragmento que amplíe esta clase (u otros fragmentos internos o vistas que tengan el mismo), deberá manejarlo por separado. Hay un buen artículo sobre la extensión de un EditText para perder el enfoque en una pulsación posterior.
Espero que alguien encuentre esto útil. Feliz codificacion
De acuerdo con @HaMMeRed, la respuesta aquí es pseudocódigo de cómo debería funcionar. Digamos que su actividad principal se llama BaseActivity
que tiene fragmentos secundarios (como en el ejemplo de lib de SlidingMenu). Aquí están los pasos:
Primero necesitamos crear una interfaz y una clase que implemente su interfaz para tener un método genérico.
Crear interfaz de clase
OnBackPressedListener
public interface OnBackPressedListener { public void doBack(); }
Crear una clase que implemente las habilidades 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); } }
Desde ahora, trabajaremos en nuestro código
BaseActivity
y sus fragmentos.Crea un oyente privado sobre tu clase
BaseActivity
protected OnBackPressedListener onBackPressedListener;
Crear método para configurar el oyente en
BaseActivity
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) { this.onBackPressedListener = onBackPressedListener; }
en anular
onBackPressed
implementar algo por el estilo@Override public void onBackPressed() { if (onBackPressedListener != null) onBackPressedListener.doBack(); else super.onBackPressed();
en su fragmento en
onCreateView
debe agregar nuestro oyente@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; }
Ahora, cuando haga clic de nuevo en el fragmento, debería capturar su método personalizado en la parte posterior.
Debes agregar una interfaz a tu proyecto como abajo;
public interface OnBackPressed {
void onBackPressed();
}
Y luego, debes implementar esta interfaz en tu fragmento;
public class SampleFragment extends Fragment implements OnBackPressed {
@Override
public void onBackPressed() {
//on Back Pressed
}
}
Y puede desencadenar este evento onBackPressed en sus actividades del evento onBackPressed como se muestra a continuación;
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();
}
}
Esto es solo un pequeño código que hará el truco:
getActivity().onBackPressed();
Espero que ayude a alguien :)
Esto funcionó para mí: https://.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;
}
});
}
La solución es simple:
1) Si tiene una clase de fragmentos base que se extienden a todos los fragmentos, agregue este código a su clase, de lo contrario cree una clase de fragmentos base
/*
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
// add code in super class when override
}
2) En su clase de actividad, anule onBackPressed de la siguiente manera:
private BaseFragment _currentFragment;
@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
3) En su clase de Fragmento, agregue el código deseado:
@Override
public void onBackPressed()
{
setUpTitle();
}
Nada de eso es fácil de implementar ni funcionará de manera óptima.
Los fragmentos tienen un método llamado onDetach que hará el trabajo.
@Override
public void onDetach() {
super.onDetach();
PUT YOUR CODE HERE
}
Esto va a hacer el trabajo.
No implemente el método ft.addToBackStack (), de modo que al presionar el botón Atrás se terminará su actividad.
proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Pues lo hice así, y me funciona.
Interfaz simple
FragmentOnBackClickInterface.java
public interface FragmentOnBackClickInterface {
void onClick();
}
Ejemplo de implementación
MyFragment.java
public class MyFragment extends Fragment implements FragmentOnBackClickInterface {
// other stuff
public void onClick() {
// what you want to call onBackPressed?
}
entonces simplemente anula onBackPressed en actividad
@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;
}
Respuesta muy corta y dulce:
getActivity().onBackPressed();
Explicación de todo el escenario de mi caso:
Tengo FragmentA en MainActivity, estoy abriendo FragmentB desde FragmentA (FragmentB es hijo o fragmento anidado de FragmentA)
Fragment duedateFrag = new FragmentB();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.container_body, duedateFrag);
ft.addToBackStack(null);
ft.commit();
Ahora, si desea ir a FragmentA desde FragmentB, simplemente puede poner getActivity().onBackPressed();
en FragmentB.
Si deseara ese tipo de funcionalidad, tendría que anularla en su actividad y luego agregar una interfaz YourBackPressed
a todos sus fragmentos, a los que llama en el fragmento relevante cada vez que se presiona el botón Atrás.
Edit: me gustaría añadir mi respuesta anterior.
Si tuviera que hacer esto hoy, usaría una transmisión, o posiblemente una transmisión ordenada si esperaba que otros paneles se actualizaran al unísono al panel de contenido principal / principal.
LocalBroadcastManager
en la biblioteca de soporte puede ayudarte con esto, y solo envías la transmisión en onBackPressed
y te suscribes en los fragmentos que te interesan. Creo que la mensajería es una implementación más desacoplada y se escalaría mejor, por lo que ahora sería mi recomendación oficial de implementación. Simplemente use la acción del Intent
como filtro para su mensaje. envíe su ACTION_BACK_PRESSED
recién creado, envíelo desde su actividad y escúchelo en los fragmentos relevantes.
Si usa EventBus, es probablemente una solución mucho más simple:
En tu Fragmento:
@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();
}
y en tu clase de actividad puedes definir:
@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 es solo un objeto POJO
Esto es súper limpio y no hay problemas de interfaz / implementación.
Simplemente agregue addToBackStack
mientras realiza la transición entre sus fragmentos como se muestra a continuación:
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();
Si escribe addToBackStack(null)
, lo manejará por sí mismo, pero si le addToBackStack(null)
una etiqueta, debe manejarlo manualmente.
esta es mi solucion
en 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();
}
y en Fragmento:
((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
@Override
public boolean onBackClick() {
if (condition) {
return false;
}
// some codes
return true;
}
});
onBackPressed()
hace que los fragmentos se separen de la actividad.
Según la respuesta de @Sterling Díaz, creo que tiene razón. PERO alguna situación estará mal. (ej. Rotar pantalla)
Por lo tanto, creo que podríamos detectar si se está isRemoving()
para alcanzar los objetivos.
Puede escribirlo en onDetach()
o onDestroyView()
. Eso es trabajo.
@Override
public void onDetach() {
super.onDetach();
if(isRemoving()){
// onBackPressed()
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if(isRemoving()){
// onBackPressed()
}
}
onBackPressed
esta manera anular onBackPressed
en la Actividad. Todos los FragmentTransaction
son addToBackStack
antes de confirmar:
@Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getFragmentManager().popBackStack();
}
}
Fragmento: Haz un BaseFragment colocando un método:
public boolean onBackPressed();
Actividad:
@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();
}
Su actividad se ejecutará sobre los fragmentos adjuntos y visibles y llamará a onBackPressed () en cada uno de ellos y abortará si uno de ellos devuelve "verdadero" (lo que significa que se ha manejado, por lo que no hay más acciones)
Solo sigue estos pasos:
Siempre al agregar un fragmento,
fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();
Luego, en la actividad principal, anule onBackPressed()
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
finish();
}
Para manejar el botón de retroceso en su aplicación,
Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
if (f != null)
getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()
}
¡Eso es!
Clase pública MyActivity extiende la actividad {
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();
}
}
en su fragmento agregue lo siguiente, no se olvide de implementar la interfaz 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;
}
}
He utilizado otro enfoque de la siguiente manera:
- Un autobús de eventos Otto para comunicarse entre la Actividad y sus Fragmentos.
- Una pila en la actividad que contiene acciones de retroceso personalizadas envueltas en un
Runnable
archivo que define el fragmento - Cuando
onBackPressed
se llama en la Actividad de control, muestra la acción de retroceso personalizada más reciente y la ejecutaRunnable
. Si no hay nada en la pila,super.onBackPressed()
se llama por defecto
El enfoque completo con código de ejemplo se incluye here como una respuesta a esta otra pregunta SO .
Mejor solución,
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;
}
}
}
}
}
Ok chicos, finalmente encontré una buena solución.
En su onCreate () en su actividad que contiene sus fragmentos, agregue un oyente de cambio de backstack así:
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();
}
});
(La adición de mi fragmenManager se declara en las actividades O Ahora, cada vez que cambies el fragmento, el fragmento actual. La cadena se convertirá en el nombre del fragmento actual. Luego, en las actividades enBackPressed () puedes controlar las acciones de tu botón Atrás como sigue:
@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)
}
}
Puedo confirmar que este método funciona para mí.
Tuve el mismo problema y creé un nuevo oyente para él y lo utilicé en mis fragmentos.
1 - Su actividad debe tener una interfaz de escucha y una lista de escuchas en ella.
2 - Debes implementar métodos para agregar y eliminar los oyentes.
3 - Debes anular el método onBackPressed para verificar que cualquiera de los oyentes use la tecla de retroceso o no
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 - Su fragmento debe implementar la interfaz para la prensa de vuelta
5 - Es necesario agregar el fragmento como un oyente para la prensa inversa
6 - Debes devolver true desde onBackPressed si el fragmento usa esta tecla de retroceso.
7 - IMPORTANTE - Debe eliminar el fragmento de la lista en Destruir
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;
}
}
Se utiliza una pila en lugar de ArrayList para poder comenzar desde el último fragmento. También puede haber un problema al agregar fragmentos a la pila posterior. Por lo tanto, debe verificar que el fragmento esté visible o no mientras se usa la tecla de retroceso. De lo contrario, uno de los fragmentos utilizará el evento y el último fragmento no se cerrará en la prensa trasera.
Espero que esto resuelva el problema para todos.
en 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();
}
en el fragmento implementar la actividad base / fragmento como
implements DrawerHomeActivity.OnBackPressedListener
DraweHomeActivity es mi actividad base escribir
((DrawerHomeActivity) getActivity()).setOnBackPressedListener(this);
y crea método doBack
@Override
public void doBack() {
//call base fragment
}
En el ciclo de vida de la actividad, siempre el botón de retroceso de Android trata con las transacciones de FragmentManager cuando usamos FragmentActivity o AppCompatActivity.
Para manejar el backstack no necesitamos manejar su conteo de backstack o etiquetar nada, pero debemos mantener el enfoque al agregar o reemplazar un fragmento. Por favor encuentre los siguientes fragmentos para manejar los casos del botón Atrás,
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();
}
Aquí, no agregaré la pila de nuevo para el fragmento de mi casa porque es la página de inicio de mi aplicación. Si agrega addToBackStack a HomeFragment, la aplicación esperará para eliminar todo el marco en la actividad, entonces obtendremos una pantalla en blanco, así que mantengo la siguiente condición:
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
Ahora, puede ver el fragmento agregado previamente en la actividad y la aplicación se cerrará cuando llegue a HomeFragment. También puedes mirar en los siguientes fragmentos.
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
closeDrawer();
} else {
super.onBackPressed();
}
}
Sé que es demasiado tarde, pero tuve el mismo problema la semana pasada. Ninguna de las respuestas me ayudó. Entonces estaba jugando con el código y esto funcionó, ya que ya había agregado los fragmentos.
En su Actividad, establezca una OnPageChangeListener
para ViewPager
que sepa cuándo el usuario está en la segunda actividad. Si está en la segunda actividad, haga un booleano true
como sigue:
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
}
});
Ahora compruebe el booleano cuando se presione el botón Atrás y configure el elemento actual en su primer Fragmento:
@Override
public void onBackPressed() {
if(inAnalytics)
mViewPager.setCurrentItem(0, true);
else
super.onBackPressed();
}
Su justo sencilla si tienen una actividad A y haces 3 fragmentos como B, C y D.Now si se encuentra en el fragmento B o C y onBackPressed
que desea mover el Fragmento D .A continuación, cada vez que usted tiene que apenas Reemplazar el onBackPressed()
método en el Actividad principal A y también cuando saltas a cualquier fragmento, luego pasas un TAG o nombre de ese fragmento por el cual reconociste ese fragmento en la Actividad principal A.
Estoy dando el ejemplo de aquel por el cual puedes entenderlo fácilmente ...
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit();
}
o si se está moviendo del fragmento B al fragmento C ... y al presionar hacia atrás, desea ingresar el Fragmento D ... como a continuación
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");
}
});
Ahora solo tiene que anular el método onBackPressed () en la actividad principal ... como a continuación ...
@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();
}
}
@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;
}
});
}