Como definir a cor do texto da barra de ferramentas de suporte para algo diferente de android: textColor?

94

Comecei a usar o novo Snackbar na Biblioteca de Suporte a Design, mas descobri que quando você define "android: textColor" em seu tema, ele se aplica à cor do texto da barra de ferramentas. Obviamente, isso é um problema se a cor primária do texto for escura.

insira a descrição da imagem aqui

Alguém conhece uma maneira de contornar isso ou tem algum conselho sobre como devo colorir meu texto?

EDITAR janeiro de 2017: (Pós-resposta)

Embora existam algumas soluções personalizadas para corrigir o problema abaixo, provavelmente é bom fornecer a maneira correta de criar Snackbars de tema.

Em primeiro lugar, você provavelmente não deveria definir android:textColorseus temas (a menos que realmente conheça o escopo do que está usando o tema). Isso define a cor do texto de basicamente todas as visualizações que se conectam ao seu tema. Se você deseja definir cores de texto em suas visualizações que não são padrão, use android:primaryTextColore faça referência a esse atributo em suas visualizações personalizadas.

No entanto, para aplicar temas a Snackbar, consulte este guia de qualidade de um documento de material de terceiros: http://www.materialdoc.com/snackbar/ (Siga a implementação do tema programático para que não dependa de um estilo xml)

Para referência:

// 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);  

(Você também pode criar seus próprios Snackbarlayouts personalizados , consulte o link acima. Faça-o se este método parecer muito hacky e você quiser uma maneira confiável de manter seu Snackbar personalizado por último por meio de possíveis atualizações da biblioteca de suporte).

Em alternativa, consulte as respostas abaixo para obter respostas semelhantes e talvez mais rápidas para resolver o seu problema.

Mahonster
fonte
obrigado pela solução! o nome da propriedade na verdade éandroid:textColorPrimary
muetzenflo
Obrigado por esta explicação abrangente.
Bugs acontecem de
"você provavelmente não deveria definir android: textColor em seus temas ..." essa foi a chave para mim, obrigado!
Tyler

Respostas:

41

Eu sei que isso já foi respondido, mas a maneira mais fácil que encontrei foi diretamente no make usando o Html.fromHtmlmétodo e uma fonttag

Snackbar.make(view, 
       Html.fromHtml("<font color=\"#ffffff\">Tap to open</font>").show()
JPM
fonte
3
Prefiro essa solução por se tratar de uma única linha.
Lahiru Chandima
1
Esta não é a solução real para essa questão. Use: snackbar.setActionTextColor (Color.WHITE) .show ();
Ahamadullah Saikat
Há / havia um bug na configuração do Snackbar, a cor não fazia nada. Essa forma funciona de qualquer maneira, mas pode não ser a solução ideal para outras pessoas.
JPM
Isso requer nível de API> 24.
frank17
171

Eu encontrei isso em Quais são os novos recursos da Android Design Support Library e como usar seu Snackbar?

Isso funcionou para mim para alterar a cor do texto em um Snackbar.

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();



ATUALIZAÇÃO: ANDROIDX: Como dblackker aponta nos comentários, com a nova biblioteca de suporte AndroidX, o código para encontrar o ID de Snackbar TextView muda para:

TextView tv = view.findViewById(com.google.android.material.R.id.snackbar_text);
tv.setTextColor(ContextCompat.getColor(requireContext(), R.color.someColor))
Jarod Young
fonte
2
Caso alguém esteja procurando inutilmente uma maneira de alterar o tamanho do texto de um Snackbar, é isso!
Janis Peisenieks de
2
Para sua informação, você pode fazer o mesmo com o texto de ação usando em snackbar_actionvez de snackbar_text. Veja esta resposta para um exemplo: stackoverflow.com/a/36800101/293280
Joshua Pinter
7
Isso é um hack na melhor das hipóteses - o que acontece quando o ID para android.support.design.R.id.snackbar_text muda em uma versão futura da biblioteca de suporte? Não existe algum tipo de estilo SnackBar padrão que pode ser substituído em styles.xml?
DiscDev
7
Esse ID foi realmente alterado em uma versão futura da biblioteca de suporte, estou recebendo um ponteiro nulo agora.
CaptainForge
3
Atualizar - com o androidx, o id agora é o seguinte:snack.view.findViewById(com.google.android.material.R.id.snackbar_text) as TextView
dblackker
15

Hackear android.support.design.R.id.snackbar_texté frágil, uma maneira melhor ou menos hacky de fazer isso é:

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
fonte
15

Criei esta função de extensão kotlin que uso em meus projetos:

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

    return this
}

Uso como você esperaria:

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

Richard
fonte
Adoro o uso simples dos métodos de extensão Kotlin! ;-)
Patrick Kuijpers
12
Use com.google.android.material.R.id.snackbar_textse você migrar para o AndroidX.
Rishabh876
14

Tudo bem, então eu corrigi basicamente reorganizando a forma como faço as cores do texto.

No meu tema claro, eu defini android:textColorPrimarycomo normal dark texteu queria e eu defini android:textColorcomo white.

Eu atualizei todas as minhas visualizações de texto e botões para ter android:textColor="?android:attr/textColorPrimary".

Então porque snack-retira textColor, eu apenas definir todo o meu outro texto textColorPrimary.

EDITAR DE JANEIRO DE 2017: ---------------------------------------------- ------

Portanto, como dizem os comentários, e conforme declarado na questão original editada acima, você provavelmente não deve definir android:textColorem seus temas, pois isso altera a cor do texto de cada visualização dentro do tema.

Mahonster
fonte
Acabei de concluir esta tarefa, ufa, demorou um pouco! No entanto, eu precisava usar o método "m vai" abaixo para minha atividade de Preferências antiquada (usando o preferences.xml). Acho que deixou o estilo do meu aplicativo com base no tema muito mais correto, o que é bom. +1
OceanLife de
1
Não é uma boa solução IMO, eu quero manter meu tema atual para o textview e apenas mudar a cor do texto do snakbar ...
issamux
1
Você não deve definir android:textColorem seu tema. É um atributo de estilo de TextView. Se você defini-lo em seu tema, você substitui a cor do texto de todos TextViewou Buttonque não especifica sua cor de texto em XML. Essa também é a mensagem da barra de ferramentas que normalmente pegaria cor de sua sobreposição de tema escuro .
Eugen Pechanec
12

Uma abordagem é usar spans:

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();

Com spans, você também pode adicionar várias cores e estilos dentro de um Snackbar. Aqui está um bom guia:

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

ulcica
fonte
9

Se você migrou para o androidX, use em com.google.android.material.R.id.snackbar_textvez de android.support.design.R.id.snackbar_textpara alterar a cor do texto na barra de ferramentas .

Rohit Maurya
fonte
Você merece uma medalha.
frank17,
@ frank17, foi mencionado em vários comentários aqui.
CoolMind
6

A única maneira que vejo é usando getView()e percorrendo seu filho. Não sei se vai funcionar, e é ruim como parece. Espero que eles adicionem alguma API sobre esse problema em breve.

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
fonte
6

Se você for migrar seu código para o AndroidX, a propriedade TextView agora é:

com.google.android.material.R.id.snackbar_text
Matjaz Kristl
fonte
2

É o que eu uso quando preciso de cores personalizadas

    @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;
    }

E consumido como:

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

Eu mudei meu tema

Theme.AppCompat.Light.NoActionBar

para

Theme.AppCompat.NoActionBar 

Funcionou. Tente usar um tema simples em vez de luz ou outro tema.

Pavneet_Singh
fonte
2

Se você decidir usar a solução suja e hacky para encontrar TextView no Snackbar por id e já migrou para o androidx, então aqui está o código:

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
fonte
1

Você pode usar esta biblioteca: https://github.com/SandroMachado/restaurant

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

Disclaimer: Eu fiz a biblioteca.

Sandro Machado
fonte
1

Encontrar por id não funcionou para mim, então encontrei outra solução:

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
Anrimian
fonte
1

Use o Snackbarincluído na Biblioteca de Componentes de Materiais e aplique o

Algo como:

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();

insira a descrição da imagem aqui

Gabriele Mariotti
fonte
0

Eu tenho um código simples que ajudará a obter uma instância de ambos textview do Snackbar, depois disso você pode chamar todos os métodos que são aplicáveis ​​em um textview.

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));
Summved Jain
fonte
0

Apenas para economizar seu precioso tempo de desenvolvimento, aqui está o método estático que estou usando:

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();
    }
}

Isto é o que parece:

snackbar amarelo com texto preto

Ifta
fonte
0

Se você estiver em Kotlin , poderá criar uma extensão:

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
}

Uso :

yourSnackBar.withTextColor(Color.WHITE).show()
Phil
fonte
mesma resposta que a minha 😉
Richard
0

De acordo com os novos componentes do AndroidX Jitpack

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

Use esta extensão que eu criei

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)
    }
}

Use assim

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
fonte
0

Esta é a minha solução alternativa para resolver este tipo de problema ao androidxusarkotlin

 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()
        }
    }

Você precisa inicializar mContentdentro do onViewCreatedmétodo como abaixo

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

Atualmente (janeiro de 2020) com com.google.android.material:material:1.2.0e provavelmente também1.1.0

É definitivamente a melhor maneira de fazer isso substituindo estes estilos:

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

Se você usar um tema material com .Bridgeno final, por algum motivo, nenhum desses estilos é definido. Então Snackar usará algum layout legado sem esses estilos.

Descobri no código-fonte que ambos snackbarButtonStylee snackbarTextViewStyledevem ser definidos, caso contrário, não serão usados.

Átomo
fonte
-1

Eu também notei o mesmo problema. Graças às respostas aqui, criei uma pequena classe, que pode ajudar a resolver esse problema mais facilmente, apenas substituindo este:

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

com isso:

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

Aqui está minha aula:

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
fonte
1
Este é um hack e depende dos ids de várias visualizações da biblioteca de suporte para serem estáticos. Eu evitaria essa solução a todo custo.
DiscDev