我尝试使用数据绑定将drawable资源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>
最后,活动类:
// ...
public class RecipeActivity extends AppCompatActivity {
public static final String RECIPE_PARCELABLE = "recipe_parcelable";
private Recipe mRecipe;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mRecipe = getIntent().getParcelableExtra(RECIPE_PARCELABLE);
ActivityRecipeBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_recipe);
binding.setRecipe(mRecipe);
}
// ...
}
它根本不显示图像。我做错了什么?
顺便说一下,它完全符合标准方式:@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);
}
答案 0 :(得分:78)
截至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类不需要在任何地方声明,DataBinding机制无论如何都会找到它(我相信)
答案 1 :(得分:19)
定义:
@BindingAdapter({"android:src"})
public static void setImageViewResource(ImageView imageView, int resource) {
imageView.setImageResource(resource);
}
使用:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:scaleType="center"
android:src="@{viewModel.imageRes, default=@drawable/guide_1}"/>
答案 2 :(得分:10)
在创建自己的@BindingAdapter
时,切勿覆盖标准SDK属性!
由于以下原因,这不是一个好方法: 它会阻止在该属性上获得Android SDK更新的新修补程序的好处。此外,它可能会使开发人员感到困惑,并且对于可重用性肯定很棘手(因为它未被覆盖而无法被覆盖)
您可以使用不同的命名空间,如:
custom:src="@{recipe.imageResource}"
或
mybind:src="@{recipe.imageResource}"
------开始更新2.Jul.2018
建议不要使用命名空间,因此最好依赖前缀或不同的名称:
app:custom_src="@{recipe.imageResource}"
或
app:customSrc="@{recipe.imageResource}"
------结束更新2.Jul.2018
但是,我建议使用不同的解决方案:
android:src="@{ContextCompat.getDrawable(context, recipe.imageResource)}"
上下文视图始终在绑定表达式@{ ... }
答案 3 :(得分:4)
对于 Kotlin ,将其放到顶级utils文件中,不需要静态/伴随上下文:
@BindingAdapter("android:src")
fun setImageViewResource(view: ImageView, resId : Int) {
view.setImageResource(resId)
}
答案 4 :(得分:3)
public Drawable getImageRes() {
return mContext.getResources().getDrawable(R.drawable.icon);
}
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:src="@{viewModel.imageRes}"/>
答案 5 :(得分:2)
DataBindingAdapter
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);
}
}
如果您问我为什么我使用Glide加载可绘制/资源ID,我可以使用imageView.setImageBitmap();
或imageView.setImageResource();
。所以原因是
如果您使用Piccaso,Fresso或任何其他图像加载库,则可以使用loadImageWithGlide
方法进行更改。
答案 6 :(得分:2)
基于Maher Abuthraa的回答,这就是我最终在XML中使用的内容:
android:src="@{context.getDrawable(recipe.imageResource)}"
绑定表达式中的context
变量is available没有任何导入。另外,也不需要自定义BindingAdapter
。唯一需要注意的是:getDrawable
方法仅在API 21之后可用。
答案 7 :(得分:2)
为我工作。我会把它添加到@hqzxzwb答案中作为评论,但是由于声誉限制。
我的模型中有这个
var passport = R.drawable.passport
然后在我的xml中,我有
android:src="@{context.getDrawable(model.passort)}"
就这样
答案 8 :(得分:1)
使用Fresco(脸谱图像库)
SELECT
s.class,
SUM(CASE o.result WHEN 'sunk' THEN 1 ELSE 0 END) AS sunk_ships
FROM ships s
LEFT JOIN classes c ON s.class = c.class
LEFT JOIN outcomes o ON s.name = o.ship
WHERE c.class IN (
SELECT
s.class
FROM ships s
GROUP BY s.class
HAVING COUNT(*) >= 3
)
GROUP BY s.class;
答案 9 :(得分:1)
根本不需要自定义 BindingAdapter。 Just use。
数据:
<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}" />
答案 10 :(得分:0)
我不是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>
所以这里我只保留重要的内容:
SomeViewModel
是我用于数据绑定的ViewModel
。您还可以使用扩展BaseObservable
并使用@Bindable
的类。但是,在此示例中,BindingAdapter
不必属于ViewModel
或BaseObservable
类!普通班就可以!稍后将对此进行说明。app:appIconDrawable="@{model.packageName}"
。是的...这真的让我头疼!让我们分解一下:
app:appIconDrawable
:可以是任何东西:app:iCanBeAnything
!真。您还可以保留"android:src"
!但是,请注意您的选择,我们将在以后使用!假设我们使用这个简单的Observable类:
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 aligned, that's it! :)
//
// The name of the fuction, 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 static void setImageViewDrawable()
移到其他班级,例如也许您可以使用包含BindingAdapters
集合的类:
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,适配器将变为:
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);
}
}
答案 11 :(得分:0)
您可以执行以下
android:src="@{expand?@drawable/ic_collapse:@drawable/ic_expand}"
答案 12 :(得分:0)
在您的视图状态或视图模型类中;
fun getSource(context: Context): Drawable? {
return ContextCompat.getDrawable(context, R.drawable.your_source)
}
在您的XML中;
<androidx.appcompat.widget.AppCompatImageButton
.
.
.
android:src="@{viewState.getSource(context)}"
答案 13 :(得分:0)
答案 14 :(得分:0)
<?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>
答案 15 :(得分:0)
像这样设置图片
<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" />