Как мне создать ColorStateList программно?


158

Я пытаюсь создать ColorStateListпрограммно с помощью этого:

ColorStateList stateList = new ColorStateList(states, colors); 

Но я не уверен, каковы два параметра.

Согласно документации:

public ColorStateList (int[][] states, int[] colors) 

Добавлено на уровне API 1

Создает ColorStateList, который возвращает указанное отображение из состояний в цвета.

Может кто-нибудь объяснить мне, как создать это?

В чем смысл двумерного массива для состояний?

Ответы:


344

См. Http://developer.android.com/reference/android/R.attr.html#state_above_anchor список доступных состояний.

Если вы хотите установить цвета для отключенных, несфокусированных, непроверенных состояний и т. Д., Просто отмените состояния:

int[][] states = new int[][] {
    new int[] { android.R.attr.state_enabled}, // enabled
    new int[] {-android.R.attr.state_enabled}, // disabled
    new int[] {-android.R.attr.state_checked}, // unchecked
    new int[] { android.R.attr.state_pressed}  // pressed
};

int[] colors = new int[] {
    Color.BLACK,
    Color.RED,
    Color.GREEN,
    Color.BLUE
};

ColorStateList myList = new ColorStateList(states, colors);

45
Спасибо за информацию о "противоположных" штатах!
BVB

Это можно использовать для изменения цвета fab из библиотеки дизайна.
Тапирбой

5
ПРЕДУПРЕЖДЕНИЕ. См. Ответ Роджера Алиена (и его первый комментарий), чтобы понять, что порядок состояний здесь плохой: поскольку сначала «включен», он переопределит другие состояния, которые обычно возникают, когда кнопка включена. Лучше поставить «включен» последним. (Или вместо «включено», пустой / элемент по умолчанию последним.)
ToolmakerSteve

2
Основной список состояний для кнопки , которая не сохраняет состояние (не тумблер / CheckBox) может быть {pressed}, {focused}, {-enabled}, {}. Для переключения это может быть {checked, pressed}, {pressed}, {checked, focused}, {focused}, {checked}, {-enabled}, {}. Или переключатель , который игнорирует фокус: {checked, pressed}, {pressed}, {checked}, {-enabled}, {}.
ToolmakerSteve

В случае, если кто-то попробует любое из этих решений, обратите внимание на порядок состояний, как в selector.xml!
Антон Маков

75

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

ColorStateList myColorStateList = new ColorStateList(
                        new int[][]{
                                new int[]{android.R.attr.state_pressed}, //1
                                new int[]{android.R.attr.state_focused}, //2
                                new int[]{android.R.attr.state_focused, android.R.attr.state_pressed} //3
                        },
                        new int[] {
                            Color.RED, //1
                            Color.GREEN, //2
                            Color.BLUE //3
                        }
                    );

надеюсь это поможет.

Пример РЕДАКТИРОВАТЬ: список состояний цвета xml, например:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:color="@color/white"/>
    <item android:color="@color/black"/>
</selector>

будет выглядеть так

ColorStateList myColorStateList = new ColorStateList(
        new int[][]{
                new int[]{android.R.attr.state_pressed},
                new int[]{}
        },
        new int[] {
                context.getResources().getColor(R.color.white),
                context.getResources().getColor(R.color.black)
        }
);

Можете ли вы рассказать, как представить приведенный ниже xml "<selector xmlns: android =" schemas.android.com/apk/res/android "> <item android: state_pressed =" true "android: color =" @ color / white "/ > <item android: color = "@ color / black" /> </ selector> "с использованием цветовой таблицы.
Satish

@SatishKumar проверь мои изменения, хотя я их не проверял.
Су-Ау Хван

3
Стоит сказать, что для указания ложного состояния вы можете отменить его значение, поэтому, если вы хотите указать цвет, когда оно не нажимается, вы должны использовать: new int [] {- ​​android.R.attr.state_pressed}
tinsukE

1
Чтобы добавить к тому, что сказал @tinsukE: Однако, чтобы избежать случайного подавления элемента позже в списке, для большинства состояний не имеет смысла ставить отрицание - вместо этого обрабатывайте все «другие» возможности со стандартным (пустым) элементом new int[]{}последний - как показано в последнем кодовом блоке этого ответа. Единственное отрицательное значение, которое я обычно использую, это "-enabled". Другой пример, если вы хотите три различных цвета: «сосредоточены + нажата», «сосредоточены + не нажата», «нажал + не сфокусирован», вы можете просто положить {focused, pressed}, {focused}, {pressed}. Первый «истинный» будет использоваться.
ToolmakerSteve

2
... Ошибка вы можете сделать это , чтобы иметь ряд , как {pressed}, {-pressed}, {focused}, {-focused}. Проблема в том, что {pressed}и {-pressed}охватывают ВСЕ возможности (кнопка либо нажата, либо не нажата), поэтому никакие цвета, перечисленные позже, никогда не будут использоваться.!
ToolmakerSteve

65

Иногда этого будет достаточно:

int colorInt = getResources().getColor(R.color.ColorVerificaLunes);
ColorStateList csl = ColorStateList.valueOf(colorInt);

20

К сожалению, ни одно из решений не работает для меня.

  1. Если вы не установили нажатое состояние сначала, оно не обнаружит его.
  2. Если вы установите его, то вам нужно определить пустое состояние, чтобы добавить цвет по умолчанию
ColorStateList themeColorStateList = new ColorStateList(
        new int[][]{
                new int[]{android.R.attr.state_pressed},
                new int[]{android.R.attr.state_enabled},
                new int[]{android.R.attr.state_focused, android.R.attr.state_pressed},
                new int[]{-android.R.attr.state_enabled},
                new int[]{} // this should be empty to make default color as we want
        },
        new int[]{
                pressedFontColor,
                defaultFontColor,
                pressedFontColor,
                disabledFontColor,
                defaultFontColor
        }
);

Это конструктор из исходного кода:

/**
 * Creates a ColorStateList that returns the specified mapping from
 * states to colors.
 */
public ColorStateList(int[][] states, int[] colors) {
    mStateSpecs = states;
    mColors = colors;

    if (states.length > 0) {
        mDefaultColor = colors[0];

        for (int i = 0; i < states.length; i++) {
            if (states[i].length == 0) {
                mDefaultColor = colors[i];
            }
        }
    }
}

5
Точно так же, как sidenote: Вы должны относиться к этому так же, как если бы еще. Он выбирает первое состояние, которое является истинным. Таким образом, если у вас state_enabled в качестве первого состояния, оно будет выбрано до нажатия state_pressed - если только представление не отключено.
LeoFarage

FWIW, так как у вас есть последний элемент по умолчанию, я не думаю, что первый «включенный» элемент приносит вам какую-то пользу. Почему бы не удалить его полностью?
ToolmakerSteve

18

Вот пример того, как ColorListпрограммно создать в Kotlin:

val colorList = ColorStateList(
        arrayOf(
                intArrayOf(-android.R.attr.state_enabled),  // Disabled
                intArrayOf(android.R.attr.state_enabled)    // Enabled
        ),
        intArrayOf(
                Color.BLACK,     // The color for the Disabled state
                Color.RED        // The color for the Enabled state
        )
)

Также, смотрите мой ответ ниже для вспомогательной функции Kotlin.
ареколек

7

Отражая ответ Джонатана Эллиса , в Kotlin вы можете определить вспомогательную функцию, чтобы сделать код немного более идиоматичным и проще для чтения, поэтому вы можете написать это вместо этого:

val colorList = colorStateListOf(
    intArrayOf(-android.R.attr.state_enabled) to Color.BLACK,
    intArrayOf(android.R.attr.state_enabled) to Color.RED
)

colorStateListOf может быть реализовано так:

fun colorStateListOf(vararg mapping: Pair<IntArray, Int>): ColorStateList {
    val (states, colors) = mapping.unzip()
    return ColorStateList(states.toTypedArray(), colors.toIntArray())
}

У меня тоже есть:

fun colorStateListOf(@ColorInt color: Int): ColorStateList {
    return ColorStateList.valueOf(color)
}

Так что я могу вызывать одно и то же имя функции, независимо от того, селектор ли это или один цвет.


3

Мой класс строителей для создания ColorStateList

private class ColorStateListBuilder {
    List<Integer> colors = new ArrayList<>();
    List<int[]> states = new ArrayList<>();

    public ColorStateListBuilder addState(int[] state, int color) {
        states.add(state);
        colors.add(color);
        return this;
    }

    public ColorStateList build() {
        return new ColorStateList(convertToTwoDimensionalIntArray(states),
                convertToIntArray(colors));
    }

    private int[][] convertToTwoDimensionalIntArray(List<int[]> integers) {
        int[][] result = new int[integers.size()][1];
        Iterator<int[]> iterator = integers.iterator();
        for (int i = 0; iterator.hasNext(); i++) {
            result[i] = iterator.next();
        }
        return result;
    }

    private int[] convertToIntArray(List<Integer> integers) {
        int[] result = new int[integers.size()];
        Iterator<Integer> iterator = integers.iterator();
        for (int i = 0; iterator.hasNext(); i++) {
            result[i] = iterator.next();
        }
        return result;
    }
}

Пример использования

ColorStateListBuilder builder = new ColorStateListBuilder();
builder.addState(new int[] { android.R.attr.state_pressed }, ContextCompat.getColor(this, colorRes))
       .addState(new int[] { android.R.attr.state_selected }, Color.GREEN)
       .addState(..., some color);

if(// some condition){
      builder.addState(..., some color);
}
builder.addState(new int[] {}, colorNormal); // must add default state at last of all state

ColorStateList stateList = builder.build(); // ColorStateList created here

// textView.setTextColor(stateList);

2

если вы используете ресурс Colors.xml

int[] colors = new int[] {
                getResources().getColor(R.color.ColorVerificaLunes),
                getResources().getColor(R.color.ColorVerificaMartes),
                getResources().getColor(R.color.ColorVerificaMiercoles),
                getResources().getColor(R.color.ColorVerificaJueves),
                getResources().getColor(R.color.ColorVerificaViernes)

        };

ColorStateList csl = new ColorStateList(new int[][]{new int[0]}, new int[]{colors[0]}); 

    example.setBackgroundTintList(csl);

2
как getResources()не рекомендуется, это сейчас ContextCompat.getColor(this,R.color.colorname);или ContextCompat.getColor(getActivity(),R.color.colorname);для использования во фрагменте
iBobb

Для пояснения для других читателей new int[0](как элемент в списке первого параметра) это массив нулевой длины, представляющий установку цвета по умолчанию. Здесь это единственный элемент, который означает, что оттенок применяется ко всем состояниям кнопки. Это эквивалентно тому, что new int[]{}видно в ответе Роджера Алиена.
ToolmakerSteve
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.