¿Cómo puedo ser notificado cuando un Snackbar se ha descartado?

82

Estoy usando un Snackbar de la com.android.support:design:22.2.0biblioteca. Lo estoy usando para deshacer eliminaciones. Para hacer mi vida más fácil, haré que la interfaz de usuario parezca que las cosas realmente se eliminaron de la fuente de datos, y si no se presiona el botón Deshacer en la barra de refrigerios, en realidad realizaré las eliminaciones de la fuente de datos. Entonces, quiero saber cuándo la barra de bocadillos ya no está visible, por lo que es seguro eliminar los elementos.

Puedo llamar a getView () en la Snackbar, pero no estoy seguro de qué oyente debería usar. Lo intenté setOnSystemUiVisibilityChangeListener()pero no funcionó, creo que es solo para la barra de estado del sistema.

Además, Snackbar no se puede ampliar, ya que tiene un constructor privado.

Tyler Pfaff
fuente
1
Esta función estará en la próxima versión de la biblioteca de diseño de soporte
Tyler Pfaff

Respuestas:

179

La biblioteca de diseño de Google admite devoluciones de llamada de Snackbar en la versión 23. Consulte los documentos de Snackbar y los documentos de devolución de llamada . A continuación, se le notificará cuando se cierre la barra de aperitivos (y también cuando se muestre) y también el tipo de despido si esto es útil para usted:

snackbar.addCallback(new Snackbar.Callback() {

    @Override
    public void onDismissed(Snackbar snackbar, int event) {
      //see Snackbar.Callback docs for event details
      ...  
    }

    @Override
    public void onShown(Snackbar snackbar) {
       ...
    }
  });
and_dev
fuente
13
setCallback () ahora está en desuso. Use addCallback () en su lugar
jds17
41
snackbar.addCallback(new Snackbar.Callback() {

    @Override
    public void onDismissed(Snackbar snackbar, int event) {
        if (event == Snackbar.Callback.DISMISS_EVENT_TIMEOUT) {
            // Snackbar closed on its own
        }
    }

    @Override
    public void onShown(Snackbar snackbar) {
        ...
    }
});
Ananth
fuente
4
Es bueno mencionar el evento, porque el onDismissed también se llama cuando se hace clic en
actionText
2
Para la mayoría de los casos, probablemente sea mejor verificar if (event != Snackbar.Callback.DISMISS_EVENT_ACTION)en su lugar, de lo contrario, su lógica de descarte no se ejecutará si el usuario cierra manualmente o si un snackbar es descartado por otro snackbar consecutivo.
shyamal
Gracias por esta líneaevent == Snackbar.Callback.DISMISS_EVENT_TIMEOUT
Pratik Butani
18

Snackbar.addCallback en kotlin

val snackBar = Snackbar
                .make(view, "Text Snackbar", Snackbar.LENGTH_LONG)
                .addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
                    override fun onShown(transientBottomBar: Snackbar?) {
                        super.onShown(transientBottomBar)
                    }

                    override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
                        super.onDismissed(transientBottomBar, event)
                    }
                })

        val snackBarView = snackBar.view
        snackBarView.setBackgroundColor(Color.RED)
        snackBar.show()
Sergey Milakov
fuente
16

Recientemente me topé con este asunto cuando, para desplazarme y mostrar Snackback, se mostraron demasiados antes de que el primero desapareciera. Tenía que encontrar una manera de saber si la aplicación debería haber establecido la barra de bocadillos.

Yo personalmente encontré esta solución.

Es cierto que Snackbar en sí no ofrece ningún tipo de oyente para su estado / visibilidad, pero aún puede obtener el objeto de visualización de Snackbar (getView ();). Desde el objeto de vista, tiene la oportunidad de utilizar una amplia variedad de métodos para agregar oyentes.

Para implementarlo, debe salirse del uso común de Toast / Snackbar "todo en una línea", porque agregar oyentes devuelve void .

Personalmente encontré OnAttachStateChangeListener para satisfacer mis necesidades.

Dejando caer un snipper con mi código en caso de que pueda resultarle útil.

Snackbar snack = Snackbar.make(getView(), "My Placeholder Text", Snackbar.LENGTH_LONG);

snack.getView().addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
    @Override
        public void onViewAttachedToWindow(View v) {
            canDisplaySnackbar = false;
        }

    @Override
    public void onViewDetachedFromWindow(View v) {

        Handler h = new Handler();
        h.postDelayed(new Runnable() {
            @Override
            public void run() {
                canDisplaySnackbar = true;

                }
        }, 1000);
    }
});
snack.show();

Tenga en cuenta que esta es solo mi implementación para mi propio problema, es posible que Handler con un postDelayed Runnable ni siquiera se ajuste a su caso. Fue solo para dar una idea general de la implementación que sugerí usando un fragmento que ya tengo.

FrancescoC
fuente
4
and_dev's andswer es la mejor respuesta ahora.
Islam A. Hassan
12

Para recibir una notificación cuando se muestre o descarte un snackbar, puede proporcionar un Snackbar.Callback a través de setCallback (Callback).

fabuloso
fuente
setCallBack está en desuso ahora, use addCallBack en su lugar
mjn42
5

onDismissed también se llama cuando se hace clic en la acción Text por ese motivo es necesario poner una condición como

event == Snackbar.Callback.DISMISS_EVENT_TIMEOUT

Y ahora el nuevo código se ve a continuación.

final Snackbar snackBar = Snackbar.make(findViewById(R.id.root_layout), result, Snackbar.LENGTH_LONG);

snackbar.addCallback(new Snackbar.Callback() {

@Override
public void onDismissed(Snackbar snackbar, int event) {
 if (event == Snackbar.Callback.DISMISS_EVENT_TIMEOUT) {
        // Snackbar closed on its own
    }  
}

@Override
public void onShown(Snackbar snackbar) {
...
}
});
snackBar.show();
Vishal G. Gohel
fuente
No se recomiendan las respuestas de solo código, ya que no brindan mucha información para los futuros lectores, proporcione una explicación de lo que ha escrito
WhatsThePoint
Para la mayoría de los casos, probablemente sea mejor verificar if (event != Snackbar.Callback.DISMISS_EVENT_ACTION)en su lugar, de lo contrario, su lógica de descarte no se ejecutará si el usuario cierra manualmente o si un snackbar es descartado por otro snackbar consecutivo.
shyamal
3

Actualmente no hay forma de recibir una notificación cuando la barra de aperitivos haya terminado de mostrarse.

En este hilo se analiza una solución alternativa basada en un temporizador para la duración de la visualización de Snackbar. ¿Snackbar en la biblioteca de soporte no incluye OnDismissListener ()?

Un problema a considerar con esta solución alternativa es que es posible que se reinicie la duración de Snackbar. La especificación de diseño de material para Snackbar dice que esto sucederá si se muestra un cuadro de diálogo o ventana emergente no relacionado.

BrentM
fuente
1

Actualmente no puedes lograrlo.

No se llama a un oyente cuando el snackbar está atenuado.

La forma más sencilla de hacerlo es guardar temporalmente el registro en otro lugar (incluso una variable local) y luego volver a insertarlo si presionan el botón Deshacer.

Gabriele Mariotti
fuente
1
    snackbar.addCallback(new Snackbar.Callback() {
        public void onShown(Snackbar snackbar) {
           //  on show  
        }
 public void onDismissed(Snackbar snackbar, int event) {
          //  on dismiss  
        }
      });
dileep krishnan
fuente
Proporcione una descripción / explicación junto con el fragmento de código.
Janis F
1

Tengo exactamente el mismo problema que el tuyo. Mi solución es ...

              final Snackbar povrati_obrisani_unos = Snackbar.make (coordinatorLayout, "Ponisti brisanje", Snackbar.LENGTH_INDEFINITE)
                    .addCallback (new Snackbar.Callback (){
                        @Override
                        public void onDismissed(Snackbar transientBottomBar, int event) {
                            super.onDismissed (transientBottomBar, event);
                            if(event==DISMISS_EVENT_SWIPE){//here we detect if snackbar is swipped away and not cliked (which is undo in my case)
                                Uri uriDelete = Uri.parse (obrisano.getImageuri ());
                                ContentResolver contentResolver = getContentResolver();
                                contentResolver.delete (uriDelete, null, null);
                                Toast.makeText (MainActivity.this,
                                        "Ocitavanje i slika su trajno obrisani", Toast.LENGTH_SHORT).show ();
                            }

Eso es todo, no quiero copiar y pegar snackbar.action que es deshacer. Quiero ser lo más claro posible aquí.

Saludos Nenad

Nenad Štrbić
fuente
0

Gracias a @SergeyMilakov en Kotlin es:

@SuppressLint("WrongConstant") // Suppress an error when set duration.
private fun showSnackbar() {
    val DURATION = 5000

    Snackbar.make(view!!, "Remove item?"), DURATION).apply {
        setAction("Undo") {
            // Your action when a button is clicked.
        }
        addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
            /* override fun onShown(transientBottomBar: Snackbar?) {
                super.onShown(transientBottomBar)
                Timber.d("*** onShown")
            }*/

            override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
                super.onDismissed(transientBottomBar, event)
                if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) {
                    // Your action when the Snackbar is closed and the button was not clicked.
                }

            }
        })
        view.setBackgroundColor(ContextCompat.getColor(context, R.color.black))
        setActionTextColor(ContextCompat.getColor(context, R.color.yellow))
        show()
    }
}

Tenga en cuenta que se Snackbarmuestra, incluso si se mueve a otras pantallas (por ejemplo, hacia atrás). Por lo tanto, no olvide verificar si realiza acciones en la pantalla correcta.

Tampoco Snackbarse restaura después de la rotación de la pantalla.

CoolMind
fuente