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?

Cote Mounyo
sumber
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.)

Vikram
sumber
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));
Leonly91
sumber
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.

Georgios
sumber
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.

androidqq6
sumber
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);
medhdj
sumber
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");
    }

}
Tyler Pfaff
sumber
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
    }
}
Carlos Paulino
sumber
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)
Komunitas
sumber
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

Sumit
sumber
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")
    }
}
Sattar Hummatli
sumber
1

Cara sederhana untuk mengisi bentuk dengan Radius adalah:

(view.getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);
SANAT
sumber
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....

Sistem semangat
sumber
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;
    }
}
Ryan
sumber