studio libreria custom activity android android-support-library android-design-library android-snackbar

custom - libreria snackbar android studio



¿Snackbar en la biblioteca de soporte no incluye OnDismissListener()? (7)

Ahora lo does

Snackbar.make(getView(), "Hi there!", Snackbar.LENGTH_LONG).setCallback( new Snackbar.Callback() { @Override public void onDismissed(Snackbar snackbar, int event) { switch(event) { case Snackbar.Callback.DISMISS_EVENT_ACTION: Toast.makeText(getActivity(), "Clicked the action", Toast.LENGTH_LONG).show(); break; case Snackbar.Callback.DISMISS_EVENT_TIMEOUT: Toast.makeText(getActivity(), "Time out", Toast.LENGTH_LONG).show(); break; } } @Override public void onShown(Snackbar snackbar) { Toast.makeText(getActivity(), "This is my annoying step-brother", Toast.LENGTH_LONG).show(); } }).setAction("Go away!", new View.OnClickListener() { @Override public void onClick(View v) { } }).show();

Me gustaría implementar el nuevo Snackbar incluido en la última Biblioteca de Soporte de Diseño, pero la forma en que se ofrece parece ser poco intuitiva para mi uso, y supongo que para muchos otros.

Cuando el usuario realiza una acción importante, quiero permitir que la deshaga a través del Snackbar, pero parece que no hay forma de detectar cuándo se descarta para realizar la acción. Me tiene sentido hacerlo de la siguiente manera:

  1. El usuario hace acción.
  2. Muestre Snackbar y actualice la interfaz de usuario como si la acción se hubiera completado (es decir, parece que los datos se envían a la base de datos, pero en realidad aún no lo están).
  3. Si el usuario presionó "deshacer", revertirá los cambios de la interfaz de usuario. Si no, cuando se despide el Snackbar, enviará los datos.

Pero como no veo ningún OnDismissListener accesible, tendría que:

  1. El usuario hace acción.
  2. Enviar información a la base de datos inmediatamente y actualizar la interfaz de usuario.
  3. Si el usuario presiona "deshacer", envíe otra llamada a la base de datos para eliminar los datos recién agregados y revertir los cambios en la interfaz de usuario.

Realmente me gustaría evitar tener que hacer las dos llamadas a la base de datos, y solo enviar una cuando la aplicación sepa que es segura (el usuario ha evitado presionar "deshacer"). Observo que hay una implementación de esto en una biblioteca de terceros a través de un EventListener, pero realmente me gustaría seguir con la biblioteca de Google.


Echa un vistazo a mi clase de ayudante para bares

public class SnackbarUtils { private static final String LOG_TAG = SnackbarUtils.class.getSimpleName(); private SnackbarUtils() { } public interface SnackbarDismissListener { void onSnackbarDismissed(); } public static void showSnackbar(View rootView, String message, String actionMessage, View.OnClickListener callbacks, final SnackbarDismissListener dismissListener){ Snackbar snackbar = Snackbar.make(rootView,message,Snackbar.LENGTH_LONG); snackbar.setAction(actionMessage,callbacks); if (dismissListener != null){ snackbar.getView().addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { } @Override public void onViewDetachedFromWindow(View v) { dismissListener.onSnackbarDismissed(); } }); } snackbar.show(); } }


Esto se acaba de agregar en v23 .

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


La respuesta de Francesco ( here ) es correcta, pero desafortunadamente solo funciona con API> 12. Envié una solicitud de función al Rastreador de problemas de Android. Puedes comprobarlo here y marcarlo si estás interesado. Gracias.


Para mejorar la respuesta de Hitch.united

boolean mAllowedToRemove = true; Snackbar snack = Snackbar.make(mView, mSnackTitle, Snackbar.LENGTH_LONG); snack.setAction(getString(R.string.snackbar_undo), new OnClickListener() { @Override public void onClick(View v) { mAllowedToRemove = false; // undo ... } }); snack.getView().addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { } @Override public void onViewDetachedFromWindow(View v) { if(!mAllowedToRemove){ // handle actions like http requests ... } } }); snack.show();


Tengo el mismo problema, pero estoy proporcionando un ''deshacer'' para eliminar datos.
Así es como lo trato:

  • Pretender que los datos se eliminan de la base de datos (ocultar de la interfaz de usuario, que es una lista de elementos)
  • Espere hasta que el snack bar haya "desaparecido".
  • Enviar la llamada de borrado a la base de datos.
  • SI, el usuario usó la acción de deshacer, bloquea la llamada pendiente a DB

Es posible que esto no funcione para usted, ya que está insertando datos y puede (?) Necesitar que esté disponible en la base de datos después de la primera acción, pero funcionará si es factible "falsificar" los datos (en la UI). Mi código no es óptimo, y lo llamaría piratear, pero es lo mejor que puedo encontrar mientras estoy dentro de las bibliotecas oficiales.

// Control objects boolean canRemoveData = true; Object removedData = getData(id); UI.remove(id); // Snackbar code Snackbar snackbar = Snackbar.make(view, "Data removed", Snackbar.LENGTH_LONG); snackbar.setAction("Undo", new View.OnClickListener() { @Override public void onClick(View v){ canRemoveData = false; DB.remove(id); } }); // Handler to time the dismissal of the snackbar new Handler(getActivity().getMainLooper()).postDelayed(new Runnable() { @Override public void run() { if(canRemoveData){ DB.remove(id); } } }, (int)(snackbar.getDuration() * 1.05f)); // Here I am using a slightly longer delay before sending the db delete call, // just because I don''t trust the accuracy of the Handler timing and I want // to be on the safe side. Either way this is dirty code, but the best I could do.

Mi código real es más complicado (lidiando con el problema de que canRemoveData no sea accesible dentro de las subclases sin ser definitivo, pero básicamente es cómo logré lo que está hablando.
Espero que alguien pueda encontrar una mejor solución.


public class CustomCoordinatorLayout extends CoordinatorLayout { private boolean mIsSnackBar = false; private View mSnakBarView = null; private OnSnackBarListener mOnSnackBarListener = null; public CustomCoordinatorLayout(Context context) { super(context); } public CustomCoordinatorLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if(mIsSnackBar){ // Check whether the snackbar is existed. // If it is not existed then index of the snackbar is -1. if(indexOfChild(mSnakBarView) == -1){ mSnakBarView = null; mIsSnackBar = false; if(mOnSnackBarListener != null) mOnSnackBarListener.onDismiss(); Log.d("NEOSARCHIZO","SnackBar is dismissed!"); } } } @Override public void onMeasureChild(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { super.onMeasureChild(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed); // onMeaureChild is called before onMeasure. // The view of SnackBar doesn''t have an id. if(child.getId() == -1){ mIsSnackBar = true; // Store the view of SnackBar. mSnakBarView = child; if(mOnSnackBarListener != null) mOnSnackBarListener.onShow(); Log.d("NEOSARCHIZO","SnackBar is showed!"); } } public void setOnSnackBarListener(OnSnackBarListener onSnackBarListener){ mOnSnackBarListener = onSnackBarListener; } public interface OnSnackBarListener{ public void onShow(); public void onDismiss(); } }

Uso el coordinador personalizado Cuando se muestra Snackbar, se llama onMeasure y onMeasureChild de CoordinatorLayout. Así que anulé estos métodos.

Tenga en cuenta que debe configurar las ID de los hijos del diseño del coordinador personalizado. Porque encuentro la vista de SnackBar por id. El id de SnackBar es -1.

CustomCoordinatorLayout layout = (CustomCoordinatorLayout)findViewById(R.id.main_content); layout.setOnSnackBarListener(this); Snackbar.make(layout, "Hello!", Snackbar.LENGTH_LONG).setAction("UNDO", new View.OnClickListener() { @Override public void onClick(View v) { //TODO something } }).show();

Implemente OnSnackBarListener en su actividad o fragmento. Cuando se muestre el snackbar, se activará el show. Y el uno es despedido entonces llamará a Desaparecer.