J'essaie de définir l'ID de ressource pouvant être dessiné sur Android: src d'ImageView à l'aide de la liaison de données
Voici mon objet:
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;
}
// ...
}
Voici ma mise en page:
<?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>
Et enfin, classe d'activité:
// ...
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);
}
// ...
}
Il n'affiche pas du tout l'image. Qu'est-ce que je fais mal?
BTW, cela fonctionnait parfaitement avec la manière standard:
@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);
}
la source
@BindingAdapter
. Mais, la valeur devrait êtreandroid:src
, nonimageResource
:@BindingAdapter("android:src")
. Merci!<ImageView imageResource="@{recipe.imageResource}" />
et@BindingAdapter("imageResource")
. Je viens de manquer uneimageResource="@{recipe.imageResource}"
partie de votre code extrait :)app:imageResource
?Il n'y a aucun besoin de coutume
BindingAdapter
. Juste utiliserapp:imageResource="@{yourResId}"
et cela fonctionnera très bien.
Vérifiez ceci pour savoir comment cela fonctionne.
la source
ImageView
classe et suis lasetImageResource
méthode, il semble que finalement est résolu surresolveUri
et qu'il n'y ait sinon aucune validation. Cela fonctionnerait donc carInt
je me demande ce qui pourrait arriver siInt?
. Lorsque les liaisons sont exécutées, par exemple, si quelque chose d'autre appelle,executePendingBindings
alors non nullable est défini par défaut sur zéro, nullables sur null.définir:
@BindingAdapter({"android:src"}) public static void setImageViewResource(ImageView imageView, int resource) { imageView.setImageResource(resource); }
utilisation:
<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}"/>
la source
Ne remplacez jamais les attributs standard du SDK lorsque vous créez les vôtres
@BindingAdapter
!Ce n'est pas une bonne approche pour de nombreuses raisons telles que: cela empêchera d'obtenir les avantages de nouveaux correctifs sur la mise à jour du SDK Android sur cet attribut. En outre, cela pourrait dérouter les développeurs et sûrement compliqué pour la réutilisabilité (car il ne devrait pas être remplacé)
vous pouvez utiliser différents espaces de noms comme:
custom:src="@{recipe.imageResource}"
ou
mybind:src="@{recipe.imageResource}"
------ démarrer la mise à jour 2.juil.2018
Il n'est pas recommandé d'utiliser l'espace de noms, il est donc préférable de s'appuyer sur un préfixe ou un nom différent comme:
app:custom_src="@{recipe.imageResource}"
ou
app:customSrc="@{recipe.imageResource}"
------ mettre fin à la mise à jour du 2 juillet 2018
Cependant, je recommanderais une solution différente comme:
android:src="@{ContextCompat.getDrawable(context, recipe.imageResource)}"
la vue contextuelle est toujours disponible dans l'expression de liaison
@{ ... }
la source
Sur la base de la réponse de Maher Abuthraa, voici ce que j'ai fini par utiliser dans le XML:
android:src="@{context.getDrawable(recipe.imageResource)}"
La
context
variable est disponible dans l'expression de liaison sans aucune importation. En outre, aucune coutume n'estBindingAdapter
nécessaire. Seul bémol: la méthodegetDrawable
n'est disponible que depuis l'API 21.la source
Pour Kotlin, placez ceci dans un fichier utils de niveau supérieur, aucun contexte statique / compagnon n'est nécessaire:
@BindingAdapter("android:src") fun setImageViewResource(view: ImageView, resId : Int) { view.setImageResource(resId) }
la source
Plus vous pouvez faire avec
DataBindingAdapter
Définissez l'un de ces types:
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`}"
Définir l'image d'erreur / l'image d'espace réservé
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`}" />
Testé tous les types
Cela devient donc possible avec un seul adaptateur de liaison. Copiez simplement ce projet de méthode.
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); } }
Raison pour laquelle j'ai utilisé Glide pour charger tous les objets
Si vous me demandez pourquoi j'ai utilisé Glide pour charger l'ID drawable / resource, je pourrais plutôt utiliser
imageView.setImageBitmap();
ouimageView.setImageResource();
. Donc la raison est queSi vous utilisez Piccaso, Fresso ou toute autre bibliothèque de chargement d'images, vous pouvez modifier la
loadImageWithGlide
méthode .la source
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}"/>
la source
vous pouvez faire ce qui suit
android:src="@{expand?@drawable/ic_collapse:@drawable/ic_expand}"
la source
Je ne suis pas un expert d'Android mais j'ai passé des heures à essayer de déchiffrer les solutions existantes. La bonne chose est que j'ai saisi toute l'idée de la liaison de données en utilisant
BindingAdapter
un peu mieux. Pour cela, je suis au moins reconnaissant pour les réponses existantes (bien que très incomplètes). Voici un aperçu complet de l'approche:J'utiliserai également le
BindingAdapter
dans cet exemple. Préparer lexml
:<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>
Donc ici je ne garde que les choses importantes:
SomeViewModel
est monViewModel
que j'utilise pour la liaison de données. Vous pouvez également utiliser une classe qui étendBaseObservable
et utilise@Bindable
. Cependant,BindingAdapter
dans cet exemple, n'a pas besoin d' être dans unViewModel
BaseObservable
classe ou ! Une classe simple fera l'affaire! Cela sera illustré plus tard.app:appIconDrawable="@{model.packageName}"
. Oui ... cela me causait vraiment des maux de tête! Décomposons-le:app:appIconDrawable
: Cela peut être n'importe quoiapp:iCanBeAnything
:! Vraiment. Vous pouvez également garder"android:src"
! Cependant, prenez note de votre choix, nous l'utiliserons plus tard!Supposons que nous utilisons cette simple classe 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 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)); } }
Comme promis, vous pouvez également déplacer le
public static void setImageViewDrawable()
, vers une autre classe, par exemple vous pouvez peut-être avoir une classe qui a une collection deBindingAdapters
:public class BindingAdapterCollection { @BindingAdapter({"appIconDrawable"}) public static void setImageViewDrawable(ImageView imageView, String packageName) { imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName)); } }
Une autre remarque importante est que dans ma
Observable
classe, jeString packageName
transmettais des informations supplémentaires ausetImageViewDrawable
. Vous pouvez également choisir par exempleint resourceId
, avec les getters / setters correspondants, pour lesquels l'adaptateur devient: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); } }
la source
Ce travail pour moi. Je l'aurais ajouté à la réponse @hqzxzwb en commentaire, mais en raison de limitations de réputation.
J'ai ceci dans ma vue Modèle
var passport = R.drawable.passport
Puis dans mon xml, j'ai
android:src="@{context.getDrawable(model.passort)}"
Et c'est tout
la source
Utilisation de Fresco (bibliothèque d'images 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)); } } }
la source
Dans votre état d'affichage ou dans votre classe de modèle de vue;
fun getSource(context: Context): Drawable? { return ContextCompat.getDrawable(context, R.drawable.your_source) }
Dans votre XML;
<androidx.appcompat.widget.AppCompatImageButton . . . android:src="@{viewState.getSource(context)}"
la source
<?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>
la source
définir l'image comme celle-ci,
<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" />
la source