how to customize snackBar's layout? how to customize snackBar's layout? android android

how to customize snackBar's layout?


The Snackbar does not allow you to set a custom layout. However, as Primoz990 suggested you can get the Snackbar's View. The getView function returns the Snackbar.SnackbarLayout, which is a horizontal LinearLayout object whose children are a TextView and a Button. To add your own View to the Snackbar, you just need to hide the TextView, and add your View to the Snackbar.SnackbarLayout.

// Create the SnackbarSnackbar snackbar = Snackbar.make(containerLayout, "", Snackbar.LENGTH_LONG);// Get the Snackbar's layout viewSnackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();// Hide the textTextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);textView.setVisibility(View.INVISIBLE);// Inflate our custom viewView snackView = mInflater.inflate(R.layout.my_snackbar, null);// Configure the viewImageView imageView = (ImageView) snackView.findViewById(R.id.image);imageView.setImageBitmap(image);TextView textViewTop = (TextView) snackView.findViewById(R.id.text);textViewTop.setText(text);textViewTop.setTextColor(Color.WHITE);//If the view is not covering the whole snackbar layout, add this linelayout.setPadding(0,0,0,0);// Add the view to the Snackbar's layoutlayout.addView(snackView, 0);// Show the Snackbarsnackbar.show();


It is possible starting from 25.1.0 revision of Android Support Library

I. Declare custom layout in your values/layout folder.

<?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="wrap_content"><Button    android:id="@+id/snackbar_action"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginLeft="@dimen/design_snackbar_extra_spacing_horizontal"                  android:layout_marginStart="@dimen/design_snackbar_extra_spacing_horizontal"    android:layout_gravity="center_vertical|right|end"    android:paddingTop="@dimen/design_snackbar_padding_vertical"    android:paddingBottom="@dimen/design_snackbar_padding_vertical"    android:paddingLeft="@dimen/design_snackbar_padding_horizontal"    android:paddingRight="@dimen/design_snackbar_padding_horizontal"    android:visibility="gone"    android:textColor="?attr/colorAccent"    style="?attr/borderlessButtonStyle"/><TextView    android:gravity="center_vertical|right"    android:id="@+id/snackbar_text"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_weight="1"    android:paddingTop="@dimen/design_snackbar_padding_vertical"    android:paddingBottom="@dimen/design_snackbar_padding_vertical"    android:paddingLeft="@dimen/design_snackbar_padding_horizontal"    android:paddingRight="@dimen/design_snackbar_padding_horizontal"    android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"    android:maxLines="@integer/design_snackbar_text_max_lines"    android:layout_gravity="center_vertical|left|start"    android:ellipsize="end"/></LinearLayout>

Hints:

  • Use @dimen/design_snackbar values to match material design guidelines.
  • Use ?attr/colorAccent to apply your Application Theme changes to Snackbar.

II. Extend BaseTransientBottomBar class.

public class final CustomSnackbar extends BaseTransientBottomBar<CustomSnackbar> {/** * Constructor for the transient bottom bar. * * @param parent The parent for this transient bottom bar. * @param content The content view for this transient bottom bar. * @param contentViewCallback The content view callback for this transient bottom bar. */private CustomSnackbar(ViewGroup parent, View content,                ContentViewCallback contentViewCallback) {    super(parent, content, contentViewCallback);}}

III. Add BaseTransientBottomBar.ContentViewCallback

public class final CustomSnackbar ...{...private static class ContentViewCallback implements                           BaseTransientBottomBar.ContentViewCallback {  // view inflated from custom layout  private View content;  public ContentViewCallback(View content) {      this.content = content;  }  @Override  public void animateContentIn(int delay, int duration) {      // add custom *in animations for your views      // e.g. original snackbar uses alpha animation, from 0 to 1      ViewCompat.setScaleY(content, 0f);      ViewCompat.animate(content)                .scaleY(1f).setDuration(duration)                .setStartDelay(delay);  }  @Override  public void animateContentOut(int delay, int duration) {      // add custom *out animations for your views      // e.g. original snackbar uses alpha animation, from 1 to 0      ViewCompat.setScaleY(content, 1f);      ViewCompat.animate(content)                .scaleY(0f)                .setDuration(duration)                .setStartDelay(delay);  }}}

IV. Add method to create Snackbar with custom layout and methods to fill it.

public class final CustomSnackbar ...{...public static CustomSnackbar make(ViewGroup parent, @Duration int duration) { // inflate custom layout LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View content = inflater.inflate(R.layout.snackbar_view, parent, false); // create snackbar with custom view ContentViewCallback callback= new ContentViewCallback(content); CustomSnackbar customSnackbar = new CustomSnackbar(parent, content, callback);// Remove black background padding on left and rightcustomSnackbar.getView().setPadding(0, 0, 0, 0); // set snackbar duration customSnackbar.setDuration(duration); return customSnackbar; } // set text in custom layout public CustomSnackbar setText(CharSequence text) { TextView textView = (TextView) getView().findViewById(R.id.snackbar_text); textView.setText(text); return this; } // set action in custom layout public CustomSnackbar setAction(CharSequence text, final OnClickListener  listener) { Button actionView = (Button) getView().findViewById(R.id.snackbar_action); actionView.setText(text); actionView.setVisibility(View.VISIBLE); actionView.setOnClickListener(new View.OnClickListener() {     @Override     public void onClick(View view) {         listener.onClick(view);         // Now dismiss the Snackbar         dismiss();     } }); return this;}}

V. Create instance of CustomSnackbar and call show() method.

CustomSnackbar customSnackbar = CustomSnackbar.make(rooView,      CustomSnackbar.LENGTH_INDEFINITE);customSnackbar.setText("No network connection!");customSnackbar.setAction("Retry", new View.OnClickListener() {    @Override    public void onClick(View v) {        // handle click here    }});customSnackbar.show();

See more about Snackbar and its customization at materialdoc.com

Full CustomSnackbar.class code :

import android.support.annotation.NonNull;import android.support.design.widget.BaseTransientBottomBar;import android.support.v4.view.ViewCompat;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import android.widget.TextView;public class CustomSnackbar extends BaseTransientBottomBar<CustomSnackbar> {    /**     * Constructor for the transient bottom bar.     *     * @param parent The parent for this transient bottom bar.     * @param content The content view for this transient bottom bar.     * @param callback The content view callback for this transient bottom bar.     */    private CustomSnackbar(ViewGroup parent, View content, ContentViewCallback callback) {        super(parent, content, callback);    }    public static CustomSnackbar make(@NonNull ViewGroup parent, @Duration int duration) {        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());        final View content = inflater.inflate(R.layout.snackbar_view, parent, false);        final ContentViewCallback viewCallback = new ContentViewCallback(content);        final CustomSnackbar customSnackbar = new CustomSnackbar(parent, content, viewCallback);        customSnackbar.getView().setPadding(0, 0, 0, 0);        customSnackbar.setDuration(duration);        return customSnackbar;    }    public CustomSnackbar setText(CharSequence text) {        TextView textView = (TextView) getView().findViewById(R.id.snackbar_text);        textView.setText(text);        return this;    }    public CustomSnackbar setAction(CharSequence text, final View.OnClickListener listener) {        Button actionView = (Button) getView().findViewById(R.id.snackbar_action);        actionView.setText(text);        actionView.setVisibility(View.VISIBLE);        actionView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                listener.onClick(view);                // Now dismiss the Snackbar                dismiss();            }        });        return this;    }    private static class ContentViewCallback implements BaseTransientBottomBar.ContentViewCallback {        private View content;        public ContentViewCallback(View content) {            this.content = content;        }        @Override        public void animateContentIn(int delay, int duration) {            ViewCompat.setScaleY(content, 0f);            ViewCompat.animate(content).scaleY(1f).setDuration(duration).setStartDelay(delay);        }        @Override        public void animateContentOut(int delay, int duration) {            ViewCompat.setScaleY(content, 1f);            ViewCompat.animate(content).scaleY(0f).setDuration(duration).setStartDelay(delay);        }    }}


The XML way:

The original layout xml file that is used for the Snackbar is this file:

design_layout_snackbar_include.xml:

<?xml version="1.0" encoding="utf-8"?>        <merge xmlns:android="http://schemas.android.com/apk/res/android">    <TextView            android:id="@+id/snackbar_text"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"              ...            android:ellipsize="end"/>    <Button            android:id="@+id/snackbar_action"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:visibility="gone"              ...            android:textColor="?attr/colorAccent"            style="?attr/borderlessButtonStyle"/></merge>

So in order to override this layout you should write your own layout with the same android:ids as in this one and in your refs.xml file you should add this line:

<resources xmlns:tools="http://schemas.android.com/tools">   ....       <item name="design_layout_snackbar_include" tools:override="true" type="layout">        @layout/my_layout_snackbar    </item>   ....</resources>