Вы связываете метод с app:sourceData
, но вы ожидаете переменную для него в адаптере привязки.Это не может работать.Я думаю, вы хотите заполнить список в Spinner.Для этого я хотел бы создать свойство в вашей viewModel и связать это свойство в XML.Я сделал это в приложении, где у меня был список проектов для отображения в Spinner.Вот код, включающий InverseBindingAdapter для автоматического сохранения выбранного проекта в другой переменной ViewModel.
ViewModel :
// getProjects() returns the LiveData
val projects = metaDataRepository.getProjects()
// use _selectedProject only within ViewModel. Do not expose MediatorLiveData to UI.
// in UI observe selectedProject
private val _selectedProject = MediatorLiveData<Project>()
val selectedProject: LiveData<Project>
get() = _selectedProject
Layout XML :
<Spinner
android:id="@+id/spProjects"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:projects="@{viewModel.projects}"
app:selectedProject="@={viewModel.selectedProject}" />
BindingAdapter (для заполнения данных из viewModel в пользовательский интерфейс):
/**
* fill the Spinner with all available projects.
* Set the Spinner selection to selectedProject.
* If the selection changes, call the InverseBindingAdapter
*/
@BindingAdapter(value = ["projects", "selectedProject", "selectedProjectAttrChanged"], requireAll = false)
fun setProjects(spinner: Spinner, projects: List<Project>?, selectedProject: Project, listener: InverseBindingListener) {
if (projects == null) return
spinner.adapter = ProjectAdapter(spinner.context, android.R.layout.simple_spinner_dropdown_item, projects)
setCurrentSelection(spinner, selectedProject)
setSpinnerListener(spinner, listener)
}
Вспомогательные методы для BindingAdapter :
private fun setSpinnerListener(spinner: Spinner, listener: InverseBindingListener) {
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) = listener.onChange()
override fun onNothingSelected(adapterView: AdapterView<*>) = listener.onChange()
}
}
private fun setCurrentSelection(spinner: Spinner, selectedItem: Project?): Boolean {
if (selectedItem == null) {
return false
}
for (index in 0 until spinner.adapter.count) {
val currentItem = spinner.getItemAtPosition(index) as Project
if (currentItem.name == selectedItem.name) {
spinner.setSelection(index)
return true
}
}
return false
}
Простой адаптер для вашего счетчика .Измените это для своих нужд:
/**
* Adapter for displaying the name-field of an Project in a Spinner
*/
class ProjectAdapter(context: Context, textViewResourceId: Int, private val values: List<Project>) : ArrayAdapter<Project>(context, textViewResourceId, values) {
override fun getCount() = values.size
override fun getItem(position: Int) = values[position]
override fun getItemId(position: Int) = position.toLong()
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val label = super.getView(position, convertView, parent) as TextView
label.text = values[position].name
return label
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
val label = super.getDropDownView(position, convertView, parent) as TextView
label.text = values[position].name
return label
}
}
InverseBindingAdapter (для сохранения выбранного элемента Spinner в viewModel)
/**
* get the selected projectName and use it to return a
* Project which is then used to set appEntry.value.project
*/
@InverseBindingAdapter(attribute = "selectedProject")
fun getSelectedProject(spinner: Spinner): Project {
return spinner.selectedItem as Project
}