如何在Switch的onCheckedChageListener事件中使用数据绑定?

44
如问题所示,如何在xml中将checked change listener绑定到Switch开关按钮?
我没有使用RecyclerView,只是一个简单的布局。
感谢任何帮助。

动态设置有什么问题吗? - AL.
我们能否在项目的其他地方使用具有可观察字段的相同视图模型,同时使用磁盘缓存? - Mohanish Nerurkar
4个回答

52

使用lambda表达式和Switch

public void onCheckedChanged(boolean checked) {
     // implementation      
}

XML文件:

<android.support.v7.widget.SwitchCompat
    android:onCheckedChanged="@{(switch, checked) -> item.onCheckedChanged(checked)}"
    ...
/>

item是实现onCheckedChange方法的类,并像这样导入到XML文件中:

<data>
    <variable
        name="item"
        type="yourClass"/>
</data>

我们能否创建一个自定义的双向绑定,以减少样板代码? - Aditya Ladwa
1
@AdityaLadwa,使用“checked”属性有什么问题吗?你可以很容易地绑定它。 - Hossein Shahdoost
但是在使用这个之后,如果我尝试使用binding.mySwitch.setChecked(true)编程方式来检查我的开关,item.onCheckedChanged方法就不会被调用!!! - adi
1
找不到可接受“lambda”参数类型的设置器,以用于<com.google.android.material.switchmaterial.SwitchMaterial app:onCheckedChanged>。 - Ajit Kumar Dubey

29

不同的方式

(1) 通过方法表达式设置

在布局中

<variable
    name="activity"
    type="com.innovanathinklabs.sample.activities.CalendarActivity"/>

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="@={model.checked}"
    android:onCheckedChanged="@{activity::onGenderChanged}"
    />

进行中

class HomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
        binding.activity = this
        binding.model = Model()
    }

    fun onGenderChanged(buttonView: CompoundButton, isChecked: Boolean) {
        println("buttonView = [$buttonView], isChecked = [$isChecked]")
    }
}

(2) 通过lambda表达式和方法调用设置

<variable
    name="model"
    type="com.innovanathinklabs.sample.data.Model"/>

<variable
    name="activity"
    type="com.innovanathinklabs.sample.activities.HomeActivity"/>

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="@={model.checked}"
    android:onCheckedChanged="@{(button, bool)-> activity.saveGender(bool)}"
    />

在活动中

class HomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
        binding.activity = this
        binding.model = Model()
    }

    fun saveGender(isChecked: Boolean) {
        println("isChecked = [$isChecked]")
    }
}

(3) 将 OnCheckedChangeListener 匿名类传递到布局中

<variable
    name="onGenderChange"
    type="android.widget.CompoundButton.OnCheckedChangeListener"/>

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="@={model.checked}"
    android:onCheckedChanged="@{onGenderChange}"
    />

进行中

class HomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
        binding.model = Model()
        binding.setOnGenderChange { buttonView, isChecked ->
            println("buttonView = [$buttonView], isChecked = [$isChecked]")
        }
    }
}

(4) 通过引用传递OnCheckedChangeListener

<variable
    name="onGenderChange2"
    type="android.widget.CompoundButton.OnCheckedChangeListener"/>

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="@={model.checked}"
    android:onCheckedChanged="@{onGenderChange2}"
    />

活动

class HomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
        binding.model = Model()
        binding.onGenderChange2 = onGenderChange
    }

    private val onGenderChange: CompoundButton.OnCheckedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
        println("buttonView = [$buttonView], isChecked = [$isChecked]")
    }
}

现在以下方法将不起作用

如果你在代码中设置CheckChangeListener,那么它将不起作用。因为你无法在一个组件上设置两个回调函数。一个回调函数已经被绑定设置了,所以你在代码中的回调函数将不起作用。

binding.mySwitch.setOnCheckedChangeListener { buttonView, isChecked ->
    println("buttonView = [$buttonView], isChecked = [$isChecked]")
}

查看 CompoundButtonBindingAdapter 类,以了解 Switch 绑定的工作方式。


最后那个语句救了我一天。显然我在一个RadioGroup上有两个监听器,所以绑定实现不起作用,我一直在想原因。 - Danilo Mz
有没有一种方法只使用xml来实现这个?也就是说,如果我在xml中有一个SwitchPreference,并且我想要它使用自定义布局android:layout="@layout/custom"并传递一个数据绑定的标题“passedTitle”,我可以使用<include>成功地执行如下操作:<include layout="@layout/custom" bind:passedTitle="@{@string/title}" />,但如果我只是在preference中这样做,它什么也不做(我得到attribute passedTitle not found):<SwitchPreference android:key="@string/key" layout="@layout/custom" bind:passedTitle="@{@string/title}" - Elliptica
1
漂亮的答案。使用了最后一个。 - kgandroid
很遗憾,我不能为您提交的每个解决方案点赞。 - Shawn
不需要引用任何活动,android:onCheckedChanged 应该在 viewModel 中触发一个请求。 - user924

13
你可以使用方法引用来完成它:

你可以使用方法引用来完成它:

<CheckBox android:onCheckedChanged="@{callback::checkedChangedListener}".../>

或者,如果你想传递不同的参数,可以使用 Lambda 表达式:

<CheckBox android:onCheckedChanged="@{() -> callback.checked()}".../>

28
这对我没用,我收到了“Unknown attribute android:onCheckedChanged”错误。 - Tiago Oliveira
2
@TiagoOliveira 尽管我也收到了那个警告,但启动应用程序后似乎确实可以工作。 - arekolek
@GeorgeMount 为什么我们不能使用 app:onCheckedChangeListener 来调用 CheckBox 中的 setOnCheckedChangeListener 方法? - David

4

只需在您的ViewModel上首先使用ViewModel、LiveData和Transformations。

var availabilityState = MutableLiveData<Boolean>(false)
val availabilityText :LiveData<String> =Transformations.map(availabilityState)
{
    if (it == true)
    {
        "Available"
    }else
    {
      "Not Available"
    }
}

然后在您的 XML 中使用

<Switch
android:checked="@={addBookViewModel.availabilityState}"
android:text="@{addBookViewModel.availabilityText}"
...>

就是这样。


也适用于 androidx.appcompat.widget.SwitchCompat。 - Alessandro Caliaro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接