Atur warna bentuk android secara terprogram


168

Saya sedang mengedit untuk membuat pertanyaan lebih sederhana, berharap itu membantu menuju jawaban yang akurat.

Katakanlah saya memiliki ovalbentuk berikut :

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
    <solid android:angle="270"
           android:color="#FFFF0000"/>
    <stroke android:width="3dp"
            android:color="#FFAA0055"/>
</shape>

Bagaimana cara mengatur warna secara terprogram, dari dalam kelas aktivitas?


Anda mengatur apa yang dapat digambar ini?
Vikram

Drawable adalah ovaldan merupakan latar belakang dari ImageView.
Cote Mounyo

Jika pertanyaan ini sebagai pertanyaan terlalu sulit, adakah cara untuk menggambar banyak gambar di atas kanvas dan menetapkan produk akhir yang berlapis sebagai latar belakang tampilan?
Cote Mounyo

Anda dapat mencapai ini dengan memperluas Viewkelas, dan menggunakannya sebagai basetampilan dalam tata letak yang memungkinkan tumpang tindih widget ( RelativeLayout, FrameLayout). Di dalam Viewkelas yang diperluas ini , Anda bisa draw multiple images onto a canvas. Tetapi, sebelum melakukan itu, lihat ini -> Tautan (jika Anda belum melakukannya).
Vikram

Jawaban:


266

Catatan : Jawaban telah diperbarui untuk mencakup skenario di mana backgroundmerupakan instance dari ColorDrawable. Terima kasih Tyler Pfaff , untuk menunjukkan ini.

Drawable adalah oval dan merupakan latar belakang dari ImageView

Dapatkan Drawabledari imageViewmenggunakan getBackground():

Drawable background = imageView.getBackground();

Periksa terhadap tersangka biasa:

if (background instanceof ShapeDrawable) {
    // cast to 'ShapeDrawable'
    ShapeDrawable shapeDrawable = (ShapeDrawable) background;
    shapeDrawable.getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
    // cast to 'GradientDrawable'
    GradientDrawable gradientDrawable = (GradientDrawable) background;
    gradientDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
    // alpha value may need to be set again after this call
    ColorDrawable colorDrawable = (ColorDrawable) background;
    colorDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}

Versi ringkas:

Drawable background = imageView.getBackground();
if (background instanceof ShapeDrawable) {
    ((ShapeDrawable)background).getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
    ((GradientDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
    ((ColorDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}

Perhatikan bahwa pemeriksaan nol tidak diperlukan.

Namun, Anda harus menggunakan mutate()drawable sebelum mengubahnya jika digunakan di tempat lain. (Secara default, drawable yang diambil dari XML memiliki status yang sama.)


3
Terimakasih telah menjawab. (+1). Kode saya mengalami bug lain sehingga sulit untuk diuji. Tapi tetap saja ini bisa mengatur solidporsi bentuk. Bagaimana dengan strokeporsinya?
Cote Mounyo

1
@TiGer Anda harus menambahkan @usernamekomentar Anda untuk memastikan pemberitahuan dikirimkan kepada pengguna. Ngomong-ngomong, Anda perlu subkelas ShapeDrawableuntuk mengatur porsi goresan. Info lebih lanjut di sini: Tautan . Lihatlah komentar yang menyebutkan masalah dengan jawaban yang diterima.
Vikram

3
android.graphics.drawable.GradientDrawable tidak dapat dilemparkan ke android.graphics.drawable.ShapeDrawable Para pemain gagal pada saya
John

3
@ John Jika ImageView'slatar belakang Anda diatur ke GradientDrawable, getBackground()tidak akan mengembalikan a ShapeDrawable. Sebaliknya, gunakan GradientDrawableyang dikembalikan: GradientDrawable gradientDrawable = (GradientDrawable)imageView.getBackground();.... gradientDrawable.setColors(new int[] { color1, color2 });.
Vikram

2
Terima kasih .. menyelamatkan duniaku.
sid_09

43

Lakukan seperti ini:

    ImageView imgIcon = findViewById(R.id.imgIcon);
    GradientDrawable backgroundGradient = (GradientDrawable)imgIcon.getBackground();
    backgroundGradient.setColor(getResources().getColor(R.color.yellow));

1
@ user3111850 Apakah Anda menambahkan android:backgroundxml atau bahkan setBackgrounddalam aktivitas Anda sebelum menelepon getBackground()? Seharusnya berhasil jika Anda melakukannya.
Lee Yi Hong

41

Solusi yang lebih sederhana saat ini adalah menggunakan bentuk Anda sebagai latar belakang dan kemudian mengubah warnanya secara terprogram melalui:

view.background.setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_ATOP)

Lihat PorterDuff.Mode untuk pilihan yang tersedia.

UPDATE (API 29):

Metode di atas sudah ditinggalkan sejak API 29 dan diganti dengan yang berikut:

view.background.colorFilter = BlendModeColorFilter(Color.parseColor("#343434"), BlendMode.SRC_ATOP)

Lihat BlendMode untuk opsi yang tersedia.


4
Yang benar adalah: view.getBackground().setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_ATOP);Karena mungkin ada perbatasan di latar belakang atau kurir bulat.
Berkay Turancı

1
Bagus @ BerkayTurancı bentuk saya memang memiliki sudut membulat. Saya bisa menghilangkan getBackground()panggilan. Imageview.src saya berisi bentuk dan saya menggunakan: di imageIndicator.setColorFilter(toggleColor, PorterDuff.Mode.SRC_ATOP);mana toggleColorhanya sebuah int yang sebelumnya menyimpan hasil dari getColor ()
Someone Somewhere

1
Memiliki PorterDuff.Modeuntuk BlendModeColorFiltertidak akan dikompilasi seperti yang dibutuhkan BlendMode. Jadi untuk API 29 seharusnya view.background.colorFilter = BlendModeColorFilter(Color.parseColor("#343434"), BlendMode.SRC_ATOP).
Onik

Tangkapan yang bagus @ Onik. Saya telah memperbarui jawabannya. Terima kasih!
Georgios

14

Coba ini:

 public void setGradientColors(int bottomColor, int topColor) {
 GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[]  
 {bottomColor, topColor});
 gradient.setShape(GradientDrawable.RECTANGLE);
 gradient.setCornerRadius(10.f);
 this.setBackgroundDrawable(gradient);
 }

untuk lebih jelasnya cek tautan ini ini

semoga membantu.


suara untuk tautan. Tapi itu bukan jawaban untuk pertanyaan saya.
Cote Mounyo

13

Semoga ini bisa membantu seseorang dengan masalah yang sama

GradientDrawable gd = (GradientDrawable) YourImageView.getBackground();
//To shange the solid color
gd.setColor(yourColor)

//To change the stroke color
int width_px = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, youStrokeWidth, getResources().getDisplayMetrics());
gd.setStroke(width_px, yourColor);

1
Awalnya saya tidak bisa mendapatkan ini untuk bekerja, saya tahu warna Anda harus disediakan seperti ini:gd.setStroke(width_px, Color.parseColor("#FF5722"));
pwnsauce

12

Memperluas jawaban Vikram , jika Anda mewarnai tampilan dinamis, seperti item tampilan pendaur ulang, dll .... Maka Anda mungkin ingin memanggil mutate () sebelum Anda mengatur warna. Jika Anda tidak melakukan ini, tampilan apa pun yang memiliki drawable umum (yaitu latar belakang) juga akan dapat diubah drawable / berwarna.

public static void setBackgroundColorAndRetainShape(final int color, final Drawable background) {

    if (background instanceof ShapeDrawable) {
        ((ShapeDrawable) background.mutate()).getPaint().setColor(color);
    } else if (background instanceof GradientDrawable) {
        ((GradientDrawable) background.mutate()).setColor(color);
    } else if (background instanceof ColorDrawable) {
        ((ColorDrawable) background.mutate()).setColor(color);
    }else{
        Log.w(TAG,"Not a valid background type");
    }

}

3
kebutuhan dan pemeriksaan dan parameter tambahan: if (background instanceof LayerDrawable) { background = ((LayerDrawable) background.mutate()).getDrawable(indexIfLayerDrawable); } if (background instanceof ShapeDrawable)[...]untuk menangani tata letak latar belakang yang digunakan <layer-list ... <item ....
Johny

11

Pertanyaan ini dijawab beberapa waktu lalu, tetapi dapat dimodernisasi dengan menulis ulang sebagai fungsi ekstensi kotlin.

fun Drawable.overrideColor(@ColorInt colorInt: Int) {
    when (this) {
        is GradientDrawable -> setColor(colorInt)
        is ShapeDrawable -> paint.color = colorInt
        is ColorDrawable -> color = colorInt
    }
}

7

ini adalah solusi yang bekerja untuk saya ... menulisnya di pertanyaan lain juga: Bagaimana cara mengubah warna bentuk secara dinamis?

//get the image button by id
ImageButton myImg = (ImageButton) findViewById(R.id.some_id);

//get drawable from image button
GradientDrawable drawable = (GradientDrawable) myImg.getDrawable();

//set color as integer
//can use Color.parseColor(color) if color is a string
drawable.setColor(color)

4

Tidak ada yang berhasil untuk saya, tetapi ketika saya mengatur warna warna itu berfungsi pada Shape Drawable

 Drawable background = imageView.getBackground();
 background.setTint(getRandomColor())

membutuhkan android 5.0 API 21


3

Versi fungsi ekstensi Kotlin saya berdasarkan jawaban di atas dengan Compat :

fun Drawable.overrideColor_Ext(context: Context, colorInt: Int) {
    val muted = this.mutate()
    when (muted) {
        is GradientDrawable -> muted.setColor(ContextCompat.getColor(context, colorInt))
        is ShapeDrawable -> muted.paint.setColor(ContextCompat.getColor(context, colorInt))
        is ColorDrawable -> muted.setColor(ContextCompat.getColor(context, colorInt))
        else -> Log.d("Tag", "Not a valid background type")
    }
}

1

Cara sederhana untuk mengisi bentuk dengan Radius adalah:

(view.getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);

1

Mungkin saya terlambat. Tapi jika Anda menggunakan Kotlin. Ada cara seperti ini

var gd = layoutMain.background as GradientDrawable

 //gd.setCornerRadius(10)
  gd.setColor(ContextCompat.getColor(ctx , R.color.lightblue))
  gd.setStroke(1, ContextCompat.getColor(ctx , R.color.colorPrimary)) // (Strokewidth,colorId)

Nikmati....


0

Bagi siapa pun yang menggunakan C # Xamarin, berikut adalah metode yang didasarkan pada cuplikan Vikram:

private void SetDrawableColor(Drawable drawable, Android.Graphics.Color color)
{
    switch (drawable)
    {
        case ShapeDrawable sd:
            sd.Paint.Color = color;
            break;
        case GradientDrawable gd:
            gd.SetColor(color);
            break;
        case ColorDrawable cd:
            cd.Color = color;
            break;
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.