Für ViewModel, LiveData und Datenbindung
Ich brauchte diese Funktionalität für die EditText
mehrzeilige Unterstützung in meiner Notizen-App. Ich wollte den Cursor am Ende des Textes, wenn der Benutzer zu dem Fragment navigiert, das Notiztext enthält.
Die vom Djleop vorgeschlagene Lösung kommt nahe. Das Problem dabei ist jedoch, dass, wenn der Benutzer den Cursor zum Bearbeiten irgendwo in die Mitte des Textes setzt und mit der Eingabe beginnt, der Cursor wieder zum Ende des Texts springt. Dies geschah, weil dieLiveData
neue Wert ausgegeben wurde und der Cursor erneut zum Ende des Textes sprang, was dazu führte, dass der Benutzer den Text nicht irgendwo in der Mitte bearbeiten konnte.
Um dies zu lösen, benutze ich MediatorLiveData
die Länge und weise sie String
nur einmal mit einem Flag zu. Dadurch lesen die LiveData den Wert nur einmal, dh wenn der Benutzer zum Fragment navigiert. Danach kann der Benutzer den Cursor an einer beliebigen Stelle platzieren, an der er den Text dort bearbeiten möchte.
ViewModel
private var accessedPosition: Boolean = false
val cursorPosition = MediatorLiveData<Event<Int>>().apply {
addSource(yourObject) { value ->
if(!accessedPosition) {
setValue(Event(yourObject.note.length))
accessedPosition = true
}
}
}
Hier yourObject
ist eine weitere LiveData, die aus der Datenbank abgerufen wurde und den String-Text enthält, den Sie in der Datenbank anzeigenEditText
.
Binden Sie dies MediatorLiveData
dann mit dem Bindungsadapter an Ihren EditText.
XML
Verwendet die bidirektionale Datenbindung zum Anzeigen von Text sowie zum Akzeptieren der Texteingabe.
<!-- android:text must be placed before cursorPosition otherwise we'll get IndexOutOfBounds exception-->
<EditText
android:text="@={viewModel.noteText}"
cursorPosition="@{viewModel.cursorPosition}" />
Bindungsadapter
@BindingAdapter("cursorPosition")
fun bindCursorPosition(editText: EditText, event: Event<Int>?) {
event?.getContentIfNotHandled()?.let { editText.setSelection(it) }
}
Event
Klasse
Die Event
Klasse hier ist wie ein SingleLiveEvent, das von Jose Alcérreca von Google geschrieben wurde. Ich benutze es hier, um mich um die Bildschirmrotation zu kümmern. Durch die Verwendung der Single Event
wird sichergestellt, dass der Cursor nicht zum Ende des Texts springt, wenn der Benutzer den Text irgendwo in der Mitte bearbeitet und sich der Bildschirm dreht. Es behält die gleiche Position bei, wenn sich der Bildschirm dreht.
Hier ist die Event
Klasse:
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
}
Dies ist die Lösung, die für mich funktioniert und eine gute Benutzererfahrung bietet. Hoffe, es hilft auch in Ihren Projekten.