Can we perform 2 different actions in Snack bar at a time in android?

27.6k views Asked by At

I am creating an android application in which i want to use Snack Bar, In a that snack bar i want 2 different words on which we have to perform 2 different actions.

enter image description here

8

There are 8 answers

5
Elias N On BEST ANSWER

From the Google design specifications:

Each snackbar may contain a single action, neither of which may be “Dismiss” or “Cancel.”

For multiple actions, use a dialog.

2
AiVision On

As @Elias N answer's each Snackbar may contain a single action. If you want to set more then action in Snackbar then you need to create your own layout. Please try this i hope this will help you.

Create one xml file my_snackbar.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="50dp"
              android:background="#000000">
    <TextView
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_weight=".7"
        android:gravity="center_vertical"
        android:text="Please select any one"
        android:textColor="@color/white"/>

    <TextView
        android:id="@+id/txtOne"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_weight=".1"
        android:gravity="center"
        android:text="ONE"
        android:textColor="@color/red"/>
    <TextView
        android:id="@+id/txtTwo"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_weight=".1"
        android:gravity="center"
        android:text="TWO"
        android:textColor="@color/red"/>
</LinearLayout>

Now in your activity file do the following code.

public void myCustomSnackbar()
{
    // Create the Snackbar
    LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    Snackbar snackbar = Snackbar.make(llShow, "", Snackbar.LENGTH_LONG);
    // Get the Snackbar's layout view
    Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
    layout.setPadding(0,0,0,0);
    // Hide the text
    TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
    textView.setVisibility(View.INVISIBLE);

    LayoutInflater mInflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
    // Inflate our custom view
    View snackView = getLayoutInflater().inflate(R.layout.my_snackbar, null);
    // Configure the view
    TextView textViewOne = (TextView) snackView.findViewById(R.id.txtOne);

    textViewOne.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.i("One", "First one is clicked");
        }
    });

    TextView textViewTwo = (TextView) snackView.findViewById(R.id.txtTwo);
    textViewTwo.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        Log.i("Two", "Second one is clicked");
        }
    });

    // Add the view to the Snackbar's layout
    layout.addView(snackView, objLayoutParams);
    // Show the Snackbar
    snackbar.show();
}

For more detail please read this documentation and here.

0
Slion On

Here is a proper solution with Kotlin I first deployed it when working on Fulguris.

Using Kotlin extension we expand our Snackbar class as follows:

/**
* Adds an extra action button to this snackbar.
* [aLayoutId] must be a layout with a Button as root element.
* [aLabel] defines new button label string.
* [aListener] handles our new button click event.
*/
fun Snackbar.addAction(@LayoutRes aLayoutId: Int, @StringRes aLabel: Int, aListener: View.OnClickListener?) : Snackbar {
    addAction(aLayoutId,context.getString(aLabel),aListener)
    return this;
}

/**
* Adds an extra action button to this snackbar.
* [aLayoutId] must be a layout with a Button as root element.
* [aLabel] defines new button label string.
* [aListener] handles our new button click event.
*/
fun Snackbar.addAction(@LayoutRes aLayoutId: Int, aLabel: String, aListener: View.OnClickListener?) : Snackbar {
    // Add our button
    val button = LayoutInflater.from(view.context).inflate(aLayoutId, null) as Button
    // Using our special knowledge of the snackbar action button id we can hook our extra button next to it
    view.findViewById<Button>(R.id.snackbar_action).let {
        // Copy layout
        button.layoutParams = it.layoutParams
        // Copy colors
        (button as? Button)?.setTextColor(it.textColors)
        (it.parent as? ViewGroup)?.addView(button)
    }
    button.text = aLabel
    /** Ideally we should use [Snackbar.dispatchDismiss] instead of [Snackbar.dismiss] though that should do for now */
    //extraView.setOnClickListener {this.dispatchDismiss(BaseCallback.DISMISS_EVENT_ACTION); aListener?.onClick(it)}
    button.setOnClickListener {this.dismiss(); aListener?.onClick(it)}
    return this;
}

We then need to define our button resource:

<?xml version="1.0" encoding="utf-8"?>
<!--
Used to create and extra button in our snackbar popup messages.
Though most properties including layout params and colors are overridden at runtime.
They are just copied from the standard snackbar action button to make sure they both lookalike.
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/snackbar_extra_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginStart="0dp"
android:layout_gravity="center_vertical|right|end"
android:paddingTop="14dp"
android:paddingBottom="14dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:textColor="?attr/colorAccent"
style="?attr/borderlessButtonStyle"/>

Here is how you use it:

Snackbar.make(aView, aMessage, aDuration).setAction(R.string.button_one) {
    // Do your thing after regular button press
}.addAction(R.layout.snackbar_extra_button, R.string.button_two){
    //Do your thing after extra button push
        }.show()
0
weilin wang On

You can use "dismiss" as another actions

        Snackbar snackbar = Snackbar.make(requireView(), "Marked as read", BaseTransientBottomBar.LENGTH_SHORT);
        snackbar.setAction("undo", view -> {
            //undo action
        });
        snackbar.addCallback(new Snackbar.Callback() {
            @Override
            public void onDismissed(Snackbar transientBottomBar, int event) {
               //dismiss action
            }
        });
        snackbar.show();
1
Miguel gramacho On

Following Shaileshs solution:

snackbar class

public class SnackbarOfflineErrorNotification {
/**
 * A view from the content layout.
 */
@NonNull
private final View view;

@NonNull
private Context context;

/**
 * The snack bar being shown.
 */
@Nullable
private Snackbar snackbar = null;

/**
 * Construct a new instance of the notification.
 *
 * @param view A view from the content layout, used to seek an appropriate anchor for the
 *             Snackbar.
 */
public SnackbarOfflineErrorNotification(@NonNull final View view, @NonNull Context context) {
    this.view = view;
    this.context = context;
}

public void showOfflineError (){
    if (snackbar == null){
        //create snackbar
        snackbar = Snackbar.make(this.view, R.string.offline_text, LENGTH_INDEFINITE);

        // Create the Snackbar
        LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        // Get the Snackbar's layout view
        Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
        layout.setPadding(0,0,0,0);
        // Hide the text
        TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
        textView.setVisibility(View.INVISIBLE);

        // Inflate our custom view
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View snackView = inflater.inflate(R.layout.snackbar_offline, null);
        // Configure the view
        Button btnOne = (Button) snackView.findViewById(R.id.btnOne);

        btnOne.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // action 1
            }
        });

        Button btnTwo = (Button) snackView.findViewById(R.id.btnTwo);
        btnTwo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // action 2
            }
        });

        // Add the view to the Snackbar's layout
        layout.addView(snackView, objLayoutParams);

        // Show the Snackbar
        snackbar.show();
    }

}

/**
 * Hides the currently displayed error.
 */
public void hideError() {
    if (snackbar != null) {
        snackbar.dismiss();
        snackbar = null;
    }
}
}

snackbar xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#000000">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="50dp"
    android:layout_weight=".7"
    android:gravity="center_vertical"
    android:text="offline"
    android:textColor="@color/white"
    android:paddingLeft="16dp"/>

<Button
    android:id="@+id/btnOne"
    android:layout_width="wrap_content"
    android:layout_height="50dp"
    android:layout_weight=".1"
    android:gravity="center"
    android:text="one" />

<Button
    android:id="@+id/btnTwo"
    android:layout_width="wrap_content"
    android:layout_height="50dp"
    android:layout_weight=".1"
    android:gravity="center"
    android:text="two"/>
</LinearLayout>

target activity

constructor(){
    snackbarOfflineErrorNotification = new SnackbarOfflineErrorNotification(findViewById(R.id.coordinator_layout), getApplicationContext());
}

public void hideSnackbar(){
    snackbarOfflineErrorNotification.hideError();
}

public showSnackbar(){
    snackbarOfflineErrorNotification.showOfflineError();
}
0
John Domnic George On

Another hacky workaround you could try (works in my case).

    final Snackbar snackbar = Snackbar.make(view, "UNDO MARKED AS READ", Snackbar.LENGTH_LONG);
    snackbar.setAction("DISMISS", new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (snackbar != null)
                snackbar.dismiss();
        }
    });
    View snackbarView = snackbar.getView();
    int snackbarTextId = android.support.design.R.id.snackbar_text;
    TextView textView = (TextView) snackbarView.findViewById(snackbarTextId);
    textView.setTextColor(Color.WHITE);
    textView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (snackbar != null)
                snackbar.dismiss();
            // undo mark as unread code
        }
    });
    snackbar.show();
1
Ashwin On

Thanks Shailesh, I had to modify the code in order to make it work for me.

my_snackbar.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:id="@+id/my_snackbar_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/dark_grey"
    android:padding="15dp">

    <TextView
        android:id="@+id/message_text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight=".6"
        android:gravity="center_vertical"
        android:text="Two button snackbar"
        android:textColor="@color/white"/>

    <TextView
        android:id="@+id/first_text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight=".2"
        android:gravity="center"
        android:text="ONE"
        android:textColor="#FFDEAD"/>

    <TextView
        android:id="@+id/second_text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight=".2"
        android:gravity="center"
        android:text="TWO"
        android:textColor="#FFDEAD"/>

</LinearLayout> 

In your activity call this method whenever you want to show the snackbar:

 private void showTwoButtonSnackbar() {

    // Create the Snackbar
    LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    snackbar = Snackbar.make(this.findViewById(android.R.id.content), message, Snackbar.LENGTH_INDEFINITE);

    // Get the Snackbar layout view
    Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();

    // Set snackbar layout params
    int navbarHeight = getNavBarHeight(this);
    FrameLayout.LayoutParams parentParams = (FrameLayout.LayoutParams) layout.getLayoutParams();
    parentParams.setMargins(0, 0, 0, 0 - navbarHeight + 50);
    layout.setLayoutParams(parentParams);
    layout.setPadding(0, 0, 0, 0);
    layout.setLayoutParams(parentParams);

    // Inflate our custom view
    View snackView = getLayoutInflater().inflate(R.layout.my_snackbar, null);

    // Configure our custom view
    TextView messageTextView = (TextView) snackView.findViewById(R.id.message_text_view);
    messageTextView.setText(message);

    TextView textViewOne = (TextView) snackView.findViewById(R.id.first_text_view);
    textViewOne.setText("ALLOW");
    textViewOne.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("Allow", "showTwoButtonSnackbar() : allow clicked");
            snackbar.dismiss();
        }
    });

    TextView textViewTwo = (TextView) snackView.findViewById(R.id.second_text_view);
    textViewTwo.setText("DENY");
    textViewTwo.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("Deny", "showTwoButtonSnackbar() : deny clicked");
            snackbar.dismiss();
        }
    });

    // Add our custom view to the Snackbar's layout
    layout.addView(snackView, objLayoutParams);

    // Show the Snackbar
    snackbar.show();
}

To get nav bar height:

public static int getNavBarHeight(Context context) {
    int result = 0;
    int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = context.getResources().getDimensionPixelSize(resourceId);
    }
    return result;
} 
2
Jatin Dhankhar On

You can use BottomSheetDialog and disguise it as a SnackBar. Only difference would be that it will be dismissed by swiping down instead of right and it can stay there until user dismissed it while SnackBar eventually fades away.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fragment_history_menu_bottom"
    style="@style/Widget.Design.BottomNavigationView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:orientation="horizontal"
    android:background="@color/cardview_dark_background"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior">


    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/appCompatTextView"
        android:layout_width="wrap_content"
        android:layout_height="19dp"
        android:layout_gravity="center_vertical"

        android:layout_marginStart="8dp"
        android:layout_weight="0.6"
        android:text="Load More ?"
        android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
        android:textColor="@color/cardview_light_background"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <LinearLayout
        android:id="@+id/fragment_history_bottom_sheet_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right|end"
        android:layout_weight="0.4"
        android:clickable="true"
        android:focusable="true"
        android:foreground="?android:attr/selectableItemBackground"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <android.support.v7.widget.AppCompatButton
            style="@style/Widget.AppCompat.Button.Borderless.Colored"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Yes" />

        <android.support.v7.widget.AppCompatButton
            style="@style/Widget.AppCompat.Button.Borderless"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="No"
            android:textColor="@color/cardview_light_background" />
    </LinearLayout>
</android.support.constraint.ConstraintLayout>

and use it as following (Kotlin)

val dialog = BottomSheetDialog(this)
    dialog.setContentView(this.layoutInflater.inflate(R.layout.bottom_sheet_load_prompt,null))
    dialog.show()

result will be similar to SnackBar

Similar to SnackBar