Ad

How To Change Background Color At Image In Widget Android

- 1 answer

I have a problem with change background color at image in widget. Right now i'm using like this:

try {
        Class c = Class.forName("android.widget.RemoteViews");
        Method m = c.getMethod("setDrawableParameters", int.class, boolean.class, int.class, int.class, PorterDuff.Mode.class, int.class);
        m.invoke(remoteViews, R.id.myImage, true, -1, Color.HSVToColor(color), PorterDuff.Mode.SRC_OVER, -1);
    } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
        e.printStackTrace();
    }

Everything works perfect, until i tested on android 9, here i receive an error:

java.lang.NoSuchMethodException: setDrawableParameters [int, boolean, int, int, class android.graphics.PorterDuff$Mode, int]

Do you have any idea how can i make it work on android 9 also? Thanks.

Ad

Answer

setDrawableParameters(..) is called setDrawableTint(..) in Android 9.0.

Here is the source code of the new method setDrawableTint(..) available in Android 9.0, I guess it does the same job as setDrawableParameters(..) in previous version of Android but you have to try it out in your project.

/** 
 * Equivalent to calling 
 * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}, 
 * on the {@link Drawable} of a given view. 
 * <p> 
 * The operation will be performed on the {@link Drawable} returned by the 
 * target {@link View#getBackground()} by default.  If targetBackground is false, 
 * we assume the target is an {@link ImageView} and try applying the operations 
 * to {@link ImageView#getDrawable()}. 
 * <p> 
 */ 
private class SetDrawableTint extends Action { 
    SetDrawableTint(int id, boolean targetBackground, 
            int colorFilter, @NonNull PorterDuff.Mode mode) { 
        this.viewId = id; 
        this.targetBackground = targetBackground; 
        this.colorFilter = colorFilter; 
        this.filterMode = mode; 
    } 

    SetDrawableTint(Parcel parcel) { 
        viewId = parcel.readInt(); 
        targetBackground = parcel.readInt() != 0; 
        colorFilter = parcel.readInt(); 
        filterMode = PorterDuff.intToMode(parcel.readInt()); 
    } 

    public void writeToParcel(Parcel dest, int flags) { 
        dest.writeInt(viewId); 
        dest.writeInt(targetBackground ? 1 : 0); 
        dest.writeInt(colorFilter); 
        dest.writeInt(PorterDuff.modeToInt(filterMode)); 
    } 

    @Override 
    public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { 
        final View target = root.findViewById(viewId); 
        if (target == null) return; 

        // Pick the correct drawable to modify for this view 
        Drawable targetDrawable = null; 
        if (targetBackground) { 
            targetDrawable = target.getBackground(); 
        } else if (target instanceof ImageView) { 
            ImageView imageView = (ImageView) target; 
            targetDrawable = imageView.getDrawable(); 
        } 

        if (targetDrawable != null) { 
            targetDrawable.mutate().setColorFilter(colorFilter, filterMode); 
        } 
    } 

    @Override 
    public int getActionTag() { 
        return SET_DRAWABLE_TINT_TAG; 
    } 

    boolean targetBackground; 
    int colorFilter; 
    PorterDuff.Mode filterMode; 
} 

You could check how the new method works and what parameters needs and then have in your project something like:

if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P){
    // Your actual implementation with "setDrawableParameters"
    changeImageBackgroundColorBeforeAndroidPIE()
} else{
    // Your new implementation with "setDrawableTint"
    changeImageBackgroundColorAndroidPIEAndLater()
}

Another solution could be:

As I see the method setDrawableParameters(..) is hidden, so it is not meant to be used in this way, I guess it won't be the optimal solution to solve your problem. It looks like a hacky solution, but it can actually get worst once they change it or once it won't be supported in the way you thought it works.

Let's start from the beginning, you want to change the background color of an image in a widget, in a RemoteView more precisely, probably you could convert the drawable into a bitmap and then call RemoteViews.setImageBitmap()

Here is how to Convert a drawable into a bitmap

UPDATE: Another solution that the author just found was

Another solution that worked for me is to have the image source in the xml layout android:src="@mipmap/myImage" and in code remoteViews.setInt(R.id.myImageView,"setColorFilter", myColor);

Here the author answer: https://stackoverflow.com/a/55123126/3564632

Ad
source: stackoverflow.com
Ad