Saya mencoba menyetel ID sumber daya yang dapat digambar ke android: src dari ImageView menggunakan data binding
Inilah objek saya:
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;
}
// ...
}
Inilah tata letak saya:
<?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>
Dan terakhir, kelas aktivitas:
// ...
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);
}
// ...
}
Itu tidak menampilkan gambar sama sekali. Apa yang saya lakukan salah?
BTW, itu bekerja sempurna dengan cara standar:
@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);
}
sumber
@BindingAdapter
. Tapi, nilai harusandroid:src
, tidakimageResource
:@BindingAdapter("android:src")
. Terima kasih!<ImageView imageResource="@{recipe.imageResource}" />
dan@BindingAdapter("imageResource")
. Saya baru saja melewatkanimageResource="@{recipe.imageResource}"
bagian dari potongan kode Anda :)app:imageResource
?Tidak perlu adat
BindingAdapter
sama sekali. Gunakan sajaapp:imageResource="@{yourResId}"
dan itu akan bekerja dengan baik.
Periksa ini untuk mengetahui cara kerjanya.
sumber
ImageView
kelas dan mengikutisetImageResource
metode, tampaknya akhirnya diselesaikanresolveUri
dan jika tidak ada validasi nol. Jadi itu akan berhasil karenaInt
saya bertanya-tanya apa yang bisa terjadi jikaInt?
. Ketika binding dijalankan, sebagai contoh jika sesuatu memanggilexecutePendingBindings
maka tidak nullable secara default menjadi nol, nullables menjadi null.menetapkan:
@BindingAdapter({"android:src"}) public static void setImageViewResource(ImageView imageView, int resource) { imageView.setImageResource(resource); }
menggunakan:
<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}"/>
sumber
Jangan pernah mengganti atribut SDK standar saat Anda membuatnya sendiri
@BindingAdapter
!Ini bukan pendekatan yang baik karena banyak alasan seperti: ini akan mencegah perolehan manfaat dari perbaikan baru pada pembaruan SDK Android pada atribut itu. Juga mungkin membingungkan pengembang dan pasti rumit untuk digunakan kembali (karena tidak diharapkan diganti)
Anda dapat menggunakan namespace yang berbeda seperti:
custom:src="@{recipe.imageResource}"
atau
mybind:src="@{recipe.imageResource}"
------ mulai Pembaruan 2. Juli 2018
Namespace tidak disarankan untuk digunakan, jadi lebih baik mengandalkan awalan atau nama yang berbeda seperti:
app:custom_src="@{recipe.imageResource}"
atau
app:customSrc="@{recipe.imageResource}"
------ akhiri Pembaruan 2. Juli 2018
Namun, saya akan merekomendasikan solusi yang berbeda sebagai:
android:src="@{ContextCompat.getDrawable(context, recipe.imageResource)}"
tampilan konteks selalu tersedia di dalam ekspresi binding
@{ ... }
sumber
Berdasarkan jawaban dari Maher Abuthraa, inilah yang akhirnya saya gunakan dalam XML:
android:src="@{context.getDrawable(recipe.imageResource)}"
The
context
variabel tersedia dalam mengikat ekspresi tanpa impor apapun. Juga, tidakBindingAdapter
perlu kebiasaan . Hanya peringatan: metodegetDrawable
ini hanya tersedia sejak API 21.sumber
Untuk Kotlin, letakkan ini ke file utils tingkat atas, tidak diperlukan konteks statis / pengiring:
@BindingAdapter("android:src") fun setImageViewResource(view: ImageView, resId : Int) { view.setImageResource(resId) }
sumber
Semakin banyak yang dapat Anda lakukan
DataBindingAdapter
Tetapkan salah satu dari jenis ini:
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`}"
Setel Gambar kesalahan / Gambar placeholder
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`}" />
Menguji semua tipe
Sehingga menjadi mungkin dengan adaptor pengikat tunggal. Cukup salin proyek metode ini.
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); } }
Alasan saya menggunakan Glide untuk memuat semua objek
Jika Anda bertanya mengapa saya menggunakan Glide untuk memuat id drawable / resource, sebagai gantinya saya dapat menggunakan
imageView.setImageBitmap();
atauimageView.setImageResource();
. Jadi alasannya adalah ituJika Anda menggunakan Piccaso, Fresso atau pustaka pemuatan gambar lainnya, Anda dapat membuat perubahan
loadImageWithGlide
metode .sumber
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}"/>
sumber
Anda dapat melakukan hal berikut
android:src="@{expand?@drawable/ic_collapse:@drawable/ic_expand}"
sumber
Saya bukan ahli di Android tetapi saya menghabiskan waktu berjam-jam mencoba menguraikan solusi yang ada. Hal baiknya adalah saya memahami seluruh gagasan tentang data binding menggunakan
BindingAdapter
sedikit lebih baik. Untuk itu, saya setidaknya berterima kasih atas jawaban yang ada (meski sangat tidak lengkap). Berikut rincian lengkap dari pendekatan tersebut:Saya juga akan menggunakan
BindingAdapter
dalam contoh ini. Mempersiapkanxml
:<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>
Jadi di sini saya hanya menyimpan yang penting:
SomeViewModel
adalah saya yangViewModel
saya gunakan untuk pengikatan data. Anda juga dapat menggunakan kelas yang diperluasBaseObservable
dan digunakan@Bindable
. Namun,BindingAdapter
dalam contoh ini, tidak harus berada di kelasViewModel
atauBaseObservable
! Kelas biasa sudah cukup! Ini akan diilustrasikan nanti.app:appIconDrawable="@{model.packageName}"
. Ya ... ini benar-benar membuatku pusing! Mari kita hancurkan:app:appIconDrawable
: Ini bisa apa saja:app:iCanBeAnything
! Betulkah. Anda juga bisa menyimpannya"android:src"
! Namun, perhatikan pilihan Anda, kami akan menggunakannya nanti!Mari kita asumsikan kita menggunakan kelas Observable sederhana ini:
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)); } }
Seperti yang dijanjikan, Anda juga dapat memindahkan
public static void setImageViewDrawable()
, ke kelas lain, misalnya mungkin Anda dapat memiliki kelas yang memiliki koleksiBindingAdapters
:public class BindingAdapterCollection { @BindingAdapter({"appIconDrawable"}) public static void setImageViewDrawable(ImageView imageView, String packageName) { imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName)); } }
Komentar penting lainnya adalah bahwa di
Observable
kelas saya, saya biasaString packageName
memberikan info tambahan kesetImageViewDrawable
. Anda juga dapat memilih misalnyaint resourceId
, dengan getter / setter yang sesuai, yang adaptornya menjadi: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); } }
sumber
Ini bekerja untuk saya. saya akan menambahkannya ke jawaban @hqzxzwb sebagai komentar tetapi karena batasan reputasi.
Saya memiliki ini dalam Model pandangan saya
var passport = R.drawable.passport
Kemudian di xml saya, saya punya
android:src="@{context.getDrawable(model.passort)}"
Dan hanya itu
sumber
Menggunakan Fresco (perpustakaan gambar 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)); } } }
sumber
Dalam status tampilan atau kelas model tampilan Anda;
fun getSource(context: Context): Drawable? { return ContextCompat.getDrawable(context, R.drawable.your_source) }
Dalam XML Anda;
<androidx.appcompat.widget.AppCompatImageButton . . . android:src="@{viewState.getSource(context)}"
sumber
<?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>
sumber
atur gambar seperti ini,
<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" />
sumber