在Yigit Boyar and George Mount's talk on Android Databinding中,他们说明绑定到TextWatcher
的{{1}}是多么容易(13:41)。在按钮上。他们的幻灯片错了吗?首先,onTextChanged
视图没有Button
属性。它既没有onTextChanged
方法。 setOnTextChanged
也没有。但他们都有EditText
,其中addTextChangedListener
为输入。
那么他们在谈论什么?他们是如何做到的呢?他们的示例代码无法编译,但会出现此错误:
TextWatcher
如何使用Android数据绑定框架绑定到任何View或特别是EditText上的“文本更改事件”?
答案 0 :(得分:59)
实际上它开箱即用。我认为我的错误是使用旧版本的数据绑定框架。使用最新的,这是程序:
查看:
<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);
}
确保您参考了gradle构建工具v1.5.0或更高版本,并在build.gradle中启用了android.dataBinding.enabled true
数据绑定。
答案 1 :(得分:32)
要扩展@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
}
您始终需要传递零或所有参数。
答案 2 :(得分:4)
如果文本更改后只需要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
相同。
答案 3 :(得分:4)
我正在使用此方法来处理android databinding中的文本更改侦听器。在您的 ViewModel 类中的第一个创建 LiveData 变量,并创建 getText 返回 LiveData 对象的方法。
public MutableLiveData<String> verifyCodes = new MutableLiveData<>();
public LiveData<String> getCodes(){
return verifyCodes;
}
然后在您的xml文件中,将 text 上的 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 方法中更改文本时,您可以执行任何逻辑
答案 4 :(得分:2)
如果您正在使用onTextChange()
在模型中更新文本,则可以直接使用Two-way Binding。
<data>
<variable
name="user"
type="com.package.User"/>
</data>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@={user.name}"/>
您的模型班级将有getter
和setter
。
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
现在,模型中的名称将通过用户交互实时更改。因此,每当使用binding.getUser().getName()
时,您都会得到最新的文本。
单向绑定仅在更改模型值时才会更新。它不会实时更新模型。
android:text="@{user.name}"
双向绑定通过用户输入实时更新模型变量。
android:text="@={user.name}"
唯一区别是单向和双向绑定中的=
(等号)。
答案 5 :(得分:2)
1.在您的 BindingAdapter 类中,记下这一点。这里我传递了 viewModel 以便我们可以针对特定的 viewModel 执行特定的任务:
# Only match file that exists
RewriteCond "%{REQUEST_FILENAME}" -f
# Match any files (.*) that matches the RewriteCond. Don't apply changes (-) and apply the END flag.
RewriteRule .* - [END]
2.在您的 XML 中,在 Edittext 中,放置下面给出的属性: 这里的“viewModel”是我布局标签中LoginViewModel的变量名
@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()
}
}
})
}
答案 6 :(得分: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}" />
答案 7 :(得分:0)
创建一个类(我将他命名为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) {}
})
}
将此属性设置为xml布局中的editText
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:textChangedListener="@{3}" />
答案 8 :(得分:0)
我知道它是这样工作的:
片段:
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.getDiAtomicMolecules().observe(viewLifecycleOwner, Observer { items ->
recyclerAdapter.setData(items)
})
viewModel.getDiAtomicMoleculesByName().observe(viewLifecycleOwner, Observer { items ->
recyclerAdapter.setData(items)
})
//this is important
binding.viewModel = viewModel
}
}
layout.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>
ViewModel:
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()
}
}
答案 9 :(得分:-2)
将setOnFocusChangeListener
附加到EditText
,并使用文本内容与全局变量(字段的先前状态/内容)进行比较,以确定其是否已更改:
mEditTextTitle.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(!hasFocus)
// check if text has changed
}
});
答案 10 :(得分:-5)
代码不应该运行。根据API文档,TextView和EditText都没有“onTextChanged”XML属性。它们确实支持“addTextChangedListener”方法,但我不确定它是如何用于数据绑定的。
https://developer.android.com/reference/android/widget/TextView.html https://developer.android.com/reference/android/widget/EditText.html