Snackbar with CoordinatorLayout disable dismiss

11,741

Solution 1

You can alter the duration of Snackbar to be shown. It will be similar to disable dismiss.

int     LENGTH_INDEFINITE   Show the Snackbar indefinitely. 

Check docs.

if it does not work For this then there is only one way, Implement Your custom Snackbar and override dismiss() method and in that do nothing. :) As dismiss() is a public API.

Solution 2

Snackbar now has actual support disabling swipe to dismiss using the setBehavior method. The great thing here is that before you would always lose some behaviors which are now preserved. You'll also want to use Snackbar.LENGTH_INDEFINITE

Note that the package moved so you have to import the "new" Snackbar in the snackbar package.

Snackbar.make(view, stringId, Snackbar.LENGTH_INDEFINITE)
    .setBehavior(new NoSwipeBehavior())
    .show();

class NoSwipeBehavior extends BaseTransientBottomBar.Behavior {

    @Override
    public boolean canSwipeDismissView(View child) {
      return false;
    }
}

Solution 3

The answer about just using LENGTH_INDEFINITE is not sufficient.

It is only non-dismissable when the Snackbar is no child of CoordinatorLayout. When it is a child, you can still swipe away the SnackBar.

What you can do in that case is listen for the dismiss swipe and simply re-show the Snackbar.

public void showAnnoyingSnackBar(View root, String text) {
    Snackbar.make(root, text, Snackbar.LENGTH_INDEFINITE)
        .setCallback(new Snackbar.Callback() {
            @Override public void onDismissed(Snackbar snackbar, int event) {
                // recursively call this method again when the snackbar was dismissed through a swipe
                if (event == DISMISS_EVENT_SWIPE) showAnnoyingSnackBar(root, text);
            }
        })
        .show();
}

Solution 4

I noticed that when show() method is called, SnackbarLayout is not fully initialised yet.

To lock dissmiss we have to clear behavior after SnackbarLayout initialisation. the best place to do this is for example in OnPreDrawListener of SnackbarLayout

final Snackbar snack = Snackbar.make(getView(), "I can't be dissmiss", Snackbar.LENGTH_INDEFINITE);
    snack.show();
    snack.getView().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            snack.getView().getViewTreeObserver().removeOnPreDrawListener(this);
                ((CoordinatorLayout.LayoutParams) snack.getView().getLayoutParams()).setBehavior(null);
                return true;
            }
        });

Solution 5

I was successful in disabling the swipe-sideways-to-dismiss snackbars with the following hack (after calling snackbar.show())

((android.support.design.widget.CoordinatorLayout.LayoutParams) snackbar.getView().getLayoutParams()).setBehavior(null);
Share:
11,741
Marko
Author by

Marko

Updated on July 22, 2022

Comments

  • Marko
    Marko almost 2 years

    I am using the support

    • FloatingActionButton
    • Snackbar
    • CoordinatorLayout

    I need the CoordinatorLayout so that if SnackBar is shown the FloatingActionButton moves up to make room for the Snackbar. For better understanding check this video.

    I am using SnackBar for double-back to exit the application, but the SnackBar can be dismissed.

    Is there a way to disable the dismiss on the SnackBar?

    Snackbar snackbar = Snackbar.make(view, R.string.press_back_again_to_exit, Snackbar.LENGTH_SHORT);
    snackbar.setAction(R.string.ok, new View.OnClickListener() {
        @Override
        public void onClick(View v)
        {
    
        }
    });
    snackbar.setActionTextColor(getResources().getColor(R.color.white));
    
    View view = snackbar.getView();
    view.setBackgroundColor(getResources().getColor(R.color.orange_warning));
    
    snackbar.show();
    

    Layout

    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.v4.widget.DrawerLayout
            android:id="@+id/drawer_layout"
            xmlns:sothree="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white"
            android:fitsSystemWindows="true">
    
            <com.sothree.slidinguppanel.SlidingUpPanelLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="bottom"
                sothree:umanoFadeColor="@android:color/transparent"
                sothree:umanoPanelHeight="100dp"
                sothree:umanoShadowHeight="4dp">
    
                <!-- Toolbar and main content -->
                <LinearLayout
                    android:id="@+id/toolbar_and_content"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
    
                    <include layout="@layout/toolbar"/>
    
                    <!-- Your content layout -->
                    <FrameLayout
                        android:id="@+id/content_frame"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"/>
    
                </LinearLayout>
    
                <!-- Sliding up panel layout -->
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@color/darker_grey"
                    android:orientation="vertical">
    
                    ...
    
                </LinearLayout>
    
            </com.sothree.slidinguppanel.SlidingUpPanelLayout>
    
    
            <!-- Navigation drawer -->
            <ExpandableListView
                android:id="@+id/lv_left_drawer"
                android:layout_width="280dp"
                android:layout_height="match_parent"
                android:layout_gravity="start"
                android:background="@color/white"
                android:childDivider="@android:color/transparent"
                android:clickable="true"
                android:divider="@color/divider_color"
                android:dividerHeight="0.6dp"
                android:fadeScrollbars="true"
                android:groupIndicator="@null"
                android:listSelector="@drawable/button_drawer_child_selector"
                android:scrollbarSize="0dp"/>
    
        </android.support.v4.widget.DrawerLayout>
    
        <android.support.design.widget.FloatingActionButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right|bottom"
            android:layout_marginBottom="@dimen/floating_action_button_margin"
            android:layout_marginRight="@dimen/floating_action_button_margin"
            android:src="@drawable/ic_add"
            android:visibility="invisible"
            app:backgroundTint="@color/orange"
            app:borderWidth="0dp"
            app:elevation="6dp"
            app:fabSize="normal"/>
    
    </android.support.design.widget.CoordinatorLayout>
    

    P.S.

    I am aware of this GitHub library, that has this functionality, but is there a 'native' way to do it?

    • Archit Jain
      Archit Jain over 8 years
      I think there is no way
    • user
      user over 8 years
      I am using SnackBar for double-back to exit the application - you're going against the platform's UI patterns. SnackBars are for small feedback and not for asking the user for action(like I'm assuming you're trying to do when the user presses back twice)
    • Marko
      Marko over 8 years
      @Luksprog I am aware of that, same could be achieved with a Toast or a Crouton, but it's basically the same, SnackBar just looks nicer. I am personally not a fan of double-back to exit, but unfortunately it's not for me to decide.
    • Melbourne Lopes
      Melbourne Lopes about 8 years
  • Marko
    Marko over 8 years
    Does not work, SnackBar is still dismissable, and stays there forever :)
  • theJango
    theJango over 8 years
    [ dismissable or stay forever ] can you explain a bit. This seems to be contradictory ;)
  • Marko
    Marko over 8 years
    If I set LENGTH_INDEFINITE the SnackBar doesn't go away after time... (makes sense), but I can still dismiss it (swipe right and it goes away).
  • theJango
    theJango over 8 years
    @Marko : check edited answer. I know its a log way but its doable.
  • Marko
    Marko over 8 years
    Awsome, I have to try it. Thanks for your answer!
  • Jared Burrows
    Jared Burrows over 8 years
    This does not work for me. Snackbar snackbar = Snackbar.make(this.rootView, "Blah", Snackbar.LENGTH_SHORT); snackbar.show();((CoordinatorLayout.LayoutParams) snackbar.getView().getLayoutParams()).setBehavior(null);
  • Ace
    Ace about 3 years
    @theJango It's not.. while Snackbar is not a final class, its only constructor is private, effectively making it final