Установите идентификатор ресурса в android: src для ImageView с использованием привязки данных в Android
Я пытаюсь установить идентификатор ресурса ресурса для android: src ImageView с использованием привязки данных
Вот мой объект:
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);
}
Ответы
Ответ 1
Ответа на этот вопрос от 10 ноября 2016
Комментарий 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 найдет его неважно (я полагаю)
Ответ 2
определить:
@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, [email protected]/guide_1}"/>
Ответ 3
Никогда не переопределяйте стандартные атрибуты SDK, когда создаете свой собственный @BindingAdapter
!
Это не очень хороший подход по многим причинам, таким как: он предотвратит получение преимуществ от новых исправлений в обновлении Android SDK для этого атрибута. Кроме того, это может сбить с толку разработчиков и, конечно, сложно использовать повторно (потому что его нельзя перезаписать).
Вы можете использовать другое пространство имен, например:
custom:src="@{recipe.imageResource}"
или же
mybind:src="@{recipe.imageResource}"
------ начать обновление 2.июл .198
Пространство имен не рекомендуется использовать, поэтому лучше использовать префикс или другое имя, например:
app:custom_src="@{recipe.imageResource}"
или же
app:customSrc="@{recipe.imageResource}"
------ конец Обновление 2. июл .2018
Тем не менее, я бы порекомендовал другое решение, как:
android:src="@{ContextCompat.getDrawable(context, recipe.imageResource)}"
контекстное представление всегда доступно внутри выражения привязки @{... }
Ответ 4
Для Kotlin поместите это в файл utils верхнего уровня, не требуется статический/вспомогательный контекст:
@BindingAdapter("android:src")
fun setImageViewResource(view: ImageView, resId : Int) {
view.setImageResource(resId)
}
Ответ 5
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}"/>
Ответ 6
Чем больше вы можете сделать с 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'}"
/>
Проверено все типы
![SC]()
Так что это становится возможным с одним адаптером привязки. Просто скопируйте этот метод проекта.
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 для загрузки всех объектов
Если вы спросите меня, почему я использовал Glide для загрузки drawable/идентификатора ресурса, я мог бы использовать imageView.setImageBitmap();
или imageView.setImageResource();
, Так что причина в том, что
- Glide - это эффективный фреймворк для загрузки изображений, который охватывает декодирование медиа, память и кеширование диска. Так что вам не нужно беспокоиться о больших размерах изображений и кэше.
- Для обеспечения согласованности при загрузке изображения. Теперь все типы ресурсов изображений загружаются Glide.
Если вы используете Piccaso, Fresso или любую другую библиотеку загрузки изображений, вы можете внести изменения в метод loadImageWithGlide
.
Ответ 7
Вы можете сделать следующее
android:src="@{[email protected]/ic_collapse:@drawable/ic_expand}"
Ответ 8
Использование Fresco (библиотека изображений 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));
}
}
}
Ответ 9
Я не эксперт по 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"
! Тем не менее, сделайте заметку на ваш выбор, мы будем использовать ее позже!
- "@{model.packageName}": если вы работали с привязкой данных, это знакомо. Я покажу, как это используется позже.
Предположим, мы используем этот простой класс 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 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 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
с соответствующими геттерами/сеттерами, для которых адаптер становится:
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);
}
}
Ответ 10
В вашем состоянии просмотра или классе модели представления;
fun getSource(context: Context): Drawable? {
return ContextCompat.getDrawable(context, R.drawable.your_source)
}
в вашем XML;
<androidx.appcompat.widget.AppCompatImageButton
.
.
.
android:src="@{viewState.getSource(context)}"