Для перегляду ViewModel, LiveData та даних
Мені потрібна ця функціональність для EditText
багатолінійної підтримки в моєму додатку. Мені хотілося, щоб курсор в кінці тексту, коли користувач перейшов до фрагмента, який містить текст примітки.
Рішення, запропоноване djleop, наближається. Але проблема з цим полягає в тому, що якщо користувач кладе курсор десь посередині тексту для редагування і почне вводити текст, курсор знову перескочить до кінця тексту. Це сталося тому, щоLiveData
виправити нове значення, а курсор знову перескочить на кінець тексту, в результаті чого користувач не зможе редагувати текст десь посередині.
Для вирішення цього питання я використовую MediatorLiveData
і призначаю його довжину String
лише один раз, використовуючи прапор. Це призведе до того, що LiveData прочитає значення лише один раз, тобто коли користувач перейде до фрагмента. Після цього користувач може розмістити курсор у будь-якому місці, де він хоче редагувати текст.
ViewModel
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
Клас тут як SingleLiveEvent написаний Хосе Alcérreca від Google. Я використовую його тут, щоб подбати про обертання екрана. Використовуючи сингл 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
}
Це рішення, яке працює для мене і забезпечує хороший досвід користувача. Сподіваємось, це допоможе і у ваших проектах.