如何使用 Snackbar 的操作按钮来关闭 Snackbar?

110

Android设计支持库现在包括对Snackbar的支持。

我使用以下代码创建了一个:

Snackbar.make(findViewById(R.id.root_layout), result, Snackbar.LENGTH_LONG)
        .setAction("Dismiss", new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        }).show();

通过滑动可以关闭 Snackbar。但是,我还希望使用其自身的操作按钮(使用 setAction 函数创建)来关闭它。

然而,似乎没有任何可用的函数可以做到这一点。


5
提示来访者注意,在 Snackbar 上执行 "Dismiss" 操作违反了Google Material Design Guidelines。请留意。 - Loyalar
具体来说:https://material.io/design/components/snackbars.html#usage - Brian Stewart
8个回答

172

对于Java,

.make方法返回一个Snackbar对象。通过将其设置为final来保存该对象的实例。然后,在onClick()中调用.dismiss

final Snackbar snackBar = Snackbar.make(findViewById(android.R.id.content), "Snackbar Message", Snackbar.LENGTH_LONG);

        snackBar.setAction("Action Message", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Call your action method here
                snackBar.dismiss();
            }
        });
        snackBar.show();

对于Kotlin而言,

        Snackbar.make(
            findViewById(android.R.id.content),
            "Snackbar Message",
            Snackbar.LENGTH_INDEFINITE
        ).setAction("Action Message") {
            // Call action functions here
        }.show()

2
如果我在协调布局中使用FloatingActionButton,那么FloatingActionButton不会下降。 - Vinay W
70
默认情况下,单击操作时会关闭小吃货。 不需要显式调用dismiss(关闭)方法。 - Mark Buikema
11
@MarkBuikema,该功能后来被添加进来。在问题提出的时候,这不是snackbar的默认行为。 - EE66
2
顺便提一下,如果 OnClickListener 为空,则不会显示该操作。 - crgarridos
从今天起,这段代码将调用两次dismiss(),并分别传递不同的事件值,一次是在单击操作时,另一次是程序调用dismiss()。 - Juan

59

实现一个点击操作,并让它为空。单击空的点击操作将关闭 Snackbar。

Snackbar.make(coordinatorLayoutView, "Service Enabled", Snackbar.LENGTH_LONG)
                        .setAction("DISMISS", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                            }
                        })
                        .show();

1
你可以传递 null 作为监听器,无需创建实际的实例。 - ccpizza
@ccpizza 这并不完全相同:使用空的监听器,您仍然会得到“DISMISS”按钮,但是使用“null”它不会显示该按钮(我刚刚测试了一下)。编辑:在您对此进行评论之前,已经在被接受的答案的评论中说明了这一点 ;) - V4karian

11

当您使用Snackbar.LENGTH_LONG时,您不需要动作按钮来解除,两秒后将自动解除。 您应该使用以下代码:

当您使用Snackbar.LENGTH_LONG时,无需操作按钮即可解除消息,2秒后会自动解除。请使用以下代码:

 Snackbar snackbar = Snackbar.make(relativeLayout, "Your Message", Snackbar.LENGTH_INDEFINITE);
            snackbar.setAction("dismiss", new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    snackbar.dismiss();
                }
            });

            snackbar.show();

请注意这一行:

Snackbar.LENGTH_INDEFINITE

9

这是一个旧问题,但我想分享下我在Snackbar类似功能上的经验。我们的应用程序有个设计要求,Snackbar应该无限期显示,用户可以通过点击来取消它,但内部不应该包含DISMISS按钮(Google也不推荐在Snackbar中包含Dismiss或Cancel操作)。我们的Snackbar必须仅能通过点击来取消。

最终,对我们有效的唯一解决方案是(我在这里使用了retrolambda,但标准的View.OnClickListener也可以使用):

final Snackbar snack = ... /* create proper snackbar as alway */
snack.getView().setOnClickListener(v -> snack.dismiss());

请注意中间getView()的调用。


你在哪里看到“Google不建议在Snackbars中使用Dismiss或Cancel操作”这一说法的?我想了解原因... - JoseF
@JoseF 请查看问题本身下的第一条评论 ;) 它在Material Design指南中有说明:https://material.io/guidelines/components/snackbars-toasts.html#snackbars-toasts-usage(“0-1个操作,不要解除或取消”) - Dariusz Wiechecki
这个答案的独特之处在于它提供了一种解除设置为“LENGTH_INDEFINITE”(以便用户有时间阅读)的snackbar的方法,而无需启动任何操作按钮开始的操作。我使用Snackbar通知我的玩家已经下载更新并重新启动,如果他们想要实施更新。如果他们还没有准备好重新启动,我希望有一种方法可以解除它,而不必点击操作按钮。在我的测试设备上,Snackbar不能通过滑动来解除。这段代码通过在操作按钮外部触摸来解除它,这应该是我认为的默认行为。 - Androidcoder

4

Snackbar(来自'com.android.support:design:23.2.1')支持多种类型的消失操作。您可以通过使用事件创建一个简单的过滤器,例如在此示例中:

Snackbar.make(view, wornMessage, Snackbar.LENGTH_LONG).setActionTextColor(context.getResources().getColor(R.color.primary))
    .setCallback(new Snackbar.Callback() {
        @Override
        public void onShown(Snackbar snackbar) {
            super.onShown(snackbar);
        // when snackbar is showing
        }

        @Override
        public void onDismissed(Snackbar snackbar, int event) {
            super.onDismissed(snackbar, event);
            if (event != DISMISS_EVENT_ACTION) {
               //will be true if user not click on Action button (for example: manual dismiss, dismiss by swipe
            }
        }
    })
    .setAction("Undo, view1 -> {
        // if user click on Action button
}).show();

Snackbar 的消失类型:

/** Indicates that the Snackbar was dismissed via a swipe.*/
public static final int DISMISS_EVENT_SWIPE = 0;
/** Indicates that the Snackbar was dismissed via an action click.*/
public static final int DISMISS_EVENT_ACTION = 1;
/** Indicates that the Snackbar was dismissed via a timeout.*/
public static final int DISMISS_EVENT_TIMEOUT = 2;
/** Indicates that the Snackbar was dismissed via a call to {@link #dismiss()}.*/
public static final int DISMISS_EVENT_MANUAL = 3;
/** Indicates that the Snackbar was dismissed from a new Snackbar being shown.*/
public static final int DISMISS_EVENT_CONSECUTIVE = 4;

备注:示例代码中使用了Lambda表达式(由RetroLambda提供)


问题不在于解除处理程序。问题是如何在按钮点击时解除。 - The incredible Jan

2

我曾经遇到过同样的问题。当我使用.dismiss()时,动画效果看起来不同,并且出现了两个问题:

  1. FAB按钮无法再次下降
  2. SnackBar本身不像在单击时那样向下滑动

查看原始Android Snackbar源代码,我找到了以下解决方法:

View snackbarView = snackbar.getView();
Button snackbarActionButton = (Button) snackbarView.findViewById(android.support.design.R.id.snackbar_action);
//snackbarActionButton.setSoundEffectsEnabled(false); // might be considered in order not to have a confusing sound because nothing was clicked by the user

然后,我将在 snackBarActionButton 上调用 .performClick。
snackBarActionButton.performClick();

Snackbar的Android源代码链接如下: https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/design/src/android/support/design/widget/Snackbar.java


1
对我来说毫无意义。如果你实际上点击了一个按钮,为什么还要调用performClick()呢?那似乎是无意义的。 - The incredible Jan

0

有一个简单的 Kotlin 扩展函数:

fun View.showSnack(msg: String) {
    Snackbar.make(this, msg, Snackbar.LENGTH_LONG).apply {
        setAction(resources.getString(android.R.string.cancel)) {
            dismiss()
        }
        setActionTextColor(resources.getColor(android.R.color.holo_red_light, null))
        show()
    }
}

-1

如果你想把 snackbar 放在一个静态方法中,请使用这个。

 public static  void showSnackbar(Activity activity,String msg){
        Snackbar snackBar = null;

        snackBar = Snackbar.make( ((activity.findViewById(android.R.id.content))), msg,20000);//Snackbar.LENGTH_INDEFINITE
        Snackbar finalSnackBar = snackBar;
        //
        View.OnClickListener action =  new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finalSnackBar.dismiss();
            }
        };

        snackBar.setAction("OKAY",action )
                .setActionTextColor(activity.getApplicationContext().getResources().getColor(android.R.color.holo_red_light ));
        snackBar.show();
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接