Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/229.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在android中使用数据绑定为ImageView设置可绘制资源ID:src_Android_Android Layout_Android Databinding - Fatal编程技术网

在android中使用数据绑定为ImageView设置可绘制资源ID:src

在android中使用数据绑定为ImageView设置可绘制资源ID:src,android,android-layout,android-databinding,Android,Android Layout,Android Databinding,我正在尝试使用数据绑定将drawable resource ID设置为ImageView的android:src 这是我的目标: public class Recipe implements Parcelable { public final int imageResource; // resource ID (e.g. R.drawable.some_image) public final String title; // ... public Recipe(

我正在尝试使用数据绑定将drawable resource ID设置为ImageView的android:src

这是我的目标:

public class Recipe implements Parcelable {
    public final int imageResource; // resource ID (e.g. R.drawable.some_image)
    public final String title;
    // ...

    public Recipe(int imageResource, String title /* ... */) {
        this.imageResource = imageResource;
        this.title = title;
    }

    // ...
}
以下是我的布局:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="recipe"
            type="com.example.android.fivewaystocookeggs.Recipe" />
    </data>

    <!-- ... -->

    <ImageView
        android:id="@+id/recipe_image_view"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="centerCrop"
        android:src="@{recipe.imageResource}" />

    <!-- ... -->

</layout>
它根本不显示图像。我做错了什么

顺便说一句,这是完美的工作与标准的方式:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recipe);

    final ImageView recipeImageView = (ImageView) findViewById(R.id.recipe_image_view);
    recipeImageView.setImageResource(mRecipe.imageResource);

}

截至2016年11月10日的回答

Splash下面的评论强调了不必使用自定义属性类型(如
imageResource
),我们可以为
android:src
创建多个方法,如:

public class DataBindingAdapters {

    @BindingAdapter("android:src")
    public static void setImageUri(ImageView view, String imageUri) {
        if (imageUri == null) {
            view.setImageURI(null);
        } else {
            view.setImageURI(Uri.parse(imageUri));
        }
    }

    @BindingAdapter("android:src")
    public static void setImageUri(ImageView view, Uri imageUri) {
        view.setImageURI(imageUri);
    }

    @BindingAdapter("android:src")
    public static void setImageDrawable(ImageView view, Drawable drawable) {
        view.setImageDrawable(drawable);
    }

    @BindingAdapter("android:src")
    public static void setImageResource(ImageView imageView, int resource){
        imageView.setImageResource(resource);
    }
}

旧答案

您始终可以尝试使用适配器:

public class DataBindingAdapters {

    @BindingAdapter("imageResource")
    public static void setImageResource(ImageView imageView, int resource){
        imageView.setImageResource(resource);
    }
}
然后,您可以像这样在xml中使用适配器

<ImageView
    android:id="@+id/recipe_image_view"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:scaleType="centerCrop"
    imageResource="@{recipe.imageResource}" />

请务必注意,xml中的名称与BindingAdapter注释(imageResource)匹配。

DataBindingAdapters类不需要在任何地方声明,尤其是数据绑定机制将发现它,无论(我相信)定义:

@BindingAdapter({"android:src"})
public static void setImageViewResource(ImageView imageView, int resource) {
    imageView.setImageResource(resource);
}
使用:


使用Fresco(facebook图像库)

public可绘制getImageRes(){
返回mContext.getResources().getDrawable(R.drawable.icon);
}

对于Kotlin将其放在顶级utils文件中,不需要静态/伴随上下文:

@BindingAdapter("android:src")
fun setImageViewResource(view: ImageView, resId : Int) {
    view.setImageResource(resId)
}

创建自己的
@BindingAdapter
时,切勿覆盖标准SDK属性

这不是一个好方法,原因很多,如: 这将阻止获得安卓SDK上的新修复程序对该属性进行更新的好处。此外,它可能会让开发人员感到困惑,并且在可重用性方面肯定很棘手(因为它是不可扩展的,因此无法被覆盖)

您可以使用不同的命名空间,如:

custom:src="@{recipe.imageResource}"

------2018年7月2日开始更新

不建议使用名称空间,因此最好依赖前缀或其他名称,如:

app:custom_src="@{recipe.imageResource}"

------完2018年7月2日更新

但是,我会推荐不同的解决方案,如:

android:src="@{ContextCompat.getDrawable(context, recipe.imageResource)}"
上下文视图始终在绑定表达式中可用
@{…}

使用
DataBindingAdapter
  • 您可以通过数据绑定设置图像Url文件位图字节数组可绘制可绘制Id任何内容
  • 也可以使用设置错误图像/占位符图像
设置以下任一类型: 设置错误图像/占位符图像

placeholderImage="@{@drawable/img_placeholder}"
errorImage="@{@drawable/img_error}"


<ImageView
    placeholderImage="@{@drawable/ic_launcher}"
    errorImage="@{@drawable/ic_launcher}"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:src="@{`https://placekitten.com/2000/2000`}"
    />
placeholder image=“@{@drawable/img_placeholder}”
errorImage=“@{@drawable/img_error}”
测试了所有类型

因此,使用单个绑定适配器就可以做到这一点。只需复制此方法项目

public class BindingAdapters {
    @BindingAdapter(value = {"android:src", "placeholderImage", "errorImage"}, requireAll = false)
    public static void loadImageWithGlide(ImageView imageView, Object obj, Object placeholder, Object errorImage) {
        RequestOptions options = new RequestOptions();
        if (placeholder instanceof Drawable) options.placeholder((Drawable) placeholder);
        if (placeholder instanceof Integer) options.placeholder((Integer) placeholder);

        if (errorImage instanceof Drawable) options.error((Drawable) errorImage);
        if (errorImage instanceof Integer) options.error((Integer) errorImage);

        RequestManager manager = Glide.with(App.getInstance()).
                applyDefaultRequestOptions(options);
        RequestBuilder<Drawable> builder;

        if (obj instanceof String) {
            builder = manager.load((String) obj);
        } else if (obj instanceof Uri)
            builder = manager.load((Uri) obj);
        else if (obj instanceof Drawable)
            builder = manager.load((Drawable) obj);
        else if (obj instanceof Bitmap)
            builder = manager.load((Bitmap) obj);
        else if (obj instanceof Integer)
            builder = manager.load((Integer) obj);
        else if (obj instanceof File)
            builder = manager.load((File) obj);
        else if (obj instanceof Byte[])
            builder = manager.load((Byte[]) obj);
        else builder = manager.load(obj);
        builder.into(imageView);
    }
}
公共类绑定适配器{
@BindingAdapter(值={“android:src”、“占位符图像”、“错误图像”},requireAll=false)
公共静态void loadImageWithGlide(图像视图、对象对象、对象占位符、对象错误图像){
RequestOptions=newrequestoptions();
if(可绘制的占位符实例)选项。占位符((可绘制的)占位符);
if(整数的占位符实例)选项。占位符((整数)占位符);
if(errorImage instanceof Drawable)options.error((Drawable)errorImage);
if(errorImage instanceof Integer)选项。error((Integer)errorImage);
RequestManager=Glide.with(App.getInstance())。
applyDefaultRequestOptions(选项);
请求生成器;
if(字符串的obj实例){
builder=manager.load((字符串)obj);
}else if(Uri的obj实例)
builder=manager.load((Uri)obj);
else if(可拉伸的obj实例)
builder=manager.load((可绘制)对象);
else if(位图的obj实例)
builder=manager.load((位图)obj);
else if(obj instanceof Integer)
builder=manager.load((整数)obj);
else if(文件的obj实例)
builder=manager.load((文件)obj);
else if(字节[]的obj实例)
builder=manager.load((字节[])obj);
else builder=manager.load(obj);
builder.into(imageView);
}
}
我使用Glide加载所有对象的原因 如果您问我为什么使用Glide加载可绘制/资源id,我可以使用
imageView.setImageBitmap()
imageView.setImageResource()。所以原因是

  • Glide是一个高效的图像加载框架,它封装了媒体解码、内存和磁盘缓存。因此,您无需担心大尺寸图像和缓存
  • 加载图像时保持一致性。现在所有类型的图像资源都由Glide加载

如果您使用Piccaso、Fresso或任何其他图像加载库,您可以使用Glide
方法对
加载图像进行更改

我不是Android专家,但我花了数小时试图破解现有的解决方案。好的是,我更好地掌握了使用
BindingAdapter
进行数据绑定的整个思想。为此,我至少要感谢现有的答案(尽管还很不完整)。以下是该方法的完整分类:

在本例中,我还将使用
BindingAdapter
。准备
xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="model"
            type="blahblah.SomeViewModel"/>
    </data>

    <!-- blah blah -->

    <ImageView
        android:id="@+id/ImageView"
        app:appIconDrawable="@{model.packageName}"/>

    <!-- blah blah -->
</layout>
正如所承诺的,您还可以将
公共静态void setImageViewDrawable()
移动到其他类,例如,您可以拥有一个包含
绑定适配器集合的类

public class BindingAdapterCollection {
   @BindingAdapter({"appIconDrawable"})
   public static void setImageViewDrawable(ImageView imageView, String packageName) {
       imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName));
   }
}
另一个重要的注意事项是,在我的
Observable
类中,我使用
String packageName
将额外的信息传递给
setImageViewDrawable
。您还可以选择例如
int-resourceId
,以及相应的getter/setter,对于这些getter/setter,适配器变为:

public class SomeViewModel extends BaseObservable {
   private String packageName; // this is what @{model.packageName}
                               // access via the getPackageName() !!!
   private int resourceId;     // if you use this, don't forget to update
                               // your xml with: @{model.resourceId}

   @Bindable
   public String getPackageName() {
       return packageName;
   }

   public void setPackageName(String packageName) {
       this.packageName = packageName;
       notifyPropertyChanged(BR.packageName);
   }

   @Bindable
   public int getResourceId() {
       return packageName;
   }

   public void setResourceId(int resourceId) {
       this.resourceId = resourceId;
       notifyPropertyChanged(BR.resourceId);
   }

   // For this you use: app:appIconDrawable="@{model.packageName}" (passes String)
   @BindingAdapter({"appIconDrawable"})
   public static void setImageViewDrawable(ImageView imageView, String packageName) {
       imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName));
   }

   // for this you use: app:appIconResourceId="@{model.resourceId}" (passes int)
   @BindingAdapter({"appIconResourceId"})
   public static void setImageViewResourceId(ImageView imageView, int resource) {
       imageView.setImageResource(resource);
   }
}

您可以执行以下操作

android:src="@{expand?@drawable/ic_collapse:@drawable/ic_expand}"

在视图状态或视图模型类中<
android:src="@{model.profileImage}"

android:src="@{roundIcon ? @drawable/ic_launcher_round : @drawable/ic_launcher_round}"

android:src="@{bitmap}"

android:src="@{model.drawableId}"

android:src="@{@drawable/ic_launcher}"

android:src="@{file}"

android:src="@{`https://placekitten.com/200/200`}"
placeholderImage="@{@drawable/img_placeholder}"
errorImage="@{@drawable/img_error}"


<ImageView
    placeholderImage="@{@drawable/ic_launcher}"
    errorImage="@{@drawable/ic_launcher}"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:src="@{`https://placekitten.com/2000/2000`}"
    />
public class BindingAdapters {
    @BindingAdapter(value = {"android:src", "placeholderImage", "errorImage"}, requireAll = false)
    public static void loadImageWithGlide(ImageView imageView, Object obj, Object placeholder, Object errorImage) {
        RequestOptions options = new RequestOptions();
        if (placeholder instanceof Drawable) options.placeholder((Drawable) placeholder);
        if (placeholder instanceof Integer) options.placeholder((Integer) placeholder);

        if (errorImage instanceof Drawable) options.error((Drawable) errorImage);
        if (errorImage instanceof Integer) options.error((Integer) errorImage);

        RequestManager manager = Glide.with(App.getInstance()).
                applyDefaultRequestOptions(options);
        RequestBuilder<Drawable> builder;

        if (obj instanceof String) {
            builder = manager.load((String) obj);
        } else if (obj instanceof Uri)
            builder = manager.load((Uri) obj);
        else if (obj instanceof Drawable)
            builder = manager.load((Drawable) obj);
        else if (obj instanceof Bitmap)
            builder = manager.load((Bitmap) obj);
        else if (obj instanceof Integer)
            builder = manager.load((Integer) obj);
        else if (obj instanceof File)
            builder = manager.load((File) obj);
        else if (obj instanceof Byte[])
            builder = manager.load((Byte[]) obj);
        else builder = manager.load(obj);
        builder.into(imageView);
    }
}
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="model"
            type="blahblah.SomeViewModel"/>
    </data>

    <!-- blah blah -->

    <ImageView
        android:id="@+id/ImageView"
        app:appIconDrawable="@{model.packageName}"/>

    <!-- blah blah -->
</layout>
public class SomeViewModel extends BaseObservable {
   private String packageName; // this is what @{model.packageName}
                               // access via the getPackageName() !!!
                               // Of course this needs to be set at some
                               // point in your program, before it makes
                               // sense to use it in the BindingAdapter.

   @Bindable
   public String getPackageName() {
       return packageName;
   }

   public void setPackageName(String packageName) {
       this.packageName = packageName;
       notifyPropertyChanged(BR.packageName);
   }

   // The "appIconDrawable" is what we defined above! 
   // Remember, they have to align!! As we said, we can choose whatever "app:WHATEVER".
   // The BindingAdapter and the xml need to be aligned, that's it! :)
   //
   // The name of the function, i.e. setImageViewDrawable, can also be 
   // whatever we want! Doesn't matter.
   @BindingAdapter({"appIconDrawable"})
   public static void setImageViewDrawable(ImageView imageView, String packageName) {
       imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName));
   }
}
public class BindingAdapterCollection {
   @BindingAdapter({"appIconDrawable"})
   public static void setImageViewDrawable(ImageView imageView, String packageName) {
       imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName));
   }
}
public class SomeViewModel extends BaseObservable {
   private String packageName; // this is what @{model.packageName}
                               // access via the getPackageName() !!!
   private int resourceId;     // if you use this, don't forget to update
                               // your xml with: @{model.resourceId}

   @Bindable
   public String getPackageName() {
       return packageName;
   }

   public void setPackageName(String packageName) {
       this.packageName = packageName;
       notifyPropertyChanged(BR.packageName);
   }

   @Bindable
   public int getResourceId() {
       return packageName;
   }

   public void setResourceId(int resourceId) {
       this.resourceId = resourceId;
       notifyPropertyChanged(BR.resourceId);
   }

   // For this you use: app:appIconDrawable="@{model.packageName}" (passes String)
   @BindingAdapter({"appIconDrawable"})
   public static void setImageViewDrawable(ImageView imageView, String packageName) {
       imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName));
   }

   // for this you use: app:appIconResourceId="@{model.resourceId}" (passes int)
   @BindingAdapter({"appIconResourceId"})
   public static void setImageViewResourceId(ImageView imageView, int resource) {
       imageView.setImageResource(resource);
   }
}
android:src="@{expand?@drawable/ic_collapse:@drawable/ic_expand}"
 fun getSource(context: Context): Drawable? {
        return ContextCompat.getDrawable(context, R.drawable.your_source)
    }
<androidx.appcompat.widget.AppCompatImageButton
   .
   .
   .
   android:src="@{viewState.getSource(context)}"
android:src="@{context.getDrawable(recipe.imageResource)}"
app:imageResource="@{yourResId}"
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
           name="model"
           type="YourViewModel"/>
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:background="?android:attr/selectableItemBackground"
          android:paddingStart="@dimen/dp16"
          android:paddingTop="@dimen/dp8"
          android:paddingEnd="@dimen/dp8"
          android:paddingBottom="@dimen/dp8">

          <ImageView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content" 
              android:src="@{model.selected ? @drawable/check_fill : @drawable/check_empty}"/>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
var passport = R.drawable.passport
android:src="@{context.getDrawable(model.passort)}"
  <ImageView
        android:layout_width="28dp"
        android:layout_height="28dp"
        android:src="@{model.isActive ? @drawable/white_activated_icon :@drawable/activated_icon}"
        tools:src="@mipmap/white_activated_icon" />
<data>
    <import type="com.example.R"/>
      :
</data>
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:imageResource="@{gender == 0 ? R.drawable.male : R.drawable.female}" />