对于ViewModel,LiveData和数据绑定
我需要EditText
在Notes应用程序中提供多行支持的功能。当用户导航到具有注释文本的片段时,我希望光标位于文本的末尾。
djleop建议的解决方案接近。但是,这样做的问题是,如果用户将光标放在文本中间的某个位置以进行编辑并开始输入,则光标会再次跳到文本结尾。发生这种情况是因为LiveData
会发出新值,并且光标会再次跳到文本的末尾,导致用户无法在中间的某个位置编辑文本。
为了解决这个问题,我使用一个标志并仅为MediatorLiveData
其分配了String
一次长度。这将使LiveData仅读取一次值,即,当用户导航到片段时。之后,用户可以将光标放置在要在其中编辑文本的任何位置。
视图模型
private var accessedPosition: Boolean = false
val cursorPosition = MediatorLiveData<Event<Int>>().apply {
addSource(yourObject) { value ->
if(!accessedPosition) {
setValue(Event(yourObject.note.length))
accessedPosition = true
}
}
}
这里yourObject
是从数据库检索的另一个LiveData,其中包含您在中显示的String文本EditText
。
然后MediatorLiveData
使用绑定适配器将此绑定到您的EditText。
XML格式
使用双向数据绑定来显示文本以及接受文本输入。
<!-- android:text must be placed before cursorPosition otherwise we'll get IndexOutOfBounds exception-->
<EditText
android:text="@={viewModel.noteText}"
cursorPosition="@{viewModel.cursorPosition}" />
绑定适配器
@BindingAdapter("cursorPosition")
fun bindCursorPosition(editText: EditText, event: Event<Int>?) {
event?.getContentIfNotHandled()?.let { editText.setSelection(it) }
}
Event
类
Event
这里的类就像Google的JoseAlcérreca编写的SingleLiveEvent。我在这里使用它来照顾屏幕旋转。Event
当用户在中间的某个位置编辑文本并旋转屏幕时,使用单个将确保光标不会跳到文本的末尾。屏幕旋转时它将保持相同的位置。
这是Event
课程:
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
这是对我有效的解决方案,并提供了良好的用户体验。希望它也对您的项目有所帮助。