Двусторонняя привязка данных с переключателем внутри пользовательского представления относительного макета

Я пытаюсь реализовать некоторые пользовательские адаптеры привязки, чтобы я мог привязать значение моей модели представления к значению switch.ischecked в моем пользовательском представлении. Я хочу, чтобы состояние переключателя изменилось, если оно включено в моих изменениях модели просмотра и наоборот. Я просмотрел множество статей о том, как это сделать, но все равно ничего не делает. Я вижу, что мой метод setSwitchChecked используется реализацией привязки данных, но на самом деле он ничего не устанавливает. остальные 2 адаптера остаются неиспользованными. Любая помощь, как и то, что я упускаю или делаю неправильно, приветствуется.

ViewModel

open class SettingsViewModel @Inject constructor(): ViewModel() {

    var enabled: MutableLiveData<Boolean> = MutableLiveData()

}

Фрагмент

class SettingsFragment @Inject constructor(): Fragment() {

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory

    private lateinit var viewDataBinding: FragmentSettingsBinding
    private lateinit var viewModel: SettingsViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view: View = inflater.inflate(R.layout.fragment_settings, container, false)

        viewModel = ViewModelProviders.of(activity!!, viewModelFactory).get(SettingsViewModel::class.java)

        viewDataBinding = FragmentSettingsBinding.inflate(inflater, container, false).apply {
            viewmodel = viewModel
        }

      return view
    }
}

Привязка CustomView xml

<com.stinson.sleepcycles.views.SwitchRow
            android:id="@+id/switch_row"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:switchLabel="@string/enabled"
            app:switchChecked="@{viewmodel.enabled}"/>

Пользовательский класс представления

class SwitchRow constructor(context: Context, attrs: AttributeSet, defStyle: Int = 0) :
    RelativeLayout(context, attrs, defStyle), View.OnClickListener {

    constructor(context: Context, attrs: AttributeSet): this(context, attrs, 0)

    init {
        val view = inflate(context, R.layout.view_switch_row, this)

        val a = context.theme.obtainStyledAttributes(attrs, R.styleable.SwitchRow, defStyle, 0)
        try {
            view.text_label.text = a.getString(R.styleable.SwitchRow_switchLabel)
            view.switch_toggle.isChecked = a.getBoolean(R.styleable.SwitchRow_switchChecked, false)
        } finally {
            a.recycle()
        }

        view.setOnClickListener {
            view.switch_toggle.callOnClick()
        }
        view.switch_toggle.setOnClickListener {
            toggleSwitch(view)
        }
    }

    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
        if (event.action == MotionEvent.ACTION_UP) {
            this.callOnClick()
        }
        return super.dispatchTouchEvent(event)
    }

    override fun onClick(view: View?) {
        if (view != null) view.callOnClick()
    }

    private fun toggleSwitch(view: View) {
        view.switch_toggle.isChecked = !view.switch_toggle.isChecked
    }
}

XML пользовательского представления

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/selectableItemBackground"
    android:clickable="true"
    android:padding="16dp">

    <TextView
        android:id="@+id/text_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="@dimen/text_size_medium"
        tools:text="Label" />

    <androidx.appcompat.widget.SwitchCompat
        android:id="@+id/switch_toggle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"/>

</RelativeLayout>

Адаптеры для привязки

@BindingAdapter("switchCheckedAttrChanged")
fun setListener(switchRow: SwitchRow, listener: InverseBindingListener) {
    switchRow.switch_toggle.setOnCheckedChangeListener { _, _ ->
        listener.onChange()
    }
}

@BindingAdapter("switchChecked")
fun setSwitchChecked(switchRow: SwitchRow, value: Boolean) {
    if (value != switchRow.switch_toggle.isChecked) {
        switchRow.switch_toggle.isChecked = value
    }
}

@InverseBindingAdapter(attribute = "switchChecked")
fun getSwitchChecked(switchRow: SwitchRow): Boolean {
    return switchRow.switch_toggle.isChecked
}

person Jacob Stinson    schedule 12.05.2019    source источник


Ответы (1)


Ваш InverseBindingAdapter должен иметь следующую аннотацию:

@InverseBindingAdapter(attribute = "switchChecked", event = "switchCheckedAttrChanged")
person janosch    schedule 20.05.2019