Ich bin kein Experte für Android, aber ich habe stundenlang versucht, die vorhandenen Lösungen zu entschlüsseln. Das Gute ist, dass ich die ganze Idee der Datenbindung mit verstanden habeBindingAdapter
etwas besser verstanden habe. Dafür bin ich zumindest dankbar für die vorhandenen Antworten (obwohl stark unvollständig). Hier eine vollständige Aufschlüsselung des Ansatzes:
Ich werde das auch BindingAdapter
in diesem Beispiel verwenden. Vorbereiten der 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>
Also behalte ich hier nur das Wichtige:
SomeViewModel
ist mein ViewModel
ich benutze für die Datenbindung. Sie können auch eine Klasse verwenden, die erweitert BaseObservable
und verwendet wird @Bindable
. Das BindingAdapter
in diesem Beispiel muss jedoch nicht in einer ViewModel
oder BaseObservable
Klasse sein! Eine einfache Klasse wird es tun! Dies wird später veranschaulicht.
app:appIconDrawable="@{model.packageName}"
. Ja ... das hat mir wirklich Kopfschmerzen bereitet! Lassen Sie es uns zusammenfassen:
app:appIconDrawable
: Das kann alles sein : app:iCanBeAnything
! Ja wirklich. Sie können auch behalten "android:src"
! Notieren Sie sich jedoch Ihre Wahl, wir werden sie später verwenden!
- "@ {model.packageName}": Wenn Sie mit Datenbindung gearbeitet haben , ist dies bekannt. Ich werde später zeigen, wie dies verwendet wird.
Nehmen wir an, wir verwenden diese einfache Observable-Klasse:
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));
}
}
Wie versprochen können Sie die public static void setImageViewDrawable()
Klasse auch in eine andere Klasse verschieben, z. B. können Sie eine Klasse mit einer Sammlung von BindingAdapters
:
public class BindingAdapterCollection {
@BindingAdapter({"appIconDrawable"})
public static void setImageViewDrawable(ImageView imageView, String packageName) {
imageView.setImageDrawable(Tools.getAppIconDrawable(imageView.getContext(), packageName));
}
}
Eine weitere wichtige Bemerkung ist, dass ich in meiner Observable
Klasse String packageName
zusätzliche Informationen an die weitergegeben habe setImageViewDrawable
. Sie können beispielsweise int resourceId
auch mit den entsprechenden Gettern / Setzern auswählen , für die der Adapter wird:
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);
}
}
@BindingAdapter
. Wert sollte aberandroid:src
nicht seinimageResource
:@BindingAdapter("android:src")
. Danke dir!