防止 Snackbar 在点击操作时关闭
Prevent Snackbar from dismissing on action click
如何防止 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();
迟到总比不到好 - 这就是我的做法。
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()
}
}
首先,根据设计 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
相似视图。但作为一种快速解决方法,您可以考虑使用此反射版本。
这里有一个更简洁的解决方案,不需要反射。它基于了解 Snackbar 中按钮的视图 ID。 这适用于支持库的 27.1.1 版,但如果更改视图 ID,可能在未来的版本中不再适用!
首先,使用空的 OnClickListener 设置您的快餐栏操作:
snackbar.setAction("Save", new View.OnClickListener() {
@Override
public void onClick(View v) {}
});
然后,添加一个回调到 snackbar(在显示它之前)。覆盖 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
}
如何防止 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();
迟到总比不到好 - 这就是我的做法。
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()
}
}
首先,根据设计 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
相似视图。但作为一种快速解决方法,您可以考虑使用此反射版本。
这里有一个更简洁的解决方案,不需要反射。它基于了解 Snackbar 中按钮的视图 ID。 这适用于支持库的 27.1.1 版,但如果更改视图 ID,可能在未来的版本中不再适用!
首先,使用空的 OnClickListener 设置您的快餐栏操作:
snackbar.setAction("Save", new View.OnClickListener() {
@Override
public void onClick(View v) {}
});
然后,添加一个回调到 snackbar(在显示它之前)。覆盖 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
}