如何在android小部件中更改图像的背景色

如何在android小部件中更改图像的背景色,android,widget,background-image,Android,Widget,Background Image,我在小部件中更改图像的背景色时遇到问题。 现在我用的是这样的: 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.

我在小部件中更改图像的背景色时遇到问题。 现在我用的是这样的:

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();
    }
一切都很完美,直到我在android 9上测试,这里我收到一个错误:

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

你知道我怎样才能让它也在android 9上工作吗?
谢谢。

setDrawableParameters(..)
在Android 9.0中被称为
setDrawableTint(..)

以下是Android 9.0中提供的新方法
setDrawableTint(..)
的源代码,我想它与Android早期版本中的
setDrawableParameters(..)
的功能相同,但您必须在项目中试用

/** 
 * 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; 
} 
/**
*相当于呼叫
*{@link Drawable#setColorFilter(int,android.graphics.PorterDuff.Mode)},
*在给定视图的{@link Drawable}上。
*
*该操作将在返回的{@link Drawable}上执行
*默认情况下,目标为{@link View#getBackground()}。如果targetBackground为false,
*我们假设目标是{@link ImageView},并尝试应用这些操作
*到{@link ImageView#getDrawable()}。
*
*/ 
私有类SetDrawableTint扩展操作{
SetDrawableTint(整数id,布尔targetBackground,
int colorFilter,@NonNull PorterDuff.Mode模式){
this.viewId=id;
this.targetBackground=targetBackground;
this.colorFilter=colorFilter;
this.filterMode=模式;
} 
SetDrawableTint(包裹){
viewId=parcel.readInt();
targetBackground=parcel.readInt()!=0;
colorFilter=parcel.readInt();
filterMode=PorterDuff.intToMode(parcel.readInt());
} 
公共无效writeToParcel(Parcel dest,int标志){
目标写入(视图ID);
目标写入(targetBackground?1:0);
目的写入(颜色过滤器);
目的写入(PorterDuff.modeToInt(filterMode));
} 
@凌驾
public void apply(视图根、视图组根父、OnClickHandler处理程序){
最终视图目标=root.findviewbyd(viewId);
if(target==null)返回;
//为此视图选择要修改的正确绘图
Drawable targetDrawable=null;
if(targetBackground){
targetDrawable=target.getBackground();
}如果(ImageView的目标实例){
ImageView ImageView=(ImageView)目标;
targetDrawable=imageView.getDrawable();
} 
如果(targetDrawable!=null){
targetDrawable.mutate().setColorFilter(colorFilter,filterMode);
} 
} 
@凌驾
public int getActionTag(){
返回设置\u可绘制\u着色\u标签;
} 
布尔目标背景;
int彩色滤光片;
PorterDuff.Mode filterMode;
} 
您可以检查新方法的工作方式以及需要哪些参数,然后在项目中包含如下内容:

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()
}
if(android.os.Build.VERSION.SDK\u INT
另一个解决方案可以是:

正如我看到的方法
setDrawableParameters(..)
是隐藏的,因此它不打算以这种方式使用,我想它不会是解决问题的最佳解决方案。它看起来像一个黑客解决方案,但一旦他们改变它,或者一旦它无法以您认为有效的方式得到支持,它实际上可能会变得最糟糕

让我们从头开始,您想要更改小部件中图像的背景色,在
RemoteView
中更准确地说,您可以将
可绘制的
转换为
位图
,然后调用

以下是如何

更新:作者刚刚找到的另一个解决方案是


另一个对我有效的解决方案是在 xml布局android:src=“@mipmap/myImage”和代码 setInt(R.id.myImageView,“setColorFilter”,myColor)


作者的回答是:

另一个对我有效的解决方案是将图像源放在xml布局
android:src=“@mipmap/myImage”
和code
remoteview.setInt(R.id.myImageView,“setColorFilter”,myColor)中

我已经尝试了解决方案1:
Drawable-Drawable=ContextCompat.getDrawable(context,R.mipmap.image);drawable.setColorFilter(Color.HSVToColor(mycolor),PorterDuff.Mode.SRC_;位图位图=drawableToBitmap(drawable);RemoteView.setImageViewBitmap(R.id.myimageview,位图);
,但不起作用。解决方案2它起作用了,非常感谢。尝试Android 9中提供的新方法。我更新了我的答案,以更好地匹配您问题的上下文和范围第一个解决方案有效…但我收到了屏幕上弹出一条消息:
检测到API兼容性问题
若要解决此问题,我必须将targetSdkVersion修改为28,但之后背景不变,我收到错误:
java.lang.NoSuchMethodException:setDrawableTint[int,boolean,int,class android.graphics.PorterDuff$Mode]
弹出窗口之所以出现,是因为您试图访问深灰色列表API方法中的方法是的,您是对的……看起来没有办法更改小部件的背景图像颜色……我喜欢它!@Bogdan感谢您的贡献!我添加了您的答案,并在我的accep中提到了您