Запретить отключение Snackbar при нажатии действия

Как предотвратить блокировку Android Snackbar на setAction onclick, спасибо

Snackbar.make(rootlayout, "Hello SnackBar!", Snackbar.LENGTH_INDEFINITE) .setAction("Undo", new View.OnClickListener() { @Override public void onClick(View v) { // Snackbar should not dismiss } }) .show(); 

Во-первых, по дизайну Snackbar не должен оставаться там после щелчка действия, поэтому он не настраивается.

Погрузившись в код, я смог найти достаточно швов, чтобы сделать это, отражая.

 public static void doNotHideSnackbar(Snackbar snackbar) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException { final Field sHandler = BaseTransientBottomBar.class.getDeclaredField("sHandler"); sHandler.setAccessible(true); final Method handleMessage = Handler.class.getMethod("handleMessage", Message.class); final Handler originalHandler = (Handler) sHandler.get(snackbar); Handler decoratedHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() { @Override public boolean handleMessage(Message message) { switch (message.what) { case 0: try { handleMessage.invoke(originalHandler, Message.obtain(originalHandler, 0)); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return true; } return false; } }); sHandler.set(snackbar, decoratedHandler); } 

Это проверено и работает с библиотекой поддержки 25.3.1 .

Применение

 final Snackbar snackbar = Snackbar.make(root, "Hello SnackBar!", Snackbar.LENGTH_INDEFINITE).setAction("Undo", new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(v.getContext(), "clicked", Toast.LENGTH_SHORT).show(); } }); snackbar.show(); try { doNotHideSnackbar(snackbar); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } 

результат

Введите описание изображения здесь

ОСТОРОЖНО , это не то решение, которое вы предпочитаете придерживаться, если API может измениться с версии на версию. Вам лучше подумать о том, чтобы реализовать свой собственный Snackbar . Но в качестве быстрого обходного пути вы можете использовать эту отраженную версию.

Лучше поздно, чем никогда – вот как я это сделал.

 private fun showSnackbar() { if(snackbar == null) { //init snackbar snackbar = Snackbar.make(mainCoordinator, R.string.snackbar_no_network, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.snackbar_no_network_action) { checkConnection() } // action text on the right side .setActionTextColor(ContextCompat.getColor(context, R.color.snack_green)) //set background color snackbar!!.view.setBackgroundColor(ContextCompat.getColor(context, R.color.main_dark_gray)) } //show snackbar!!.show() } private val handler = Handler() private fun checkConnection() { handler.postDelayed(checkConnectionRunnable, 500) } private val checkConnectionRunnable = Runnable { if (!NetworkUtil.isOnline(context)){ showSnackbar() } }