Я не эксперт в 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}"
. Yes... this was really causing me headaches! Let's break it down:
app:appIconDrawable
: This can be anything: app:iCanBeAnything
! Really. You can also keep "android:src"
! However, take a note on your choice, we will use it later!
- "@{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'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));
}
}
Как и было обещано, вы также можете переместить 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);
}
}
person
Tanasis
schedule
23.11.2018