2016-01-14 2 views
27

Die diskutiert Bindungswerte innerhalb einer Aktivität oder eines Fragments, aber gibt es eine Möglichkeit, Datenbindung mit einer benutzerdefinierten Ansicht durchzuführen?Androide Datenbindung mit einer benutzerdefinierten Ansicht

würde Ich mag, wie etwas zu tun ist:

<LinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <com.mypath.MyCustomView 
     android:id="@+id/my_view" 
     android:layout_width="match_parent" 
     android:layout_height="40dp"/> 

</LinearLayout> 

mit my_custom_view.xml:

<layout> 

<data> 
    <variable 
     name="myViewModel" 
     type="com.mypath.MyViewModelObject" /> 
</data> 

<LinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="@{myViewModel.myText}" /> 

</LinearLayout> 

</layout> 

Während es möglich erscheint diesen Brauch durch das Setzen zu tun Attribute auf der benutzerdefinierten Ansicht, dies würde schnell lästig werden wenn es viele zu bindende Werte gibt.

Gibt es einen guten Weg, um das zu erreichen, was ich versuche?

+0

Haben Sie versucht, die Daten in Ihrer MyCustomView Klasse Bindung nach der custome Ansicht Aufblasen? –

+0

Ich habe ein paar Dinge versucht, um dies zu erreichen, aber die Bindungsfunktionen scheinen Informationen zu benötigen, die in einer Aktivität oder einem Fragment enthalten sind. Ihre Beispiele gaben kein Beispiel dafür, wie dies in einer benutzerdefinierten Ansicht erreicht werden kann. Ein kurzes Code-Snippet, um dies zu erreichen, wäre sehr willkommen. – Dave

+0

FYI: Ich denke, XML-Layout-Dateien werden per Konvention mit Unterstrich-Notation benannt. –

Antwort

31

in Ihrer benutzerdefinierten Ansicht, aufblasen Layout jedoch gewohnt und einen Setter für die Sie festlegen möchten Attribut bieten:

<layout xmlns...> 
    <data> 
     <variable 
      name="myViewModel" 
      type="com.mypath.MyViewModelObject" /> 
    </data> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     <com.mypath.MyCustomView 
      android:id="@+id/my_view" 
      app:myViewModel="@{myViewModel}" 
      android:layout_width="match_parent" 
      android:layout_height="40dp"/> 

    </LinearLayout> 
</layout> 

:

Sie verwenden es
private MyCustomViewBinding mBinding; 
public MyCustomView(...) { 
    ... 
    LayoutInflater inflater = (LayoutInflater) 
     context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    mBinding = MyCustomViewBinding.inflate(inflater); 
} 

public void setMyViewModel(MyViewModelObject obj) { 
    mBinding.setMyViewModel(obj); 
} 

dann im Layout Im obigen Beispiel wird ein automatisches Bindungsattribut für app: myViewModel erstellt, da ein Setter mit dem Namen setMyViewModel vorhanden ist.

+0

Vielen Dank! Ein Teil des Kampfes, den ich hatte, war von Android Studio, dessen Cache ungültig gemacht werden musste, und das Projekt wurde mehrmals neu erstellt, um Zwischendateien loszuwerden und neue Bindungsdateien zu erzeugen. Es war schwer zu wissen, was mit all dem Rot schief lief. – Dave

+1

Wo wird der Typ 'MyCustomViewBinding' erstellt? –

+0

MyCustomViewBinding wird über einen Annotationsprozessor als Teil des Datenbindungsframeworks generiert. Die XML-Datei (Dave verwendete MyCustomView.xml, aber er meinte wirklich meine_Kunden_Version.xml, da Groß-/Kleinschreibung für Ressourcendateien in Groß- und Kleinschreibung sein sollte) verursacht einen Standard-Binding-Klassennamen von MyCustomViewBinding (camel cased, suffixed with Binding). Sie können auch den Namen der Binding-Klasse anpassen: http://developer.android.com/tools/data-binding/guide.html#custom_binding_class_names –

4

Zuerst tun Sie dies nicht, wenn diese benutzerdefinierte Ansicht bereits <include> in einem anderen Layout ist, z. B. Aktivität usw. Sie erhalten nur eine Ausnahme über das Tag als unerwarteten Wert. Die Datenbindung hat bereits die Bindung daran geknüpft, also bist du eingestellt.

Haben Sie versucht, onFinishInflate zu verwenden, um die Bindung auszuführen? (Kotlin Beispiel)

override fun onFinishInflate() { 
    super.onFinishInflate() 
    this.dataBinding = MyCustomBinding.bind(this) 
} 

Beachten Sie, dass, wenn Sie die Bindung Ihrer Ansicht verwenden, wird es nicht möglich sein, programmatisch erstellt werden, zumindest wäre es sehr gewunden sein, sowohl selbst zu unterstützen, wenn Sie können.

1

Following the solution presented by george Der grafische Editor in Android Studio war nicht mehr in der Lage, die benutzerdefinierte Ansicht zu rendern. Der Grund dafür ist, dass keine Ansicht tatsächlich in dem folgenden Code aufgeblasen wird:

public MyCustomView(...) { 
    ... 
    LayoutInflater inflater = (LayoutInflater) 
     context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    mBinding = MyCustomViewBinding.inflate(inflater); 
} 

Ich nehme an, dass die Bindung die Inflation behandelt, aber der grafische Editor hat es nicht gefallen.

In meinem speziellen Anwendungsfall wollte ich ein einzelnes Feld und nicht ein komplettes Ansichtsmodell binden. Ich kam (kamlin ankommend):

class LikeButton @JvmOverloads constructor(
     context: Context, 
     attrs: AttributeSet? = null, 
     defStyleAttr: Int = 0 
) : ConstraintLayout(context, attrs, defStyleAttr) { 

    val layout: ConstraintLayout = LayoutInflater.from(context).inflate(R.layout.like_button, this, true) as ConstraintLayout 

    var numberOfLikes: Int = 0 
     set(value) { 
      field = value 
      layout.number_of_likes_tv.text = numberOfLikes.toString() 
     } 
} 

Der ähnliche Knopf besteht aus einer Bild- und einer Textansicht. Die Textansicht enthält die Anzahl der Likes, die ich per Datenbindung einstellen möchte.

den Setter für numberOfLikes als Attribut in der folgenden XML Durch die Verwendung von Bindungsdaten macht automatisch den Verein:

<views.LikeButton 
    android:id="@+id/like_btn" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    app:numberOfLikes="@{story.numberOfLikes}" /> 

Weiterführende Literatur: https://medium.com/google-developers/android-data-binding-custom-setters-55a25a7aea47

0

Basierend auf, was Sie tun, habe ich versucht zu tun MyCustomBinding.bind(this) und das hat nicht mehr für mich gearbeitet.Die Bindung hat bereits stattgefunden, aber was wir stattdessen tun, ist es zu finden.

private MyCustomBinding binding; 

@Override 
protected void onAttachedToWindow() { 
    super.onAttachedToWindow(); 

    binding = DataBindingUtil.getBinding(this); //got the binding! 
    MyViewModelObject model = MyViewModelObject.get("myText"); 

    binding.setVariable(BR.myViewModel, model); 
}