我经历了许多类似的问题,但没有一个答案似乎解决了我的问题.我实现了一个自定义EditText,我希望与双向数据绑定兼容.问题是,每次我尝试编译时都会收到错误:
Error:java.lang.IllegalStateException: Failed to analyze: android.databinding.tool.util.LoggedErrorException: Found data binding errors. ****/ data binding error ****msg:Cannot find the getter for attribute 'android:text' with value type java.lang.String on com.app.toolkit.presentation.view.CustomEditText. file:/Users/humble-student/Home/workspace/android/application/app/src/main/res/layout/login_view.xml loc:68:8 - 81:69 ****\ data binding error **** at org.jetbrains.kotlin.analyzer.AnalysisResult.throwIfError(AnalysisResult.kt:57) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.kt:137) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:158) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:61) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:107) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:51) at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:92) at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$2.invoke(CompileServiceImpl.kt:386) at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$2.invoke(CompileServiceImpl.kt:96) at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:892) at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:96) at org.jetbrains.kotlin.daemon.common.DummyProfiler.withMeasure(PerfUtils.kt:137) at org.jetbrains.kotlin.daemon.CompileServiceImpl.checkedCompile(CompileServiceImpl.kt:919) at
这是我的实施:
CustomEditText
class CustomEditText @JvmOverloads constructor( context: Context,attrs: AttributeSet? = null,defStyleAttr: Int = 0 ) : LinearLayout(context,attrs,defStyleAttr) { // ... private lateinit var editText_input: EditText private lateinit var textView_errorMessage: TextView private var isErrorDisplayed = false private var inputTextOriginalColor: ColorStateList? = null init { orientation = VERTICAL clearContainerFormatting() createEditTextInput(context,defStyleAttr) createTextViewErrorMessage(context) addView(editText_input) addView(textView_errorMessage) } fun setError(message: String) { //... } fun getText(): String = editText_input.text.toString() fun setText(text: String) = editText_input.setText(text) // ... }
模型
data class SampleData( private var _content: String ) : BaSEObservable() { var content: String @Bindable get() = _content set(value) { _content = value notifyPropertyChanged(BR.content) } }
使用带有数据绑定的CustomView的客户端
<?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" xmlns:tools="http://schemas.android.com/tools"> <data> <import type="android.view.View" /> <variable name="data" type="SampleData" /> <variable name="presenter" type="SamplePresenter" /> </data> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:animateLayoutChanges="true" tools:context=".sample_view.presentation.view.SampleView"> <NotificationPopup android:id="@+id/notificationPopup" android:layout_width="match_parent" android:layout_height="wrap_content" android:clipToPadding="false" android:elevation="4dp" app:allowManualExit="true" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/textView_mirror" android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="sans-serif" android:text="@{data.content}" android:textSize="16sp" android:textStyle="bold" tools:text="test" /> <CustomEditText android:id="@+id/customEditText_sample" style="@style/RegisterInput" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Type anything" android:text="@={data.content}" /> <Button android:id="@+id/button_validateInput" style="@style/Widget.AppCompat.Button.Colored" android:layout_width="150dp" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:onClick='@{(v) -> presenter.onValidateDataClick(customEditTextSample.getText())}' android:text="Validate Input" /> </LinearLayout> </RelativeLayout> </layout>
P.S.:如果我将CustomEditText替换为常规的EditText小部件,它可以很好地工作
解决方法
有趣,但我能找到一个伟大的
post on medium,帮助我解决这个问题.基本上我需要的是CustomEditTextBinder:
@InverseBindingMethods( InverseBindingMethod( type = CustomEditText::class,attribute = "android:text",method = "getText" ) ) class CustomEditTextBinder { companion object { @JvmStatic @BindingAdapter(value = ["android:textAttrChanged"]) fun setListener(editText: CustomEditText,listener: InverseBindingListener?) { if (listener != null) { editText.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(charSequence: CharSequence,i: Int,i1: Int,i2: Int) { } override fun onTextChanged(charSequence: CharSequence,i2: Int) { } override fun afterTextChanged(editable: Editable) { listener.onChange() } }) } } @JvmStatic @BindingAdapter("android:text") fun setText(editText: CustomEditText,text: String?) { text?.let { if (it != editText.text) { editText.text = it } } }
它可能看起来很奇怪但你实际上并不需要在任何地方调用它,只需添加类,框架将负责通过注释处理找到它.请注意,为了防止无限循环,setText确实非常重要.我还补充说:
var text: String? get() = editText_input.text.toString() set(value) { editText_input.setText(value) } fun addTextChangedListener(listener: TextWatcher) = editText_input.addTextChangedListener(listener)
在CustomEditText上.