Bagaimana cara membuat ColorStateList secara terprogram?

158

Saya mencoba membuat ColorStateListprogram menggunakan ini:

ColorStateList stateList = new ColorStateList(states, colors); 

Tapi saya tidak yakin apa dua parameternya.

Sesuai dokumentasi:

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

Ditambahkan di API level 1

Membuat ColorStateList yang mengembalikan pemetaan yang ditentukan dari status ke warna.

Dapatkah seseorang tolong jelaskan saya cara membuat ini?

Apa arti dari array dua dimensi untuk negara?

Anukool
sumber

Jawaban:

344

Lihat http://developer.android.com/reference/android/R.attr.html#state_above_anchor untuk daftar status yang tersedia.

Jika Anda ingin mengatur warna untuk kondisi nonaktif, tidak fokus, tidak dicentang dll. Cukup meniadakan status:

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);
Caner
sumber
45
Terima kasih atas info mengenai status "berlawanan"!
BVB
Ini dapat digunakan untuk mengubah warna fab dari perpustakaan desain.
Tapirboy
5
HATI-HATI: Lihat jawaban Roger Alien (dan komentar pertama) untuk memahami bahwa urutan negara bagian di sini buruk: karena "diaktifkan" adalah yang pertama, itu akan menimpa negara-negara lain yang biasanya terjadi saat tombol diaktifkan. Lebih baik menempatkan "diaktifkan" terakhir. (Atau alih-alih "diaktifkan", item kosong / default terakhir.)
ToolmakerSteve
2
Sebuah daftar dasar negara untuk tombol yang tidak mempertahankan negara (TIDAK beralih / kotak centang) mungkin {pressed}, {focused}, {-enabled}, {}. Untuk beralih mungkin {checked, pressed}, {pressed}, {checked, focused}, {focused}, {checked}, {-enabled}, {}. Atau toggle yang abaikan fokus: {checked, pressed}, {pressed}, {checked}, {-enabled}, {}.
ToolmakerSteve
Jika seseorang akan mencoba salah satu dari solusi tersebut, perhatikan urutan kondisi seperti di selector.xml!
Anton Makov
75

Dimensi pertama adalah larik set keadaan, yang kedua adalah set negara itu sendiri. Array warna mencantumkan warna untuk setiap set keadaan yang cocok, oleh karena itu panjang array warna harus cocok dengan dimensi pertama dari array state (atau akan crash ketika negara "digunakan"). Di sini dan contoh:

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

semoga ini membantu.

Contoh EDIT: daftar status warna xml seperti:

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

akan terlihat seperti ini

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)
        }
);
Su-Au Hwang
sumber
Bisakah Anda memberi tahu cara merepresentasikan xml "di bawah ini: <selector xmlns: android =" schemas.android.com/apk/res/android "> <item android: state_pressed =" true "android: color =" @ color / white "/ > <item android: color = "@ color / black" /> </selector> "menggunakan colorstatelist.
Satish
@SatishKumar memeriksa edit saya, saya belum mengujinya.
Su-Au Hwang
3
Layak untuk mengatakan bahwa untuk menentukan keadaan salah, Anda dapat meniadakan nilainya, jadi jika Anda ingin menentukan warna ketika tidak ditekan, Anda harus menggunakan: new int [] {- ​​android.R.attr.state_pressed}
tinsukE
1
Untuk menambahkan apa yang dikatakan @tinsukE: Namun, untuk menghindari penekanan item secara tidak sengaja di akhir daftar, untuk sebagian besar negara, tidak masuk akal untuk menempatkan negasi - alih-alih menangani semua kemungkinan "lainnya" dengan item default (kosong) new int[]{}terakhir - seperti yang ditunjukkan pada blok kode terakhir dari jawaban ini. Satu-satunya nilai negasi yang biasanya saya gunakan adalah "-enable". Contoh lain, jika Anda ingin tiga warna berbeda: "difokuskan + ditekan", "terfokus + tidak ditekan", "ditekan + tidak fokus", Anda hanya dapat menempatkan {focused, pressed}, {focused}, {pressed}. Yang "benar" pertama akan digunakan.
ToolmakerSteve
2
... Kesalahan yang mungkin membuat adalah untuk memiliki serangkaian seperti {pressed}, {-pressed}, {focused}, {-focused}. Masalahnya adalah itu {pressed}dan {-pressed}mencakup SEMUA kemungkinan (tombolnya ditekan atau tidak ditekan), jadi tidak ada warna yang terdaftar nantinya yang akan digunakan.!
ToolmakerSteve
64

Terkadang ini sudah cukup:

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

Sayangnya tidak ada solusi yang berfungsi untuk saya.

  1. Jika Anda tidak menyetel keadaan ditekan pada awalnya, ia tidak akan mendeteksi itu.
  2. Jika Anda mengaturnya, maka Anda perlu mendefinisikan keadaan kosong untuk menambahkan warna default
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
        }
);

Ini adalah konstruktor dari kode sumber:

/**
 * 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];
            }
        }
    }
}
Roger Alien
sumber
5
Sama seperti sidenote: Anda harus memperlakukannya seperti jika Anda melakukan if-elseif. Ini memilih keadaan pertama yang benar. Jadi, jika Anda memiliki state_enabled sebagai keadaan pertama, itu akan dipilih sebelum state_pressed - kecuali tampilan dinonaktifkan.
LeoFarage
FWIW, karena Anda memiliki elemen default yang terakhir, saya rasa elemen "diaktifkan" pertama tidak ada gunanya sama sekali. Mengapa tidak menghapusnya sepenuhnya?
ToolmakerSteve
18

Berikut adalah contoh cara membuat ColorListprogram di 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
        )
)
Jonathan Ellis
sumber
Juga, lihat jawaban saya di bawah ini untuk fungsi pembantu Kotlin.
arekolek
7

Memantulkan jawaban oleh Jonathan Ellis , di Kotlin Anda dapat mendefinisikan fungsi pembantu untuk membuat kode sedikit lebih idiomatis dan lebih mudah dibaca, jadi Anda bisa menulis ini sebagai gantinya:

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

colorStateListOf dapat diimplementasikan seperti ini:

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

Saya juga punya:

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

Sehingga saya bisa memanggil nama fungsi yang sama, tidak peduli apakah itu pemilih atau warna tunggal.

arekolek
sumber
3

Kelas pembangun saya untuk buat 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;
    }
}

Contoh Menggunakan

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);
Phan Van Linh
sumber
2

jika Anda menggunakan sumber daya 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);
David Hackro
sumber
2
seperti yang getResources()sudah ditinggalkan, sekarang ContextCompat.getColor(this,R.color.colorname);atau ContextCompat.getColor(getActivity(),R.color.colorname);untuk digunakan dalam Fragmen
iBobb
Untuk mengklarifikasi bagi pembaca lain, new int[0](sebagai elemen dalam daftar parameter pertama) adalah array panjang nol, dan mewakili pengaturan warna default. Ini dia satu-satunya elemen, yang berarti warna diterapkan ke semua status tombol. Ini sama dengan yang new int[]{}terlihat dalam jawaban Roger Alien.
ToolmakerSteve