Comment définir la couleur du texte du snackbar de la bibliothèque de support sur autre chose que Android: textColor?

94

J'ai donc commencé à utiliser le nouveau Snackbar dans la bibliothèque de support de conception, mais j'ai trouvé que lorsque vous définissez "android: textColor" dans votre thème, cela s'applique à la couleur du texte du snackbar. C'est évidemment un problème si la couleur de votre texte principale est sombre.

entrez la description de l'image ici

Quelqu'un connaît-il un moyen de contourner ce problème ou a-t-il des conseils sur la façon dont je dois colorer mon texte?

EDIT Janvier 2017: (Post-réponse)

Bien qu'il existe des solutions personnalisées pour résoudre le problème ci-dessous, il est probablement bon de fournir le bon moyen de thème Snackbars.

Premièrement, vous ne devriez probablement pas du tout définir android:textColorvos thèmes (à moins que vous ne connaissiez vraiment la portée de ce qui utilise le thème). Cela définit la couleur du texte de pratiquement toutes les vues qui se connectent à votre thème. Si vous souhaitez définir des couleurs de texte dans vos vues qui ne sont pas par défaut, utilisez android:primaryTextColoret référencez cet attribut dans vos vues personnalisées.

Cependant, pour appliquer des thèmes à Snackbar, veuillez vous reporter à ce guide de qualité à partir d'un document tiers: http://www.materialdoc.com/snackbar/ (Suivez l'implémentation du thème programmatique pour qu'il ne repose pas sur un style xml)

Pour référence:

// create instance
Snackbar snackbar = Snackbar.make(view, text, duration);

// set action button color
snackbar.setActionTextColor(getResources().getColor(R.color.indigo));

// get snackbar view
View snackbarView = snackbar.getView();

// change snackbar text color
int snackbarTextId = android.support.design.R.id.snackbar_text;  
TextView textView = (TextView)snackbarView.findViewById(snackbarTextId);  
textView.setTextColor(getResources().getColor(R.color.indigo));

// change snackbar background
snackbarView.setBackgroundColor(Color.MAGENTA);  

(Vous pouvez également créer vos propres Snackbarmises en page personnalisées , voir le lien ci-dessus. Faites-le si cette méthode vous semble trop piratée et que vous voulez un moyen sûrement fiable de faire durer votre Snackbar personnalisé à travers d'éventuelles mises à jour de la bibliothèque de support).

Et sinon, voir les réponses ci-dessous pour des réponses similaires et peut-être plus rapides pour résoudre votre problème.

Mahonster
la source
merci pour la solution! la propriété est effectivement appeléeandroid:textColorPrimary
muetzenflo
Merci pour cette explication complète.
bugs se produisent le
"vous ne devriez probablement pas du tout définir android: textColor dans vos thèmes ..." c'était la clé pour moi, merci!
Tyler

Réponses:

41

Je sais que cela a déjà été répondu, mais le moyen le plus simple que j'ai trouvé était directement dans la marque en utilisant la Html.fromHtmlméthode et une fontbalise

Snackbar.make(view, 
       Html.fromHtml("<font color=\"#ffffff\">Tap to open</font>").show()
JPM
la source
3
Je préfère cette solution car il s'agit d'une seule ligne.
Lahiru Chandima
1
Ce n’est pas la véritable solution de cette question. Utilisez: snackbar.setActionTextColor (Color.WHITE) .show ();
Ahamadullah Saikat le
Il y a / était un bug dans le réglage du Snackbar, la couleur n'a rien fait. Cette méthode fonctionne quoi qu'il arrive, mais peut ne pas être la solution optimale pour les autres.
JPM
Cela nécessite un niveau d'API> 24.
frank17
171

J'ai trouvé ceci sur Quelles sont les nouvelles fonctionnalités de la bibliothèque de support de conception Android et comment utiliser sa barre de collation?

Cela a fonctionné pour moi pour changer la couleur du texte dans un snack-bar.

Snackbar snack = Snackbar.make(view, R.string.message, Snackbar.LENGTH_LONG);
View view = snack.getView();
TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
tv.setTextColor(Color.WHITE);
snack.show();



MISE À JOUR: ANDROIDX: Comme le souligne dblackker dans les commentaires, avec la nouvelle bibliothèque de support AndroidX, le code pour trouver l'ID de Snackbar TextView change en:

TextView tv = view.findViewById(com.google.android.material.R.id.snackbar_text);
tv.setTextColor(ContextCompat.getColor(requireContext(), R.color.someColor))
Jarod Young
la source
2
Juste au cas où quelqu'un d'autre chercherait en vain un moyen de changer la taille du texte d'un Snackbar, c'est tout!
Janis Peisenieks
2
Pour info, vous pouvez faire de même avec le texte Action en utilisant snackbar_actionau lieu de snackbar_text. Voir cette réponse pour un exemple: stackoverflow.com/a/36800101/293280
Joshua Pinter
7
Il s'agit au mieux d'un hack - que se passe-t-il lorsque l'ID de android.support.design.R.id.snackbar_text change dans une future version de la bibliothèque de support? N'existe-t-il pas une sorte de style SnackBar par défaut qui peut être remplacé dans styles.xml?
DiscDev
7
Cet identifiant a en effet été modifié dans une future version de la bibliothèque de support, je reçois maintenant un pointeur nul.
CaptainForge
3
Mise à jour - avec androidx, l'identifiant est maintenant le suivant:snack.view.findViewById(com.google.android.material.R.id.snackbar_text) as TextView
dblackker
15

Le piratage android.support.design.R.id.snackbar_textest fragile, une manière meilleure ou moins pirate de le faire sera:

String snackText = getResources().getString(YOUR_RESOURCE_ID);
SpannableStringBuilder ssb = new SpannableStringBuilder()
    .append(snackText);
ssb.setSpan(
    new ForegroundColorSpan(Color.WHITE),
    0,
    snackText.length(),
    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Snackbar.make(
        getView(),
        ssb,
        Snackbar.LENGTH_SHORT)
        .show();
Jet Zhao
la source
15

J'ai créé cette fonction d'extension de kotlin que j'utilise dans mes projets:

fun Snackbar.setTextColor(color: Int): Snackbar {
    val tv = view.findViewById(android.support.design.R.id.snackbar_text) as TextView
    tv.setTextColor(color)

    return this
}

Utilisation comme vous vous attendez:

Snackbar.make (vue, R.string.your_string, Snackbar.LENGTH_LONG) .setTextColor (Color.WHITE) .show ()

Richard
la source
J'adore l'utilisation simple des méthodes d'extention Kotlin! ;-)
Patrick Kuijpers
12
À utiliser com.google.android.material.R.id.snackbar_textsi vous migrez vers AndroidX.
Rishabh876
14

D'accord, j'ai donc résolu le problème en réorganisant essentiellement la façon dont je fais les couleurs du texte.

Dans mon thème clair, je me suis mis android:textColorPrimaryaunormal dark text je voulais, et je me suis mis android:textColoràwhite .

J'ai mis à jour toutes mes vues de texte et mes boutons pour avoir android:textColor="?android:attr/textColorPrimary".

Donc, parce que le snack s'inspire de textColor , je viens de définir tous mes autres textes sur textColorPrimary.

MODIFIER JANVIER 2017: ---------------------------------------------- ------

Donc, comme le disent les commentaires, et comme indiqué dans la question originale modifiée ci-dessus, vous ne devriez probablement pas définir android:textColordans vos thèmes, car cela change la couleur du texte de chaque vue à l'intérieur du thème.

Mahonster
la source
Je viens de terminer cette tâche, ouf, cela a pris du temps! Cependant, j'avais besoin d'utiliser la méthode "m vai" ci-dessous pour mon activité obsolète Préférences (en utilisant preferences.xml). Je pense que le style de mon application est beaucoup plus correctement basé sur le thème, ce qui est bien. +1
OceanLife
1
Pas une bonne solution IMO, je veux garder mon thème actuel pour la visualisation de texte et simplement changer la couleur du texte de la snakbar ...
Issamux
1
Vous n'êtes pas du tout censé définir android:textColorvotre thème. C'est un attribut de style de TextView. Si vous le définissez dans votre thème, vous remplacez la couleur du texte de tout TextViewou Buttonqui ne spécifie pas sa couleur de texte en XML. Cela se trouve également être le message du snack-bar qui prend normalement la couleur de sa superposition de thème sombre .
Eugen Pechanec
12

Une approche consiste à utiliser des travées:

final ForegroundColorSpan whiteSpan = new ForegroundColorSpan(ContextCompat.getColor(this, android.R.color.white));
SpannableStringBuilder snackbarText = new SpannableStringBuilder("Hello, I'm white!");
snackbarText.setSpan(whiteSpan, 0, snackbarText.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);

Snackbar.make(view, snackbarText, Snackbar.LENGTH_LONG)
                .show();

Avec les travées, vous pouvez également ajouter plusieurs couleurs et styles dans un seul Snackbar. Voici un bon guide:

https://androidbycode.wordpress.com/2015/06/06/material-design-snackbar-using-the-design-support-library/

ulcica
la source
9

Si vous avez migré vers androidX, utilisez com.google.android.material.R.id.snackbar_textplutôt que android.support.design.R.id.snackbar_textpour changer la couleur du texte sur le snackbar.

Rohit Maurya
la source
Tu mérites une médaille.
frank17
@ frank17, cela a été mentionné dans plusieurs commentaires ici.
CoolMind
6

La seule façon que je vois est d'utiliser getView()et de parcourir son enfant. Je ne sais pas si ça va marcher, et c'est mauvais comme ça en a l'air. J'espère qu'ils ajouteront bientôt une API sur ce problème.

Snackbar snack = Snackbar.make(...);
ViewGroup group = (ViewGroup) snack.getView();
for (int i = 0; i < group.getChildCount(); i++) {
    View v = group.getChildAt(i);
    if (v instanceof TextView) {
        TextView t = (TextView) v;
        t.setTextColor(...)
    }
}
snack.show();
natario
la source
6

Si vous allez migrer votre code vers AndroidX, la propriété TextView est maintenant:

com.google.android.material.R.id.snackbar_text
Matjaz Kristl
la source
2

C'est ce que j'utilise lorsque j'ai besoin de couleurs personnalisées

    @NonNull
    public static Snackbar makeSnackbar(@NonNull View layout, @NonNull CharSequence  text, int duration, int backgroundColor, int textColor/*, int actionTextColor*/){
        Snackbar snackBarView = Snackbar.make(layout, text, duration);
        snackBarView.getView().setBackgroundColor(backgroundColor);
        //snackBarView.setActionTextColor(actionTextColor);
        TextView tv = (TextView) snackBarView.getView().findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(textColor);
        return snackBarView;
    }

Et consommé comme:

CustomView.makeSnackbar(view, "Hello", Snackbar.LENGTH_LONG, Color.YELLOW,Color.CYAN).setAction("DO IT", myAction).show();
makata
la source
2

J'ai changé de thème

Theme.AppCompat.Light.NoActionBar

à

Theme.AppCompat.NoActionBar 

Cela a fonctionné Essayez d'utiliser un thème simple au lieu d'un thème léger ou autre.

Pavneet_Singh
la source
2

Si vous décidez d'utiliser la solution sale et hacky avec la recherche de TextView dans Snackbar par identifiant et que vous avez déjà migré vers androidx, voici le code:

val textViewId = com.google.android.material.R.id.snackbar_text
val snackbar = Snackbar.make(view, "Text", Snackbar.LENGTH_SHORT)
val textView = snackbar.view.findViewById(textViewId) as TextView
textView.setTextColor(Color.WHITE)
Grzegorz Matyszczak
la source
1

Vous pouvez utiliser cette bibliothèque: https://github.com/SandroMachado/restaurant

new Restaurant(MainActivity.this, "Snackbar with custom text color", Snackbar.LENGTH_LONG)
    .setTextColor(Color.GREEN)
    .show();

Avertissement: j'ai fait la bibliothèque.

Sandro Machado
la source
1

Find by id n'a pas fonctionné pour moi, j'ai donc trouvé une autre solution:

Snackbar snackbar = Snackbar.make(view, text, duration);//just ordinary creation

ViewGroup snackbarView = (ViewGroup) snackbar.getView();
SnackbarContentLayout contentLayout = (SnackbarContentLayout) snackbarView.getChildAt(0);
TextView tvText = contentLayout.getMessageView();
tvText.setTextColor(/*your color here*/);

//set another colors, show, etc
Anrimien
la source
1

Utilisez le Snackbarinclus dans la bibliothèque de composants de matériaux et appliquez le

  • setTextColor pour définir la couleur du texte
  • setActionTextColorpour définir la couleur du texte utilisée par l'action. Vous pouvez utiliser une couleur ou un sélecteur de couleur
  • setBackgroundTint pour définir la couleur de fond du Snackbar

Quelque chose comme:

Snackbar snackbar = Snackbar.make(view, "My custom Snackbar", Snackbar.LENGTH_LONG);        
snackbar.setTextColor(ContextCompat.getColor(this,R.color.xxxxx));
snackbar.setActionTextColor(ContextCompat.getColor(this,R.color.my_selector));
snackbar.setBackgroundTint(ContextCompat.getColor(this,R.color.xxxx));
snackbar.show();

entrez la description de l'image ici

Gabriele Mariotti
la source
0

J'ai un code simple qui aidera à obtenir une instance à la fois de la vue de texte de Snackbar, après cela, vous pouvez appeler toutes les méthodes applicables à une vue de texte.

Snackbar snackbar = Snackbar.make( ... )    // Create Snack bar


snackbar.setActionTextColor(getResources().getColor(R.color.white));  //if you directly want to apply the color to Action Text

TextView snackbarActionTextView = (TextView) snackbar.getView().findViewById( android.support.design.R.id.snackbar_action );

snackbarActionTextView.setTextColor(Color.RED);  //This is another way of doing it

snackbarActionTextView.setTypeface(snackbarActionTextView.getTypeface(), Typeface.BOLD);

//Below Code is to modify the Text in Snack bar
TextView snackbarTextView = (TextView) snackbar.getView().findViewById(android.support.design.R.id.snackbar_text);
snackbarTextView.setTextSize( 16 );
snackbarTextView.setTextColor(getResources().getColor(R.color.white));
Jain sommé
la source
0

Juste pour économiser votre précieux temps de développement, voici la méthode statique que j'utilise:

public static void snack(View view, String message) {
    if (!TextUtils.isEmpty(message)) {
        Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT);
        snackbar.getView().setBackgroundColor(Color.YELLOW);
        TextView tv =  snackbar.getView().findViewById(android.support.design.R.id.snackbar_text); //snackbar_text
        tv.setTextColor(Color.BLACK);
        snackbar.show();
    }
}

Voici à quoi ça ressemble:

snack-bar jaune avec texte noir

Ifta
la source
0

Si vous êtes à Kotlin , vous pouvez créer une extension:

fun Snackbar.withTextColor(color: Int): Snackbar {
    val tv = this.view.findViewById(android.support.design.R.id.snackbar_text) as TextView
    tv.setTextColor(color)
    return this
}

Utilisation :

yourSnackBar.withTextColor(Color.WHITE).show()
Phil
la source
même réponse que la mienne 😉
Richard
0

Selon les nouveaux composants AndroidX Jitpack

implementation 'com.google.android.material:material:1.0.0'

Utilisez cette extension que j'avais créée

inline fun View.snack(message: String, length: Int = Snackbar.LENGTH_LONG,
 f: Snackbar.() -> Unit) {
val snack = Snackbar.make(this, message, length)
snack.f()
snack.show()
}

fun Snackbar.action(action: String, actionColor: Int? = null, textColor: Int? = null, listener: (View) -> Unit) {
setAction(action, listener)
actionColor?.let {
    setActionTextColor(it)
    }
textColor?.let {
    this.view.findViewById<TextView>(R.id.snackbar_text).setTextColor(it)
    }
}

Utilisez-le comme ça

btn_login.snack(
        getString(R.string.fields_empty_login),
        ContextCompat.getColor(this@LoginActivity, R.color.whiteColor)
    ) {
        action(getString(R.string.text_ok), ContextCompat.getColor(this@LoginActivity, R.color.gray_300),ContextCompat.getColor(this@LoginActivity, R.color.yellow_400)) {
            this@snack.dismiss()
        }
    }
Manoj Perumarath
la source
0

C'est ma solution de contournement pour résoudre ce type de problème lors de l' androidxutilisationkotlin

 fun showSnackBar(message: String) {
        mContent?.let {
            val snackbar = Snackbar.make(it, message, Snackbar.LENGTH_LONG)
            val snackbarView = snackbar.view
            val tv = snackbarView.findViewById<TextView>(R.id.snackbar_text)
            tv.setTextColor(Color.WHITE) //change the color of text
            tv.maxLines = 3 //specify the limit of text line
            snackbar.duration = BaseTransientBottomBar.LENGTH_SHORT //specify the duraction of text message
            snackbar.show()
        }
    }

Vous devez initialiser à l' mContentintérieur de la onViewCreatedméthode comme ci-dessous

var mContent: View? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mContent = view
    }
Suraj Bahadur
la source
0

Actuellement (janvier 2020) avec com.google.android.material:material:1.2.0 et probablement aussi1.1.0

Est certainement la meilleure façon de le faire en remplaçant ces styles:

<item name="snackbarStyle">@style/Widget.MaterialComponents.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.MaterialComponents.Snackbar.TextView</item>

Si vous utilisez un thème matériel avec .Bridge à la fin, pour une raison quelconque, aucun de ces styles n'est défini. Snackar utilisera donc une mise en page héritée sans ces styles.

J'ai trouvé dans le code source que les deux snackbarButtonStyleet snackbarTextViewStyledoivent être définis sinon il ne sera pas utilisé.

Atome
la source
-1

J'ai également remarqué le même problème. Grâce aux réponses ici, j'ai créé une petite classe, qui peut aider à résoudre ce problème plus facilement, simplement en remplaçant ceci:

Snackbar.make(view, "Error", Snackbar.LENGTH_LONG).show();

avec ça:

Snackbar2.make(view, "Error", Snackbar.LENGTH_LONG).show();

Voici ma classe:

public class Snackbar2 {
static public Snackbar make(View view, int resid, int duration){
    Snackbar result = Snackbar.make(view, resid, duration);
    process(result);
    return result;
}
static public Snackbar make(View view, String text, int duration){
    Snackbar result = Snackbar.make(view, text, duration);
    process(result);
    return result;
}
static private void process(Snackbar snackbar){
    try {
        View view1= snackbar.getView();

        TextView tv = (TextView) view1.findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(Color.WHITE);

    }catch (Exception ex)
    {
        //inform about error
        ex.printStackTrace();
    }
}

}

Dr Failov
la source
1
Il s'agit d'un piratage et repose sur les identifiants de diverses vues de la bibliothèque de support pour être statiques. J'éviterais à tout prix cette solution.
DiscDev