ViewModel, LiveData 및 데이터 바인딩
EditText
노트 앱에서 여러 줄을 지원 하기 위해이 기능이 필요했습니다 . 사용자가 메모 텍스트가있는 조각으로 이동할 때 텍스트 끝에 커서를 원했습니다.
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가 있습니다 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의 Jose Alcé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
}
이것은 저에게 효과적이며 우수한 사용자 경험을 제공하는 솔루션입니다. 그것이 당신의 프로젝트에도 도움이되기를 바랍니다.