νλ‘κ·Έλλ°μ μΌλ‘κ° μλ μ μΈμ νμμ μ¬μ©νμ¬ μ±μ λ°μ΄ν° μμ€μ λ μ΄μμ UI μ»΄ν¬λνΈλ₯Ό λ°μΈλ©ν μ μλλ‘ νμ©νλ λΌμ΄λΈλ¬λ¦¬.
λ μ΄μμμ μ’ μ’ μ‘ν°λΉν°μμ UI νλ μμν¬ λ©μλλ₯Ό νΈμΆνλ μ½λμ ν¨κ» μ μλ¨.
findViewById<TextView>(R.id.sample_text).apply {
text = viewModel.userName
}
νμ§λ§ Data Binding λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ λ μ΄μμ νμΌμμ μμ ―μ μ§μ ν μ€νΈλ₯Ό ν λΉν μ μμ.
<TextView
android:text="@{viewmodel.userName}" />
λ μ΄μμ νμΌμμ μ»΄ν¬λνΈλ₯Ό λ°μΈλ©νλ©΄ μ‘ν°λΉν°μμ λ§μ UI νλ μμν¬ νΈμΆμ μ κ±°νμ¬ μ‘ν°λΉν°λ₯Ό λ κ°λ¨νκ³ μ μ§ κ΄λ¦¬νκΈ° μ½κ² λ§λ€ μ μμ.
π μ±μ μ±λ₯μ ν₯μμν€κ³ λ©λͺ¨λ¦¬ λμμ λ ν¬μΈν° μμΈλ₯Ό λ°©μ§.
μ± λͺ¨λμ build.gradle νμΌμμ dataBinding λΉλ μ΅μ νμ±ν.
android {
...
buildFeatures {
dataBinding true
}
}
ννμ μΈμ΄λ₯Ό μ¬μ©νλ©΄ λ³μλ₯Ό λ μ΄μμμ λ·°μ μ°κ²°νλ ννμμ μμ±ν μ μμ.
λ°μ΄ν° λ°μΈλ© λΌμ΄λΈλ¬λ¦¬λ λ μ΄μμ λ·°λ₯Ό λ°μ΄ν° κ°μ²΄μ μλμΌλ‘ μ°κ²°νκΈ° μν΄ νμν ν΄λμ€λ₯Ό μλμΌλ‘ μμ±ν¨. λΌμ΄λΈλ¬λ¦¬λ λ μ΄μμμμ μ¬μ©ν μ μλ imports, variables λ° includes κ°μ κΈ°λ₯ μ 곡.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewmodel"
type="com.myapp.data.ViewModel" />
</data>
<ConstraintLayout... /> <!-- UI layout's root element -->
</layout>
λ°μ΄ν° λ°μΈλ© λ μ΄μμ νμΌμ layout λ£¨νΈ νκ·Έλ‘ μμνλ©°, data elementμ view root elementκ° μ΄μ΄μ μμ±λ¨. view elementλ μΌλ° λ μ΄μμ νμΌκ³Ό λμΌνκ² μμ±.
μμ μ½λ)
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/> <!-- λ μ΄μμ λ΄μμ μ¬μ©ν μ μλ μμ± μ€λͺ
-->
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
λ μ΄μμ λ΄μμμ ννμμ @{} ꡬ문μ μ¬μ©νμ¬ μμ± νλ‘νΌν°μ μμ±λ¨.
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}" />
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
binding.user = User("Test", "User") //λ°νμ μ UIμ Test userλ₯Ό νμ
}
κ° λ μ΄μμ νμΌμ λν΄ λ°μΈλ© ν΄λμ€κ° μμ±λ¨. κΈ°λ³Έμ μΌλ‘ ν΄λμ€ μ΄λ¦μ λ μ΄μμ νμΌμ μ΄λ¦μ νμ€μΉΌ νκΈ°λ²μΌλ‘ λ³νν κ²μ΄λ©° μ¬κΈ°μ Binding μ λ―Έμ¬κ° μΆκ°λ¨.(λ·° λ°μΈλ©κ³Ό λμΌ)
LayoutInflaterλ₯Ό μ¬μ©νμ¬ λ·°λ₯Ό κ°μ Έμ¬ μλ μμ.
val binding: ActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater())
Fragment, ListView λλ RecyclerView μ΄λν° λ΄μμ λ°μ΄ν° λ°μΈλ© νλͺ©μ μ¬μ©νλ κ²½μ°, λ°μΈλ© ν΄λμ€ λλ DataBindingUtil ν΄λμ€μ inflate() λ©μλλ₯Ό μ¬μ©ν μ μμ.
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)
// or
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
λ€μ μ°μ°μλ₯Ό ννμ μΈμ΄μμ μ¬μ©ν μ μμ.
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
λ λ³ν© μ°μ°μ (??
)λ μΌμͺ½ νΌμ°μ°μκ° nullμ΄ μλ κ²½μ° μΌμͺ½μ μ ννκ³ , μΌμͺ½μ΄ nullμΈ κ²½μ° μ€λ₯Έμͺ½μ μ νν¨.
android:text="@{user.displayName ?? user.lastName}"
<!--μλ μ½λμ λμΌν μ½λμ-->
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
ννμμ νλ, κ²ν°, ObservableField κ°μ²΄μ λν΄ λμΌν νμμ μ¬μ©νμ¬ ν΄λμ€ λ΄ μμ±μ μ°Έμ‘°ν μ μμ.
android:text="@{user.lastName}"
λ€μ ꡬ문μ μ¬μ©νμ¬ λ μ΄μμ λ΄μ λ€λ₯Έ λ·°λ₯Ό IDλ‘ μ°Έμ‘°ν μ μμ.
β λ°μΈλ© ν΄λμ€λ IDλ₯Ό μΉ΄λ© μΌμ΄μ€λ‘ λ³ν.
android:text="@{exampleText.text}"
<EditText
android:id="@+id/example_text"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
<TextView
android:id="@+id/example_output"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{exampleText.text}"/>
λ°°μ΄, 리μ€νΈ, ν¬μ 리μ€νΈ λ° λ§΅κ³Ό κ°μ μΌλ° 컬λ μ μ [] μ°μ°μλ₯Ό μ¬μ©νμ¬ νΈνκ² μ κ·Ό κ°λ₯.
<data>
<import type="android.util.SparseArray"/>
<import type="java.util.Map"/>
<import type="java.util.List"/>
<variable name="list" type="List<String>"/>
<variable name="sparse" type="SparseArray<String>"/>
<variable name="map" type="Map<String, String>"/>
<variable name="index" type="int"/>
<variable name="key" type="String"/>
</data>
...
android:text="@{list[index]}"
...
android:text="@{sparse[index]}"
...
android:text="@{map[key]}"
β xml λ¬Έλ²μ μ¬λ°λ₯΄κ² μμ±νκΈ° μν΄ < λ¬Έμλ₯Ό μ΄μ€μΌμ΄νν΄μΌ ν¨. List<String>
λμ List<String>
μ κ°μ΄ μμ±. 맡μμ κ°μ μ°Έμ‘°ν λ object.key νκΈ°λ² μ¬μ© κ°λ₯.
μλ₯Ό λ€μ΄ @{map[key]}
λ₯Ό @{map.key}
λ‘ λ체
λ°μ΄ν° λ°μΈλ©μ μ¬μ©νλ©΄ λ·°μμ μ λ¬λλ μ΄λ²€νΈλ₯Ό μ²λ¦¬νλ ννμμΌλ‘ μμ±ν μ μμ.
π‘ μ΄λ²€νΈ μ²λ¦¬λ₯Ό μν λ κ°μ§ λ©μ»€λμ¦
Method references
ννμμ΄ λ©μλ μ°Έμ‘°λ‘ μ€νλλ©΄ λ°μ΄ν° λ°μΈλ©μ λ©μλ μ°Έμ‘°μ μμ μ κ°μ²΄λ₯Ό 리μ€λμ λννκ³ ν΄λΉ 리μ€λλ₯Ό λμ λ·°μ μ€μ ν¨.
ννμμ΄ nullλ‘ νκ°λλ©΄ λ°μ΄ν° λ°μΈλ©μ 리μ€λλ₯Ό μμ±νμ§ μκ³ null 리μ€λλ₯Ό μ€μ ν¨.
Listener bindings
μ΄λ²€νΈ λ°μ μμ μ€νλλ λλ€ ννμ. λ°μ΄ν° λ°μΈλ©μ νμ 리μ€λλ₯Ό μμ±νκ³ ν΄λΉ 리μ€λλ₯Ό λ·°μ μ€μ ν¨. μ΄λ²€νΈκ° λ°μνλ©΄ 리μ€λκ° λλ€ ννμμ μ€νν¨.
μ΄λ²€νΈλ₯Ό νΈλ€λ¬ λ©μλμ μ§μ λ°μΈλ©ν μ μμΌλ©° μ΄λ μ‘ν°λΉν°μμ android.onClick λ©μλμ ν λΉνλ λ°©μκ³Ό μ μ¬.
Viewμ onClick μμ±κ³Ό λΉκ΅νμ λμ μ₯μ μ ννμμ΄ μ»΄νμΌ μκ°μ μ²λ¦¬λλ€λ κ².
λ©μλκ° μ‘΄μ¬νμ§ μκ±°λ μκ·Έλμ²κ° μλͺ»λ κ²½μ° μ»΄νμΌ νμ μ€λ₯κ° λ°μν¨.
class MyHandlers {
fun onClickFriend(view: View) { ... }
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="handlers" type="com.example.MyHandlers"/>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:onClick="@{handlers::onClickFriend}"/> <!--λ©μλ μκ·Έλμ²μ μ νν μΌμΉν΄μΌ ν¨-->
</LinearLayout>
</layout>
μ΄λ²€νΈκ° λ°μν λ μ€νλλ λ°μΈλ© ννμ. λ©μλ μ°Έμ‘°μ μ μ¬νμ§λ§ μμμ λ°μ΄ν° λ°μΈλ© ννμ μ€ν κ°λ₯. (Android Gradle νλ¬κ·ΈμΈ λ²μ 2.0 μ΄μμμ μ¬μ© κ°λ₯.)
Method referenceμμλ λ©μλμ 맀κ°λ³μκ° μ΄λ²€νΈ 리μ€λμ λ§€κ° λ³μμ μΌμΉν΄μΌ ν¨. (λ©μλ μκ·Έλμ²κ° μ νν μΌμΉν΄μΌ ν¨)
리μ€λ λ°μΈλ©μμλ voidλ₯Ό κΈ°λνλ κ²½μ°λ₯Ό μ μΈνκ³ λ λ°ν κ°λ§ 리μ€λμ κΈ°λ λ°ν κ°κ³Ό μΌμΉνλ©΄ λ¨.
class Presenter {
fun onSaveClick(task: Task){}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="task" type="com.android.example.Task" />
<variable name="presenter" type="com.android.example.Presenter" />
</data>
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
<Button android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onClick="@{() -> presenter.onSaveClick(task)}" />
</LinearLayout>
</layout>
μ½λ°±μ΄ ννμμμ μ¬μ©λ λ λ°μ΄ν° λ°μΈλ©μ νμν 리μ€λλ₯Ό μλμΌλ‘ μμ±νκ³ ν΄λΉ μ΄λ²€νΈμ λ±λ‘ν¨.
λ·°κ° μ΄λ²€νΈλ₯Ό λ°μμν€λ©΄ λ°μ΄ν° λ°μΈλ©μ μ£Όμ΄μ§ ννμμ μ€νν¨. μ΄ λ 리μ€λ ννμμ΄ μ€νλλ λμ λ°μ΄ν° λ°μΈλ©μ null λ° μ€λ λ μμ μ±μ μ 곡λ°μ.
μμ μ½λλ₯Ό μλμ κ°μ΄ μμ± κ°λ₯.
android:onClick="@{(view) -> presenter.onSaveClick(task)}" <!--onClick(View)μ μ λ¬λλ 맀κ°λ³μλ₯Ό λͺ
λͺ
ν κ². 무μνκ±°λ λͺ¨λ λͺ
λͺ
ν μ μμ.-->
μλμ κ°μ΄ μ¬μ© κ°λ₯.
class Presenter {
fun onSaveClick(view: View, task: Task){}
}
android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
νλλ³΄λ€ λ§μ 맀κ°λ³μλ₯Ό κ°μ§ λλ€μ μ¬μ© κ°λ₯.
class Presenter {
fun onCompletedChanged(task: Task, completed: Boolean){}
}
<CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
μ΄λ²€νΈκ° voidκ° μλ λ°νκ°μ κ°μ§ κ²½μ° ννμμ λμΌν μ νμ λ°ν κ°μ λ°νν΄μΌ ν¨.
class Presenter {
fun onLongClick(view: View, task: Task): Boolean { }
}
android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}"
ννμμ΄ null κ°μ²΄λ‘ μΈν΄ μ€νν μ μλ κ²½μ° κΈ°λ³Έκ°μ λ°νν μ μμ.
μΌνμμ μ¬μ©ν΄μΌ νλ κ²½μ° voidλ₯Ό κΈ°νΈλ‘ μ¬μ©ν μ μμ.
android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"
리μ€λ ννμμ μ½λλ₯Ό μ½κΈ° μ½κ² λ§λ€ μ μμ. κ·Έλ¬λ 볡μ‘ν ννμμ ν¬ν¨νλ 리μ€λλ λ μ΄μμμ μ½κ³ μ μ§νκΈ° νλ€κ² λ§λ¦. ννμμ κ°λ₯ν ν κ°λ¨νκ² μ μ§νκ³ UIμμ μ¬μ© κ°λ₯ν λ°μ΄ν°λ₯Ό μ½λ°± λ©μλλ‘ μ λ¬. 리μ€λ ννμμμ νΈμΆνλ μ½λ°± λ©μλ λ΄μμ λΉμ¦λμ€ λ‘μ§ κ΅¬ν.
Importsλ₯Ό μ¬μ©νλ©΄ λ μ΄μμ νμΌ λ΄μμ ν΄λμ€λ₯Ό μ°Έμ‘°ν μ μμ.
data μμ λ΄μμ import μμλ₯Ό 0κ° μ΄μ μ¬μ©ν μ μμ.
<data>
<import type="android.view.View"/>
</data>
View ν΄λμ€λ₯Ό κ°μ Έμ€λ©΄ λ°μΈλ© ννμμμ ν΄λΉ ν΄λμ€λ₯Ό μ°Έμ‘° ν μ μμ.
<TextView
android:text="@{user.lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
<import type="android.view.View"/>
<import type="com.example.real.estate.View"
alias="Vista"/> <!-- λ³μΉμΌλ‘ λ°κΏ -->
<data>
<import type="com.example.User"/>
<import type="java.util.List"/>
<variable name="user" type="User"/>
<variable name="userList" type="List<User>"/>
</data>
μΊμ€ν μλ μ¬μ© κ°λ₯.
<TextView
android:text="@{((User)(user.connection)).lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
μ μ νλμ λ©μλλ₯Ό μ°Έμ‘°ν λλ importλ μ ν μ¬μ© κ°λ₯.
<data>
<import type="com.example.MyStringUtils"/>
<variable name="user" type="com.example.User"/>
</data>
β¦
<TextView
android:text="@{MyStringUtils.capitalize(user.lastName)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
data element λ΄μμ μ¬λ¬ variable element μ¬μ© κ°λ₯.
κ° variable μμλ λ μ΄μμμ μ€μ ν μ μλ μμ±μ μ€λͺ
νλ©°, λ μ΄μμ νμΌ λ΄μ λ°μΈλ© ννμμμ μ¬μ©λ¨.
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="user" type="com.example.User"/>
<variable name="image" type="Drawable"/>
<variable name="note" type="String"/>
</data>
variable μ νμ μ»΄νμΌ νμμ κ²μ¬λ¨. λ³μκ° Observableμ ꡬννκ±°λ Observable 컬λ μ μΈ κ²½μ° κ·Έ μ¬νμ΄ typeμ λ°μλμ΄μΌ ν¨.
λ€μν ꡬμ±(κ°λ‘λͺ¨λ νΉμ μΈλ‘λͺ¨λ)μ λ μ΄μμ νμΌμ΄ μλ‘ λ€λ₯Ό λ λ³μκ° κ²°ν©λ¨. μ΄λ¬ν λ μ΄μμ νμΌ κ° μΆ©λνλ λ³μ μ μκ° μμ΄μλ μλ¨.
μμ±λ λ°μΈλ© ν΄λμ€μλ κ° λ³μμ λν΄ getterμ setterκ° μμ. setterκ° νΈμΆλ λκΉμ§ λ³μλ κΈ°λ³Έκ°μ μ¬μ©.(μ°Έμ‘° μ νμ null, intλ 0, booleanμ false)
app λ€μ μ€νμ΄μ€μ μμ±μμ λ³μ μ΄λ¦μ μ¬μ©νμ¬ ν¬ν¨λ λ μ΄μμμ λ°μΈλ©μ λ³μλ₯Ό μ λ¬ν μ μμ.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/name"
bind:user="@{user}"/>
<include layout="@layout/contact"
bind:user="@{user}"/>
</LinearLayout>
</layout>
μμ μ½λ2)
<!--layout_name.xml-->
<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="user"
type="com.example.User" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Other views and UI elements specific to layout_name.xml -->
<!-- Include the contact_info.xml layout -->
<include
layout="@layout/contact_info"
bind:user="@{user}" />
</RelativeLayout>
</layout>
<!-- contact_info.xml -->
<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="user"
type="com.example.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Include user-specific data from the variable -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.email}" />
</LinearLayout>
</layout>
λ°μ΄ν° λ°μΈλ©μ includeλ₯Ό μ§μ μμμΌλ‘ μ¬μ©νλ merge μμλ₯Ό μ§μνμ§ μμ.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="user" type="com.example.User"/>
</data>
<merge><!-- Doesn't work -->
<include layout="@layout/name"
bind:user="@{user}"/>
<include layout="@layout/contact"
bind:user="@{user}"/>
</merge>
</layout>