Reputation: 123
I am trying to bind the following elements:
xml:
<android.support.v7.widget.SwitchCompat
...
bind:onCheckedChanged="@{(isChecked) -> viewModel.onCheckedChanged(isChecked)}"
.../>
viewModel:
class MyViewModel() {
fun onCheckedChanged(isChecked: Boolean) {
...
}
}
using a BindingAdapter:
@BindingAdapter("onCheckedChanged")
fun bindOnCheckedChanged(view: SwitchCompat, onCheckedChanged: (Boolean) -> Unit) {
view.setOnCheckedChangeListener(
{ _, isChecked ->
if (view.isPressed) onCheckedChanged(isChecked)
}
)
}
The error I get is this one:
data binding error ****msg:cannot find method onCheckedChanged(java.lang.Object) in class MyViewModel
It seems that the data binder does not recognize isChecked
as a Boolean
. I tried to force the typing in the xml like isChecked:Boolean
but I get a bunch of different errors.
Right now I made it work by using Any
instead of Boolean
but I feel like it's wrong:
@BindingAdapter("onCheckedChanged")
fun bindOnCheckedChanged(view: SwitchCompat, onCheckedChanged: (Any) -> Unit) {
...
and
fun onCheckedChanged(isChecked: Any) {
val isSwitchChecked = isChecked as? Boolean ?: return
...
Does anyone know how to make it work the correct function signature?
Upvotes: 5
Views: 1148
Reputation: 1377
Use lambda with parameters
1️⃣ ➖ Lambda implementation:
MainActivity.kt
val lambda: (TextView?) -> Unit = {
Log.i(TAG, "lambda: ${it?.text}")
}
2️⃣ ➖ BindingAdapter implementation:
Bindings.kt
@BindingAdapter("lambda")
fun View.lambda(block: (TextView?) -> Unit) {
// Your logic
}
3️⃣ ➖ Use DataBinding and BindingAdapter:
activity_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="activityMain"
type="com.veldan.mvi.ui.activities.MainActivity" />
</data>
<View
lambda="@{activityMain.lambda}"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</layout>
Upvotes: 2
Reputation: 1126
According to Binding Adapters documentation: "Event handlers may only be used with interfaces or abstract classes with one abstract method, as shown in the following example:
@BindingAdapter("android:onLayoutChange")
fun setOnLayoutChangeListener(
view: View,
oldValue: View.OnLayoutChangeListener?,
newValue: View.OnLayoutChangeListener?
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (oldValue != null) {
view.removeOnLayoutChangeListener(oldValue)
}
if (newValue != null) {
view.addOnLayoutChangeListener(newValue)
}
}
}
" DB docs never specify you can use Kotlin lambdas in Binding Adapters In this case you need to create an interface with only one method like this:
interface CustomOnCheckedListener {
fun onChecked(isChecked: Boolean)
}
then your Binding Adapter:
@BindingAdapter("onCheckedChanged")
fun bindOnCheckedChanged(view: SwitchCompat, onCheckedChanged: CustomCheckListener) {
view.setOnCheckedChangeListener(
{ _, isChecked ->
if (view.isPressed) onCheckedChanged.onChecked(isChecked)
}
)
}
in your ViewModel class you need to create a function with the same signature of the listener's method:
fun onChecked(isChecked: Boolean){
//some code here
}
and in your xml simply pass a reference to your function:
"@{viewModel::onChecked}"
Upvotes: 6