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.
Can we perform 2 different actions in Snack bar at a time in android?
27.6k views Asked by Anjali Patel AtThere are 8 answers
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.
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()
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();
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();
}
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();
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;
}
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
From the Google design specifications:
For multiple actions, use a dialog.