在android中使用数据绑定为ImageView设置可绘制资源ID:src
我正在尝试使用数据绑定将drawable resource ID设置为ImageView的android: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(
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}" />