how to customize snackBar's layout?

北战南征 提交于 2019-11-25 18:53:55
Mike

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 Snackbar Snackbar snackbar = Snackbar.make(containerLayout, "", Snackbar.LENGTH_LONG); // Get the Snackbar's layout view Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView(); // Hide the text TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text); textView.setVisibility(View.INVISIBLE);  // Inflate our custom view View snackView = mInflater.inflate(R.layout.my_snackbar, null); // Configure the view ImageView 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 line layout.setPadding(0,0,0,0);  // Add the view to the Snackbar's layout layout.addView(snackView, 0); // Show the Snackbar snackbar.show(); 
Yakiv Mospan

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 right customSnackbar.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);         }     } } 
Mohammad Mahtabi

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> 
Primoz990

The answer is: Don't customize the Snackbar. It should not contain any more elements than a short text and one action. See Google Material design guidelines.

UPDATE: If you anyway want to customize the Snackbar here is what I have implemented in my app:

//generate the snackbar Snackbar sb = Snackbar.make(rootView, snack.text, duration); //set te action button text color sb.setActionTextColor(mCurrentActivity.getResources().getColor(R.color.snack_text_action)); //Get the view of the snackbar View sbView = sb.getView(); //set background color sbView.setBackgroundColor(mCurrentActivity.getResources().getColor(backgroudResId)); //Get the textview of the snackbar text TextView textView = (TextView) sbView.findViewById(android.support.design.R.id.snackbar_text); //set text color textView.setTextColor(mCurrentActivity.getResources().getColor(R.color.snack_text)); //increase max lines of text in snackbar. default is 2. textView.setMaxLines(10); 

I have never tried, but with getting the the root view of the Snackbar, you could programmatically add new views to the Snackbar.

aamitarya

private Snackbar showSnackbar(CoordinatorLayout coordinatorLayout, int duration) { // Create the Snackbar     Snackbar snackbar = Snackbar.make(coordinatorLayout, "", duration);     // 15 is margin from all the sides for snackbar     int marginFromSides = 15;      float height = 100;      //inflate view     View snackView = getLayoutInflater().inflate(R.layout.snackbar_layout, null);      // White background     snackbar.getView().setBackgroundColor(Color.WHITE);     // for rounded edges     snackbar.getView().setBackground(getResources().getDrawable(R.drawable.round_edges));      Snackbar.SnackbarLayout snackBarView = (Snackbar.SnackbarLayout) snackbar.getView();     FrameLayout.LayoutParams parentParams = (FrameLayout.LayoutParams) snackBarView.getLayoutParams();     parentParams.setMargins(marginFromSides, 0, marginFromSides, marginFromSides);     parentParams.height = (int) height;     parentParams.width = FrameLayout.LayoutParams.MATCH_PARENT;     snackBarView.setLayoutParams(parentParams);      snackBarView.addView(snackView, 0);     return snackbar; } 

In onCreate of the Activity:

CoordinatorLayout coordinatorLayout = findViewById(R.id.coordinator_layout);  final Snackbar snackbar = showSnackbar(coordinatorLayout, Snackbar.LENGTH_LONG);             snackbar.show();             View view = snackbar.getView();             TextView tv = (TextView) view.findViewById(R.id.snackbar_action);             tv.setOnClickListener(new View.OnClickListener() {                 @Override                 public void onClick(View v) {                     snackbar.dismiss();                 }             }); 
Nha Phạm Thị

I tried it and it works!

View custom = LayoutInflater.from(this).inflate(R.layout.custom_view, null); snackbar.getView().setPadding(0,0,0,0); ((ViewGroup) snackbar.getView()).removeAllViews(); ((ViewGroup) snackbar.getView()).addView(custom); TextView textView = custom.findViewById(R.id.text); View button = custom.findViewById(R.id.button); textView.setText("Your text here"); button.setOnClickListener(new View.OnClickListener() {     @Override     public void onClick(View v) {        // do something     } }); 
Surendar D

Try the following code.

Snackbar snackbar = Snackbar.make(container, "No Internet Connection", Snackbar.LENGTH_LONG); View sbView = snackbar.getView(); sbView.setBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimary)); snackbar.show(); 

Note:

container - parent view of layout.

Tunji_D

To add to Yakiv Mospan's answer, to make your custom BaseTransientBottomBar show from the bottom like a Snackbar, copy this method from the Snackbar class to find a suitable parent in for the BaseTransientBottomBar constructor.

private static ViewGroup findSuitableParent(View view) {     ViewGroup fallback = null;     do {         if (view instanceof CoordinatorLayout) {             // We've found a CoordinatorLayout, use it             return (ViewGroup) view;         } else if (view instanceof FrameLayout) {             if (view.getId() == android.R.id.content) {                 // If we've hit the decor content view, then we didn't find a CoL in the                 // hierarchy, so use it.                 return (ViewGroup) view;             } else {                 // It's not the content view but we'll use it as our fallback                 fallback = (ViewGroup) view;             }         }          if (view != null) {             // Else, we will loop and crawl up the view hierarchy and try to find a parent             final ViewParent parent = view.getParent();             view = parent instanceof View ? (View) parent : null;         }     } while (view != null);      // If we reach here then we didn't find a CoL or a suitable content view so we'll fallback     return fallback; } 

You can try this library. This is a wrapper for android default snackbar. https://github.com/ChathuraHettiarachchi/CSnackBar

Snackbar.with(this,null)     .type(Type.SUCCESS)     .message("Profile updated successfully!")     .duration(Duration.SHORT)     .show(); 

or you can even use your own view,

View view = getLayoutInflater().inflate(R.layout.custom_view, null);  Snackbar.with(this,null)         .type(Type.UPDATE)         .contentView(view, 76)         .duration(Duration.SHORT)         .show(); 

Currently only issue with custom layout is, we need to pass view height in dp as an input

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!