¿Existe algún método para cambiar el diseño de un snackBar a una vista personalizada?
Ahora viene negro y podemos cambiar el color de fondo. ¿Pero no sé la forma correcta de inflar un nuevo diseño y convertirlo en un fondo de snackBars?
Gracias...
¿Existe algún método para cambiar el diseño de un snackBar a una vista personalizada?
Ahora viene negro y podemos cambiar el color de fondo. ¿Pero no sé la forma correcta de inflar un nuevo diseño y convertirlo en un fondo de snackBars?
Gracias...
Respuestas:
Snackbar no le permite establecer un diseño personalizado. Sin embargo, como sugirió Primoz990, puede obtener la Vista de Snackbar. La función getView devuelve Snackbar.SnackbarLayout, que es un objeto LinearLayout horizontal cuyos hijos son TextView y Button. Para agregar su propia Vista a Snackbar, solo necesita ocultar TextView y agregar su Vista a 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();
Es posible a partir de la revisión 25.1.0 de la biblioteca de soporte de Android
I. Declare un diseño personalizado en su carpeta de valores / diseño.
<?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>
Sugerencias:
@dimen/design_snackbar
valores para que coincidan con las pautas de diseño de materiales.?attr/colorAccent
para aplicar los cambios en el tema de la aplicación a Snackbar.II. Amplíe la clase BaseTransientBottomBar .
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. Agregar 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. Agregue un método para crear Snackbar con diseño personalizado y métodos para llenarlo.
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. Crear instancia de CustomSnackbar
y llamar al show()
método.
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();
Vea más sobre Snackbar y su personalización en materialdoc.com
CustomSnackbar.class
Código completo :
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);
}
}
}
El archivo xml de diseño original que se utiliza para el Snackbar
es este archivo:
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>
Entonces, para anular este diseño , debe escribir su propio diseño con los mismos android:id
s que en este y en su refs.xml
archivo debe agregar esta línea:
<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>
BaseTransientBottomBar
, según stackoverflow.com/a/41154330/9636
La respuesta es: no personalice la barra de aperitivos. No debe contener más elementos que un texto breve y una acción. Ver las pautas de diseño de materiales de Google .
ACTUALIZACIÓN: Si de todos modos desea personalizar la barra de aperitivos, esto es lo que he implementado en mi aplicación:
//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);
Nunca lo he intentado, pero al obtener la vista raíz de Snackbar, podría agregar nuevas vistas a Snackbar mediante programación.
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;
}
En onCreate de la actividad:
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();
}
});
¡Lo probé y funciona!
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
}
});
Prueba el siguiente código.
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();
Nota:
contenedor : vista principal del diseño.
Para agregar a la respuesta de Yakiv Mospan, para hacer su BaseTransientBottomBar
presentación personalizada desde la parte inferior como a Snackbar
, copie este método de la Snackbar
clase para encontrar un padre adecuado para el 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;
}
Versión de Kotlin para la respuesta aceptada: https://stackoverflow.com/a/33441214/2437655
private fun showSnackbar() {
val snackbar = Snackbar.make(
binding.root,
"",
Snackbar.LENGTH_INDEFINITE
)
(snackbar.view as Snackbar.SnackbarLayout).apply {
findViewById<View>(R.id.snackbar_text).visibility = View.INVISIBLE
findViewById<View>(R.id.snackbar_action).visibility = View.INVISIBLE
val snackbarBinding = DataBindingUtil.inflate<SnackbarBinding>(
LayoutInflater.from(this@SnackbarActivity),
R.layout.snackbar,
binding.root as ViewGroup,
false
)
setPadding(0, 0, 0, 0)
addView(snackbarBinding.root, 0)
}
snackbar.setDuration(8000).show()
}
Puedes probar esta biblioteca. Este es un contenedor para la barra de aperitivos predeterminada de Android. https://github.com/ChathuraHettiarachchi/CSnackBar
Snackbar.with(this,null)
.type(Type.SUCCESS)
.message("Profile updated successfully!")
.duration(Duration.SHORT)
.show();
o incluso puedes usar tu propia vista,
View view = getLayoutInflater().inflate(R.layout.custom_view, null);
Snackbar.with(this,null)
.type(Type.UPDATE)
.contentView(view, 76)
.duration(Duration.SHORT)
.show();
Actualmente, el único problema con el diseño personalizado es que necesitamos pasar la altura de la vista en dp como entrada