Dynamically change SVG image color in android - android

I know that using third party library, it is possible to use SVG image in Android.
Library like: svg-android
The code to load SVG image is like below:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a new ImageView
ImageView imageView = new ImageView(this);
// Set the background color to white
imageView.setBackgroundColor(Color.WHITE);
// Parse the SVG file from the resource
SVG svg = SVGParser.getSVGFromResource(getResources(), R.raw.android);
// Get a drawable from the parsed SVG and set it as the drawable for the ImageView
imageView.setImageDrawable(svg.createPictureDrawable());
// Set the ImageView as the content view for the Activity
setContentView(imageView);
}
It's working fine. I'm able to see the image. But now I want to change the color for the svg image at runtime.
For that I tried the code below as mentioned in the same project description.
// 0xFF9FBF3B is the hex code for the existing Android green, 0xFF1756c9 is the new blue color
SVG svg = SVGParser.getSVGFromResource(getResources(), R.raw.android, 0xFF9FBF3B, 0xFF1756c9);
But with that I am not able to see the change in the color. So I would like to know how it is possible to change the color dynamically in Java file.

I know it's kind of late but I also had this issue and was able to fix this issue using the setColorFilter(int color, PorterDuff.Mode mode) method.
Example:
imageView.setColorFilter(getResources().getColor(android.R.color.black), PorterDuff.Mode.SRC_IN);

I got where is the problem.
The issue is with the color code i am using in svg file.
Its not exactly 0xFF9FBF3B but #9FBF3B
But during java code you have to write it with ARGB value (e.g. 0xFF9FBF3B).
I have updated it and its work fine now. I can able to change the color of svg file with same code.
Hope this will also help others to identify the actual case while changing the color of the SVG image at runtime.

Using the answer of Antlip Dev in Kotlin.
package com.example.... // Your package.
import android.graphics.PorterDuff
import android.widget.ImageView
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
fun ImageView.setSvgColor(#ColorRes color: Int) =
setColorFilter(ContextCompat.getColor(context, color), PorterDuff.Mode.SRC_IN)
Usage:
view.your_image.setSvgColor(R.color.gray)

what #Antlip Dev said is correct, but that method is deprecated now.
This is the updated version:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
drawable.setColorFilter(new BlendModeColorFilter(color, BlendMode.SRC_ATOP));
} else {
drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
}

You can use: drawableTint to change the color

This worked for me DrawableCompat.setTint(imageView.getDrawable(),ContextCompat.getColor(getApplicationContext(), R.color.colorAccent))

Related

ActonBar with two custom colors

Hi guys, i'm trying to make ActionBar the same as in the image above (with this "wave"), where the red color can be changed at run time. I tried to use GradientDrawable (code below), but the gradient effect was not cool and it's not what i need.
GradientDrawable gd = new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,
new int[] {cor, Color.WHITE});
gd.setCornerRadius(0f);
actionBar.setBackgroundDrawable(gd);
Any idea?
I'm not completly sure, but it can be done using custom drawable.xml something like this. Even, I think that you would have mix some drawables to get the image that you're posting.
An alternative is having the image in png or jpg that you want to set to actionbar and code this. Regards!
I created the red part of the image above at https://vectr.com (.svg).
in Android Studio, i added a new shape_action_bar.xml (vector asset), from the created image.
in the activity I added the following code:
Drawable drawable = getNavigationController().getResources().getDrawable(R.drawable.shape_action_bar);
ColorFilter color = new PorterDuffColorFilter(selected_color, PorterDuff.Mode.SRC_ATOP );
drawable.setColorFilter(color);
actionBar.setBackgroundDrawable(drawable);
The shape will change color according to the desired color. Thankss

Change image fill color in Android

I have an ImageView with the source being an ImageAsset.
My image is a circle with a plus and I am looking to colour the inside of the circle only. How do I do that?
Using setBackgroundColor colours the whole of the view thus giving a square background like this:
.
You can apply a color tint to your ImageView. This will not affect your background if it's transparent, just the colored part (which is the circle and the plus)
imageView.setColorFilter(ContextCompat.getColor(context, R.color.COLOR_YOUR_COLOR),
android.graphics.PorterDuff.Mode.MULTIPLY);
Update
Using android.graphics.PorterDuff.Mode.SRC_IN will also work (if you don't need to multiply the source and destination pixels)
Update 2
Since the destination part is not colored than the best solution is to use VectorDrawable.
You can use VectorChildFinder to find inner parts of your SVG resource and change its color.
VectorChildFinder vector = new VectorChildFinder(this, R.drawable.my_vector, imageView);
VectorDrawableCompat.VFullPath path1 = vector.findPathByName("path1");
path1.setFillColor(Color.RED);
imageView.invalidate();
to create your SVG, follow these steps :
Just click right button on folder(drawable for ex.) and choose:
then choose:

unable to setColorFilter for stickerview

am using sticker view in my project . it's a library that extend imageView and let you move and rotate image on the screen
https://github.com/nimengbo/StickerView
my problem is that i can't set color filter for images , i have tested every thing
such as
mCurrentView.setColorFilter(getResources().getColor(R.color.red_alpha_95), PorterDuff.Mode.MULTIPLY);
mCurrentView.getDrawable().setColorFilter(getResources().getColor(R.color.red_alpha_95), PorterDuff.Mode.MULTIPLY);
or even making a new drawable from resource and add that drawable to image view ;
i will be greauful if you have any experience with setColorFilter issue or know another lib or approach to move image view on the screen and share it with me
I'm use tint using compat support lib.
int color = ContextCompat.getColor(context, R.color.red_alpha_95);
Drawable drawable = mCurrentView.getDrawable();
Drawable wrap = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(wrap.mutate(), color);

Programmatically tint a Support Vector

Android Studio version 2.1, gradle version 2.1.0, please correct me if you spot any misinterpretations :)
I am confused about support vectors in the support library 23.3.0. Specifically what I would like to do is tint an image button programmatically, whose src is defined is a vector drawable. From what I can tell this is not possible on pre-lollipop now.
I have read several related posts about the changes:
23.2.0 announcement and changes:
As of Android Support Library 23.3.0, support vector drawables can only be loaded via app:srcCompat or setImageResource().
Does the above mean that vector xmls can only be used pre-Lollipop via srcCompat or setImageResource(), and therefore cannot be dynamically tinted?
Here is my basic image button:
<ImageButton
android:id="#+id/nav_header_exit_community_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:background="#null"/>
Works on Lollipop and above only:
Drawable bg = ContextCompat.getDrawable(a, R.drawable.ic_exit_to_app_24dp);
DrawableCompat.setTint(bg, headerTitleColor);
exitButton.setImageDrawable(bg);
Attempting this pre-lollipop throws:
android.content.res.Resources$NotFoundException: File res/drawable/ic_exit_to_app_24dp.xml from drawable resource ID #0x7f0200bf
Also works on Lollipop and above only
Drawable bg = ContextCompat.getDrawable(a, R.drawable.ic_exit_to_app_24dp);
DrawableCompat.setTint(bg, headerTitleColor);
exitButton.setImageResource(R.drawable.ic_exit_to_app_24dp);
This throws the same error on pre-Lollipop.
However if I remove vectorDrawables.useSupportLibrary = true as pointed out by Ian Lake here, with the intent of having the build tools auto-generate pngs for pre-Lollipop devices, the pngs do not tint on pre-lollipop, so I'm back to square one.
I have also tried specifying the vector via srcCompat and retrieving it programmatically but I don't think I've been able to achieve that, even though it works on post-Lollipop if the vector is specified using src instead.
So the situation for 23.3.0 seems to be:
Post-Lollipop: src and srcCompat accept vectors, only src can be
retrieved from the view as a drawable for tinting programmatically.
Referencing vectors in code is possible using getDrawable, and they
can be tinted.
Pre-Lollipop: srcCompat only can accept vectors, cannot be retrieved
programmatically from the view for tinting. setImageResource can
accept vectors, but only if vectorDrawables.useSupportLibrary = false, and tinting does not work. Similarly referencing vectors in code is not
possible unless vectorDrawables.useSupportLibrary = false and tinting
does not work.
Working on all versions using pngs:
Drawable bg = ContextCompat.getDrawable(a, R.drawable.ic_nav_exit_community);
DrawableCompat.setTint(bg, headerTitleColor);
exitButton.setImageDrawable(bg);
Addendum:
This technique also works on post-Lollipop, but like the others on pre-Lollipop I get the drawable, but no tinting:
Drawable bg = VectorDrawableCompat.create(a.getResources(), R.drawable.ic_exit_to_app_24dp, null);
DrawableCompat.setTint(bg, headerTitleColor);
exitButton.setImageDrawable(bg);
KIND OF SOLUTION:
Thanks to John's answer so far the only fool-proof way I can come up with to tint a support vector is to set a color filter on it - this means the DrawableCompat.setTint() function is seemingly not functional for me if the drawable in question is a support vector. I'm not sure if this is a legit bug, expected behavior or if I'm just doing something wrong!
Here is the solution I'm going with for the moment:
Drawable bg;
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
bg = VectorDrawableCompat.create(a.getResources(), R.drawable.ic_exit_to_app_24dp, null);
exitButton.setColorFilter(headerTitleColor, PorterDuff.Mode.MULTIPLY);
}
else {
bg = ContextCompat.getDrawable(a, R.drawable.ic_exit_to_app_24dp);
DrawableCompat.setTint(bg, headerTitleColor);
}
exitButton.setImageDrawable(bg);
first of all you should use VectorDrawableCompat#create, once you have your Drawable you have to call DrawableCompat#wrap:
Potentially wrap drawable so that it may be used for tinting across
the different API levels, via the tinting methods in this class.
so your code would look like this:
ImageView iv = ....
Drawable d = VectorDrawableCompat.create(getResources(), R.drawable.ic_exit_to_app_24dp, null);
d = DrawableCompat.wrap(d);
DrawableCompat.setTint(d, headerTitleColor);
iv.setImageDrawable(d);
You can use setColorFilter method of ImageView:
imageView.setColorFilter(headerTitleColor, android.graphics.PorterDuff.Mode.MULTIPLY);
Another handy solution with Kotlin:
fun Context.drawableWithColor(#DrawableRes drawableRes: Int, #ColorInt color: Int): Drawable? {
val pic = ContextCompat.getDrawable(this, drawableRes)
pic?.setColorFilter(color, PorterDuff.Mode.SRC_IN)
return pic
}
Use is as simple as:
val drawable = context.drawableWithColor(R.drawable.your_awesome_drawable, Color.BLUE)

Android CardView setBackground as BitmapDrawable when API <21

I have a problem when I am trying to setBackground() of a CardView programatically in KitKat.When the application is running on Android L there is no problem in my code :
Drawable drawable = new BitmapDrawable(appContext.getResources(), bitmap);
if (cardView != null) {
cardView.setBackground(drawable);
}
But when it runs in API older than Android L I get this error: android.graphics.drawable.BitmapDrawable cannot be cast to android.support.v7.widget.RoundRectDrawableWithShadow.
I found out that this is known issue and there is work around where you want to set a colour as a background of the card, but is there any solution with which I could set the bitmap for background programatically? Do you have any idea how could I create RoundRectDrawableWithShadow from my BitmapDrawable?
Do you have any idea how could I create RoundRectDrawableWithShadow from my BitmapDrawable?
Don't do it unless you wish to rewrite your own CardView implementation.
RoundRectDrawableWithShadow is a package private class used to take the color you supplied by app:cardBackgroundColor or setCardBackgroundColro(int) and wrap it in a rounded rectangle with shadow to produce a drawable.
Since elevation was introduced in API 21 the shadow is painted as part of CardView background drawable on prior platforms so you can't set your own background via setBackground(*).
is there any solution with which I could set the bitmap for background programatically?
You could put a View, *Layout, etc. in the card and set a rounded drawable background on it. It will not be effective performance-wise though.
https://developer.android.com/reference/android/support/v4/graphics/drawable/RoundedBitmapDrawable.html
So yeah, if you absolutely need something else than solid color, go with a View.setBackground

Categories

Resources