56

Yigit Boyar 和 George Mount 关于 Android 数据绑定的演讲中,TextWatcher他们说明了绑定到's是多么容易onTextChanged(在 13:41)。在一个按钮上。他们的幻灯片错了吗?首先ButtonView 没有onTextChanged属性。它也没有setOnTextChanged方法。也没有EditText。但他们都有addTextChangedListener将 aTextWatcher作为输入。

那么他们在说什么?他们是怎么做到的呢?他们的示例代码无法编译,但会出现以下错误:

Error:(17) No resource identifier found for attribute 'onTextChanged' in package 'android'

如何使用 Android 数据绑定框架绑定到任何 View 或 EditText 上的“文本更改事件”?

4

10 回答 10

105

实际上它是开箱即用的。我认为我的错误是使用旧版本的数据绑定框架。使用最新的,这是程序:

看法:

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/username"
    android:text="Enter username:"
    android:onTextChanged="@{data.onTextChanged}" />

模型:

public void onTextChanged(CharSequence s, int start, int before, int count) {
    Log.w("tag", "onTextChanged " + s);
}

还要确保您已将模型分配给DataBinding

例如。在你的活动中

lateinit var activityMainDataBinding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    activityMainDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) 
    val dataViewModel = ViewModelProvider(this).get(DataViewModel::class.java)
    activityMainDataBinding.dataModel = dataViewModel
}

确保您引用了 gradle build tools v1.5.0 或更高版本,并android.dataBinding.enabled true在 build.gradle 中启用了数据绑定。

编辑:在这里运行的演示项目。查看模型

于 2015-11-21T09:30:22.700 回答
58

要扩展@Nilzors 答案,还可以在布局中传递文本和/或其他参数:

看法:

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/username"
    android:text="Enter username:"
    android:onTextChanged="@{(text, start, before, count) -> viewModel.onUsernameTextChanged(text)}" />

视图模型:

public void onUsernameTextChanged(CharSequence text) {
    // TODO do something with text
}

您总是需要传递零个或所有参数。

于 2017-08-17T10:23:19.777 回答
38

简单的方法

如果您onTextChange()用于更新模型中的文本,则可以直接使用双向绑定

<data>
    <variable
        name="user"
        type="com.package.User"/>
</data>

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@={user.name}"/>

模型类将有一个gettersetter

public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

现在name模型中的内容将随着用户交互而实时更改。所以使用binding.getUser().getName()会得到最新的文本。

单向绑定仅在模型值更改时才会更新。它不会实时更新模型。

android:text="@{user.name}"

双向绑定根据用户输入实时更新模型变量。

android:text="@={user.name}"

唯一的区别=(等号)接收对属性的数据更改并同时监听用户更新

于 2018-08-09T09:06:31.977 回答
5

如果您text在文本更改后只需要参数,则可以使用android:afterTextChanged绑定适配器。例如:

android:afterTextChanged="@{(text) -> viewModel.onTextChange(text)}"

然后在你ViewModel刚刚实现这样的:

fun onTextChange(editable: Editable?) {
    Log.d("TAG","New text: ${editable.toString()}")
}

此外,还有android:beforeTextChanged一个在文本更改事件之前知道旧文本的方法,用法与android:afterTextChanged.

于 2020-01-19T13:29:27.763 回答
5

我使用此方法处理 android databinding 中的文本更改侦听器。1st 在您的ViewModel类中创建LiveData变量,并创建返回LiveData对象的getText方法。

  • public MutableLiveData<String> verifyCodes = new MutableLiveData<>();
  • public LiveData<String> getCodes(){ return verifyCodes; }

然后在您的 xml 文件中,editText字段设置属性上的文本与上述 liveData 字段绑定

  • <EditText android:id="@+id/et_verification1st" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@={viewModel.verifyCodes}"/>

在数据绑定中,您已经知道如何在我相信的数据标签内创建 viewModel 类的变量。例如

  • <data> <variable name="viewModel" type="viewModel.VerifyUserActivityViewModel" /> </data>

好的,现在您的活动必须观察我们在 viewModel 类中创建的 liveData 对象

  • mViewModel.getCodes().observe(this,new Observer< String>(){ @Override public void onChange(String strings){ log.d("OnChange",strings); }});

您可以在onChange方法中更改文本时执行任何逻辑

于 2020-04-27T06:13:50.673 回答
3

1. 在你的 BindingAdapter 类中,写下这个。在这里,我传递了 viewModel,以便我们可以针对特定的 viewModel 执行特定的任务:

@BindingAdapter("app:addTextChangeListener")
fun addTextChangeListener(view: EditText, viewModel: ViewModel) {

    view.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

        override fun afterTextChanged(s: Editable?) {
            when (viewModel) {
                is LoginViewModel -> viewModel.invisibleErrorTexts()
            }
        }

    })

}

2. 在您的 XML 中,在 Edittext 中,放入下面给出的属性: 这里的“viewModel”是我的布局标签中 LoginViewModel 的变量名

app:addTextChangeListener="@{viewModel}"
于 2021-08-09T08:37:58.347 回答
1
  1. 创建一个类(我将他命名为 BindingAdapters)。然后定义您的 bindingAdapter 方法。

    @BindingAdapter("app:textChangedListener")
    fun onTextChanged(et: EditText, number: Int) {
    et.addTextChangedListener(object : TextWatcher {
        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
            if (et.text.toString().trim().length >= number) {
                et.setBackgroundColor(Color.GREEN)
            }
        }
    
        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
        override fun afterTextChanged(s: Editable) {}
    })
    

    }

  2. 在 xml 布局中为 editText 设置此属性

    <EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:textChangedListener="@{3}" />  
    
于 2019-10-06T06:52:24.357 回答
1

我让它像这样工作:

分段:

    class DiAtomicMoleculesFragment : Fragment() {
        private lateinit var binding: FragmentDiatomicMoleculesBinding
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            binding = FragmentDiatomicMoleculesBinding.inflate(layoutInflater, container, false)
            return binding.root
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            val recyclerAdapter = DiAtomicMoleculesAdapter(onClickListener)
    
            binding.diRecyclerView.apply {
                setHasFixedSize(true)
                layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
                adapter = recyclerAdapter
            }
    
            val viewModel = ViewModelProvider(this).get(DiAtomicMoleculesViewModel::class.java)
            viewModel.getDiAtomicMoleculesByName().observe(viewLifecycleOwner, Observer { items ->
                recyclerAdapter.setData(items)
            })
    
            //this is important !!!!!!!!!!!!!
            binding.viewModel = viewModel
        }
    }

布局.xml:

<?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="viewModel"
            type="com.mychemistry.viewmodel.DiAtomicMoleculesViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white">

        <androidx.appcompat.widget.AppCompatEditText
            android:id="@+id/di_search_box"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:gravity="center_vertical"
            android:hint="@string/search"
            android:paddingStart="10dp"
            android:paddingEnd="5dp"
            android:singleLine="true"
            android:textColor="@android:color/black"
            android:textColorHint="@android:color/darker_gray"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:onTextChanged="@{(text, start, before, count) -> viewModel.onTextChange(text)}"/>

<!--     or this ->      android:afterTextChanged="@{(e) -> viewModel.onTextChange(e)}"/>-->

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/di_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/di_search_box" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

视图模型:

class DiAtomicMoleculesViewModel : ViewModel() {
    private val allLiveData = AppDatabase.getInstance().getDiAtomicMoleculeDao().getAll()
    private val filterLiveData = MutableLiveData<String>()
    private val searchByLiveData = Transformations.switchMap(filterLiveData, ::filter)

    fun getDiAtomicMolecules(): LiveData<List<DiAtomicMolecule>> {
        return allLiveData
    }

    private fun filter(text: String): LiveData<List<DiAtomicMolecule>> {
        return AppDatabase.getInstance().getDiAtomicMoleculeDao().find(text)
    }

    fun getDiAtomicMoleculesByName(): LiveData<List<DiAtomicMolecule>> {
        return searchByLiveData
    }

    fun onTextChange(e: Editable?) {
        filterLiveData.value = e?.toString()
    }

    fun onTextChange(text: CharSequence?) {
        filterLiveData.value = text?.toString()
    }
}
于 2020-02-08T15:36:31.737 回答
0

最好的方法是添加绑定适配器和文本观察器。

public class Model{
    private TextWatcher textWatcher;

public Model(){
        this.textWatcher= getTextWatcherIns();
}

private TextWatcher getTextWatcherIns() {
        return new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                //do some thing
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                //do some thing

            }

            @Override
            public void afterTextChanged(Editable s) {
                //do some thing
            }
        };
    }

    public TextWatcher getTextWatcher() {
        return textWatcher;
    }

    public void setTextWatcher(TextWatcher textWatcher) {
        this.textWatcher = textWatcher;
    }

    @BindingAdapter("textChangedListener")
    public static void bindTextWatcher(EditText editText, TextWatcher textWatcher) {
        editText.addTextChangedListener(textWatcher);
    }
}

并在您的 xml 中将此属性添加到您的编辑文本中

<EditText
            android:id="@+id/et"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:textChangedListener="@{model.textWatcher}" />
于 2019-04-16T05:25:16.000 回答
-7

将一个附加setOnFocusChangeListenerEditText, 并使用将文本内容与全局变量(字段的先前状态/内容)进行比较以确定它是否已更改:

    mEditTextTitle.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if(!hasFocus)
                // check if text has changed       
        }
    });
于 2015-11-20T21:21:36.640 回答