Estoy tratando de establecer el ID de recurso dibujable en android: src de ImageView usando el enlace de datos
Aquí está mi objeto:
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;
}
// ...
}
Aquí está mi diseño:
<?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>
Y finalmente, clase de actividad:
// ...
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);
}
// ...
}
No muestra ninguna imagen. ¿Qué estoy haciendo mal?
Por cierto, estaba funcionando perfectamente con la forma estándar:
@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);
}
fuente

@BindingAdapter. Sin embargo, el valor debe serandroid:src, noimageResource:@BindingAdapter("android:src"). ¡Gracias!<ImageView imageResource="@{recipe.imageResource}" />y@BindingAdapter("imageResource"). Me perdíimageResource="@{recipe.imageResource}"parte de tu código recortado :)app:imageResource?No hay necesidad de una costumbre
BindingAdapteren absoluto. Solo usaapp:imageResource="@{yourResId}"y funcionará bien.
Compruebe esto para saber cómo funciona.
fuente
ImageViewclase y siguiendo elsetImageResourcemétodo, parece que finalmente se resuelveresolveUriy hay, si no cero, validación. Así que eso funcionaría porqueIntme pregunto qué podría pasar siInt?. Cuando se ejecutan los enlaces, por ejemplo, si otra llamada,executePendingBindingsentonces los que no aceptan valores nulos se establecen por defecto en cero, los valores nulos en nulos.definir:
@BindingAdapter({"android:src"}) public static void setImageViewResource(ImageView imageView, int resource) { imageView.setImageResource(resource); }utilizar:
<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}"/>fuente
¡Nunca anule los atributos estándar del SDK cuando cree los suyos propios
@BindingAdapter!Este no es un buen enfoque por muchas razones como: evitará obtener beneficios de nuevas correcciones en la actualización del SDK de Android en ese atributo. También puede confundir a los desarrolladores y seguramente es complicado para la reutilización (porque no se espera que se anule)
puede usar diferentes espacios de nombres como:
custom:src="@{recipe.imageResource}"o
mybind:src="@{recipe.imageResource}"------ iniciar actualización 2.Jul.2018
No se recomienda el uso del espacio de nombres, por lo que es mejor confiar en el prefijo o en un nombre diferente como:
app:custom_src="@{recipe.imageResource}"o
app:customSrc="@{recipe.imageResource}"------ Finalizar actualización 2.Jul.2018
Sin embargo, recomendaría una solución diferente como:
android:src="@{ContextCompat.getDrawable(context, recipe.imageResource)}"la vista de contexto siempre está disponible dentro de la expresión de enlace
@{ ... }fuente
Sobre la base de la respuesta de Maher Abuthraa, esto es lo que terminé usando en el XML:
android:src="@{context.getDrawable(recipe.imageResource)}"La
contextvariable está disponible en expresión de enlace sin ninguna importación. Además, no esBindingAdapternecesario personalizarlo . Solo advertencia: el métodogetDrawablesolo está disponible desde API 21.fuente
Para Kotlin, ponga esto en un archivo de utils de nivel superior, no se necesita contexto estático / complementario:
@BindingAdapter("android:src") fun setImageViewResource(view: ImageView, resId : Int) { view.setImageResource(resId) }fuente
Cuanto más puedas hacer con
DataBindingAdapterConfigure cualquiera de estos tipos:
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`}"Establecer imagen de error / imagen de marcador de posición
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`}" />Probado todos los tipos
Eso es posible con un solo adaptador de enlace. Simplemente copie este proyecto de método.
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); } }Razón por la que usé Glide para cargar todos los objetos
Si me preguntas por qué usé Glide para cargar la identificación del recurso / dibujable, en su lugar podría usar
imageView.setImageBitmap();oimageView.setImageResource();. Entonces la razón es queSi usa Piccaso, Fresso o cualquier otra biblioteca de carga de imágenes, puede realizar cambios en el
loadImageWithGlidemétodo .fuente
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}"/>fuente
puedes hacer lo siguiente
android:src="@{expand?@drawable/ic_collapse:@drawable/ic_expand}"fuente
No soy un experto en Android pero pasé horas intentando descifrar las soluciones existentes. Lo bueno es que comprendí
BindingAdapterun poco mejor la idea de vinculación de datos . Por eso, estoy al menos agradecido por las respuestas existentes (aunque muy incompletas). Aquí un desglose completo del enfoque:También usaré
BindingAdapteren este ejemplo. Preparando elxml:<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>Así que aquí estoy guardando solo las cosas importantes:
SomeViewModeles miViewModeluso para el enlace de datos. También puede usar una clase que amplíeBaseObservabley use@Bindable. Sin embargo,BindingAdapteren este ejemplo, ¡ no tiene que estar en una claseViewModeloBaseObservable! ¡Una clase sencilla servirá! Esto se ilustrará más adelante.app:appIconDrawable="@{model.packageName}". Sí ... ¡esto realmente me estaba causando dolores de cabeza! Vamos a analizarlo:app:appIconDrawable: Esto puede ser cualquier cosaapp:iCanBeAnything:! De Verdad. ¡También puedes quedarte"android:src"! Sin embargo, tome nota de su elección, ¡la usaremos más adelante!Supongamos que usamos esta clase observable simple:
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)); } }Como se prometió, también puede mover el
public static void setImageViewDrawable(), a otra clase, por ejemplo, tal vez pueda tener una clase que tenga una colección deBindingAdapters:public class BindingAdapterCollection { @BindingAdapter({"appIconDrawable"}) public static void setImageViewDrawable(ImageView imageView, String packageName) { imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName)); } }Otro comentario importante es que en mi
Observableclase solíaString packageNamepasar información adicional alsetImageViewDrawable. También puede elegir, por ejemploint resourceId, con los getters / setters correspondientes, para lo cual el adaptador se convierte en: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); } }fuente
Esto funciona para mí. Lo habría agregado a la respuesta de @hqzxzwb como comentario, pero debido a limitaciones de reputación.
Tengo esto en mi modelo de vista
var passport = R.drawable.passportLuego, en mi xml, tengo
android:src="@{context.getDrawable(model.passort)}"Y eso es
fuente
Usando Fresco (biblioteca de imágenes de Facebook)
public class YourCustomBindingAdapters { //app:imageUrl="@{data.imgUri}" @BindingAdapter("bind:imageUrl") public static void loadImage(SimpleDraweeView imageView, String url) { if (url == null) { imageView.setImageURI(Uri.EMPTY); } else { if (url.length() == 0) imageView.setImageURI(Uri.EMPTY); else imageView.setImageURI(Uri.parse(url)); } } }fuente
En su estado de vista o clase de modelo de vista;
fun getSource(context: Context): Drawable? { return ContextCompat.getDrawable(context, R.drawable.your_source) }En su XML;
<androidx.appcompat.widget.AppCompatImageButton . . . android:src="@{viewState.getSource(context)}"fuente
<?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>fuente
establecer una imagen como esta,
<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" />fuente