【问题标题】:Two-way databinding custom property on custom view自定义视图上的双向数据绑定自定义属性
【发布时间】:2020-03-14 05:17:21
【问题描述】:

我很难实现从片段的视图模型到自定义视图上的属性的双向绑定。将String 双向绑定到EditText 没有问题,并且单向绑定可以很好地与我的自定义SearchView 配合使用。但是当我在自定义视图上将"@{vm.entry.item}" 更改为"@={vm.entry.item}" 时,项目将无法编译,并抛出:

错误:找不到符号导入 com.test.test.databinding.FragmentTestBindingImpl;

我已经阅读this one 之类的教程有一段时间了,并尝试摆弄BindingAdapters,但没有运气。感觉好像我错过了一些明显的东西。

科特林

data class TestModel(
  var item: String? = null,
  var quantity: String? = null
)

class TestViewModel : ViewModel() {
  val entry = TestModel()
}

class TestFragment : Fragment() {

  private val vm: TestViewModel by lazy {
    ViewModelProvider(this).get(TestViewModel::class.java)
  }

  override fun onCreateView(
    inflater: LayoutInflater,
    parent: ViewGroup?,
    savedInstanceState: Bundle?
  ): View {
    val binding: FragmentTestBinding =
      DataBindingUtil.inflate(inflater, R.layout.fragment_test, parent, false)
    binding.setVariable(BR.vm, vm)
    binding.lifecycleOwner = viewLifecycleOwner
    return binding.root
  }
}

class SearchView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs, 0) {

  var selected: String? = null

  init {
    inflate(context, R.layout.view_search, this)

    val input: AutoCompleteTextView = findViewById(R.id.search_input)
    input.threshold = 1
    input.setAdapter(SearchAdapter(context))

    input.setOnItemClickListener { adapterView, _, position, _ ->
      val item: SearchModel = adapterView.getItemAtPosition(position) as SearchModel
      input.setText(item.name)
      selected = item.code
    }
  }
}

片段布局

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="vm"
            type="com.test.test.ui.TestViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.test.test.ui.views.SearchView
            android:id="@+id/test_search"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:selected="@={vm.entry.item}" />

        <EditText
            android:id="@+id/test_edit_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={vm.entry.quantity}" />

    </LinearLayout>

</layout>

SearchView 布局

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/paddingDouble"
    android:orientation="horizontal">

    <AutoCompleteTextView
        android:id="@+id/search_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</merge>

【问题讨论】:

    标签: android kotlin data-binding


    【解决方案1】:

    原来答案一直在the docs 中(很疯狂,对吧?)。

    关键的要点似乎是将[Inverse]BindingAdapter 函数包装在一个伴随对象中是不够的。它们还必须使用@JvmStatic 进行注释。

    我的完整自定义视图现在看起来像:

    class SearchView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs, 0) {
    
      var selected: String? = null
    
      init {
        inflate(context, R.layout.view_search, this)
      }
    
      companion object {
        @BindingAdapter("selectedAttrChanged")
        @JvmStatic
        fun setListener(view: SearchView, listener: InverseBindingListener) {
          val input: AutoCompleteTextView = view.findViewById(R.id.search_input)
          input.threshold = 1
          input.setAdapter(SearchAdapter(view.context))
          input.setOnItemClickListener { adapterView, _, position, _ ->
            val item: SearchModel = adapterView.getItemAtPosition(position) as SearchModel
            input.setText(item.name)
            selected = item.code
            listener.onChange()
          }
        }
    
        @BindingAdapter("selected")
        @JvmStatic
        fun setTextValue(view: SearchView, value: String?) {
          if (value != view.selected) view.selected = value
        }
    
        @InverseBindingAdapter(attribute = "selected")
        @JvmStatic
        fun getTextValue(view: SearchView): String? = view.selected
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-10
      • 2019-07-23
      • 1970-01-01
      • 1970-01-01
      • 2015-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多