Как установить цвет текста панели поддержки библиотеки на что-то другое, кроме android: textColor?

95

Итак, я начал использовать новую панель закусок в библиотеке поддержки дизайна, но обнаружил, что когда вы определяете "android: textColor" в своей теме, он применяется к цвету текста панели закусок. Очевидно, это проблема, если ваш основной цвет текста темный.

введите описание изображения здесь

Кто-нибудь знает способ обойти это или есть совет, как мне раскрасить текст?

ИЗМЕНИТЬ Январь 2017: (Пост-ответ)

Несмотря на то, что есть несколько индивидуальных решений для устранения проблемы, указанной ниже, вероятно, было бы хорошо предоставить правильный способ оформления Snackbars.

Во-первых, вам, вероятно, вообще не следует определять android:textColorв своих темах (если вы действительно не знаете масштаб того, что использует тема). Это устанавливает цвет текста практически для каждого представления, которое связано с вашей темой. Если вы хотите определить цвета текста в ваших представлениях, которые не используются по умолчанию, используйте android:primaryTextColorэтот атрибут и укажите ссылку на него в ваших пользовательских представлениях.

Однако для применения тем Snackbarобратитесь к этому руководству по качеству из стороннего материала: http://www.materialdoc.com/snackbar/ (следуйте программной реализации темы, чтобы она не полагалась на стиль xml)

Для справки:

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

(Вы также можете создавать свои собственные Snackbarмакеты, см. Ссылку выше. Сделайте это, если этот метод кажется слишком хакерским и вам нужен надежный способ продлить срок службы пользовательской панели Snackbar с помощью возможных обновлений библиотеки поддержки).

Или посмотрите ответы ниже, чтобы найти похожие и, возможно, более быстрые ответы для решения вашей проблемы.

Mahonster
источник
спасибо за решение! Собственность так и называетсяandroid:textColorPrimary
muetzenflo
Спасибо за подробное объяснение.
Bugs Happen
"вам, вероятно, вообще не следует определять android: textColor в ваших темах ..." это было ключевым для меня, спасибо!
Тайлер

Ответы:

41

Я знаю, что на это уже был дан ответ, но самый простой способ, который я нашел, был непосредственно в make с использованием Html.fromHtmlметода и fontтега

Snackbar.make(view, 
       Html.fromHtml("<font color=\"#ffffff\">Tap to open</font>").show()
JPM
источник
3
Я предпочитаю это решение, так как оно однострочное.
Lahiru Chandima
1
Это не настоящее решение этого вопроса. Используйте: snackbar.setActionTextColor (Color.WHITE) .show ();
Ahamadullah Saikat
В настройке Snackbar есть / была ошибка, цвет ничего не делал. Этот способ работает несмотря ни на что, но может не быть оптимальным решением для других.
Дж.П.М.
Для этого требуется уровень API> 24.
frank17
171

Я нашел это на странице Какие новые функции библиотеки поддержки дизайна Android и как использовать ее Snackbar?

Это сработало для меня при изменении цвета текста в 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();



ОБНОВЛЕНИЕ: ANDROIDX: как указывает dblackker в комментариях, с новой библиотекой поддержки AndroidX код для поиска идентификатора Snackbar TextView изменяется на:

TextView tv = view.findViewById(com.google.android.material.R.id.snackbar_text);
tv.setTextColor(ContextCompat.getColor(requireContext(), R.color.someColor))
Джарод Янг
источник
2
На всякий случай, если кто-то тщетно ищет способ изменить размер текста на Snackbar, вот и все!
Янис Пейсениекс
2
К вашему сведению, вы можете сделать то же самое с текстом действия, используя snackbar_actionвместо snackbar_text. См. Этот ответ для примера: stackoverflow.com/a/36800101/293280
Джошуа Пинтер
7
В лучшем случае это хакерство - что произойдет, если идентификатор android.support.design.R.id.snackbar_text изменится в следующем выпуске библиотеки поддержки? Нет ли какого-то стиля SnackBar по умолчанию, который можно переопределить в styles.xml?
DiscDev
7
Этот идентификатор действительно был изменен в будущем выпуске библиотеки поддержки, теперь я получаю нулевой указатель.
CaptainForge
3
Обновление - с androidx идентификатор теперь выглядит следующим образом:snack.view.findViewById(com.google.android.material.R.id.snackbar_text) as TextView
dblackker
15

Взлом android.support.design.R.id.snackbar_text- дело хрупкое, лучший или менее хакерский способ сделать это:

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();
Джет Чжао
источник
15

Создал эту функцию расширения kotlin, которую я использую в своих проектах:

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

    return this
}

Использование, как и следовало ожидать:

Snackbar.make (просмотр, R.string.your_string, Snackbar.LENGTH_LONG) .setTextColor (Color.WHITE) .show ()

Ричард
источник
Мне нравится простое использование методов расширения Kotlin! ;-)
Patrick Kuijpers
13
Используйте, com.google.android.material.R.id.snackbar_textесли вы переходите на AndroidX.
Rishabh876 04
Изменен @ Rishabh876 :)
Ричард
14

Хорошо, поэтому я исправил это, в основном реорганизовав цвет текста.

В моей светлой теме, я поставил android:textColorPrimaryна что normal dark textя хотел, и я поставил android:textColorв white.

Я обновил все свои текстовые представления и кнопки, чтобы android:textColor="?android:attr/textColorPrimary".

Итак, поскольку снэкбар извлекается из textColor, я просто установил для всего остального текста значение textColorPrimary.

ИЗМЕНИТЬ ЯНВАРЬ 2017: ---------------------------------------------- ------

Итак, как говорится в комментариях и как указано в отредактированном исходном вопросе выше, вам, вероятно, не следует определять android:textColorв своих темах, поскольку это меняет цвет текста каждого представления внутри темы.

Mahonster
источник
Я только что выполнил эту задачу, уф, заняло время! Однако мне нужно было использовать метод «m vai», приведенный ниже, для моей устаревшей деятельности с настройками (с использованием preferences.xml). Я думаю, что стиль моего приложения стал намного более правильным, что приятно. +1
OceanLife
1
Не очень хорошее решение, IMO, я хочу сохранить свою актуальную тему для текстового просмотра и просто изменить цвет текста Snakbar ...
issamux
1
Вы вообще не должны определять android:textColorв своей теме. Это стиль атрибут TextView. Если вы определяете его в своей теме, вы переопределяете цвет текста каждого TextViewили Buttonне указываете цвет текста в XML. Это также сообщение закусочной, которое обычно берет цвет из наложения темной темы .
Eugen Pechanec
12

Один из подходов - использовать промежутки:

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

С помощью промежутков вы также можете добавить несколько цветов и стилей внутри одной Snackbar. Вот хорошее руководство:

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

ulcica
источник
9

Если вы перешли на androidX, используйте com.google.android.material.R.id.snackbar_textвместо android.support.design.R.id.snackbar_textизменения цвета текста на панели закусок .

Рохит Маурья
источник
Вы заслуживаете медали.
frank17
@ frank17, это упоминалось здесь в нескольких комментариях.
CoolMind
6

Единственный способ, который я вижу, - это использовать getView()и циклически перемещаться по его дочернему элементу. Не знаю, сработает ли это, как бы плохо это ни выглядело. Я надеюсь, что они скоро добавят API по этой проблеме.

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();
Натарио
источник
6

Если вы перенесете свой код на AndroidX, свойство TextView теперь будет:

com.google.android.material.R.id.snackbar_text
Матяз Кристл
источник
2

Это то, что я использую, когда мне нужны нестандартные цвета

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

И потребляется как:

CustomView.makeSnackbar(view, "Hello", Snackbar.LENGTH_LONG, Color.YELLOW,Color.CYAN).setAction("DO IT", myAction).show();
маката
источник
2

Я изменил свою тему

Theme.AppCompat.Light.NoActionBar

к

Theme.AppCompat.NoActionBar 

Это сработало. Попробуйте использовать простую тему вместо светлой или другой темы.

Pavneet_Singh
источник
2

Если вы решили использовать грязное и хакерское решение с поиском TextView в Snackbar по идентификатору, и вы уже перешли на androidx, то вот код:

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)
Гжегож Матыщак
источник
1

Вы можете использовать эту библиотеку: https://github.com/SandroMachado/restaurant

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

Отказ от ответственности: я сделал библиотеку.

Сандро Мачадо
источник
1

Поиск по идентификатору у меня не сработал, поэтому я нашел другое решение:

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
Анримиан
источник
1

Используйте то, что Snackbarвходит в библиотеку компонентов материала, и примените

  • setTextColor определить цвет текста
  • setActionTextColorдля определения цвета текста, используемого действием. Вы можете использовать цвет или селектор цвета
  • setBackgroundTint для определения цвета фона Snackbar

Что-то вроде:

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

введите описание изображения здесь

Габриэле Мариотти
источник
1

В настоящее время (январь 2020 г.) с com.google.android.material:material:1.2.0и, вероятно, также1.1.0

Определенно лучший способ сделать это, переопределив эти стили:

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

Если вы используете тему материала с .Bridgeв конце, по какой-то причине ни один из этих стилей не определен. Таким образом, Snackar будет использовать устаревший макет без этих стилей.

Я обнаружил в исходном коде, что оба snackbarButtonStyleи snackbarTextViewStyleдолжны быть определены, иначе он не будет использоваться.

Атом
источник
0

У меня есть простой код, который поможет получить экземпляр как текстового представления Snackbar, так и после этого вы можете вызывать все методы, применимые к текстовому представлению.

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
источник
0

Чтобы сэкономить ваше драгоценное время на разработку, я использую статический метод:

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

Вот как это выглядит:

желтая закусочная с черным текстом

Ифта
источник
0

Если вы находитесь в Котлине , вы можете создать расширение:

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
}

Использование :

yourSnackBar.withTextColor(Color.WHITE).show()
Фил
источник
тот же ответ, что и мой 😉
Ричард
0

Согласно новым компонентам AndroidX Jitpack

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

Используйте это расширение, которое я создал

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

Используйте это так

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()
        }
    }
Манодж Перумарат
источник
0

Это мой обходной путь для решения этой проблемы при androidxиспользованииkotlin

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

Вам нужно инициализировать mContentвнутренний onViewCreatedметод, как показано ниже

var mContent: View? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mContent = view
    }
Сурадж Бахадур
источник
-1

Я тоже заметил ту же проблему. Благодаря ответам здесь я создал небольшой класс, который может помочь решить эту проблему более легко, просто заменив это:

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

с этим:

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

Вот мой класс:

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

}

Доктор Файлов
источник
1
Это взлом, и он полагается на статические идентификаторы различных представлений библиотеки поддержки. Я бы избегал этого решения любой ценой.
DiscDev