防止 Snackbar 在操作单击时关闭
Posted
技术标签:
【中文标题】防止 Snackbar 在操作单击时关闭【英文标题】:Prevent Snackbar from dismissing on action click 【发布时间】:2017-02-27 10:24:50 【问题描述】:如何防止 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.show();在 onClick 内 @GaneshPokale,这行不通 【参考方案1】:这里有一个更简洁的解决方案来实现这一点,它不需要反射。它基于已知 Snackbar 中按钮的视图 ID。 这适用于支持库的 27.1.1 版本,但如果视图 ID 发生更改,可能在未来的版本中不再适用!
首先,使用空的 OnClickListener 设置您的小吃吧操作:
snackbar.setAction("Save", new View.OnClickListener()
@Override
public void onClick(View v)
);
然后,向小吃栏添加回调(在显示之前)。覆盖 onShown 函数,使用R.id.snackbar_action
找到按钮并将您自己的 OnClickListener 添加到其中。仅当手动调用snackbar.dismiss()
时,或者在小吃栏附加到 CoordinatorLayout 时滑动(如何禁用滑动是另一个 SO 问题),小吃栏才会被关闭。
snackbar.addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>()
@Override
public void onShown(Snackbar transientBottomBar)
super.onShown(transientBottomBar);
transientBottomBar.getView().findViewById(R.id.snackbar_action).setOnClickListener(new View.OnClickListener()
// your code here
【讨论】:
【参考方案2】:首先,根据设计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
alike 视图。但作为一种快速解决方法,您可以考虑使用此反射版本。
【讨论】:
我玩过这个,我发现了一些奇怪的东西...解除Snackbar
是部分阻止:既不调用dismiss()
,也不设置持续时间(不是无限期的)有效,只能在屏幕上滑动(但在这种情况下也不会调用回调)!我还尝试在switch语句中实现处理并将另一种情况转发给原始处理程序(0:显示,1:关闭),没有结果接近原始。
非常感谢,但接下来需要时如何隐藏它?【参考方案3】:
迟到总比没有好 - 我就是这样做的。
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()
【讨论】:
这将在 500 毫秒内隐藏和显示小吃栏,这不是 OP 要求的。以上是关于防止 Snackbar 在操作单击时关闭的主要内容,如果未能解决你的问题,请参考以下文章