Untuk ViewModel, LiveData, dan Data binding
Saya membutuhkan fungsi ini untuk EditText
dengan dukungan multiline di aplikasi catatan saya. Saya ingin kursor di akhir teks ketika pengguna menavigasi ke fragmen yang memiliki teks catatan.
Solusi yang disarankan oleh djleop datang mendekat. Tetapi masalah dengan ini adalah bahwa, jika pengguna meletakkan kursor di suatu tempat di tengah teks untuk mengedit dan mulai mengetik, kursor akan melompat ke ujung teks lagi. Ini terjadi karena LiveData
akan memancarkan nilai baru dan kursor akan melompat ke ujung teks lagi sehingga pengguna tidak dapat mengedit teks di suatu tempat di tengah.
Untuk mengatasi ini, saya menggunakan MediatorLiveData
dan menetapkan panjang String
hanya sekali menggunakan bendera. Ini akan menyebabkan LiveData membaca nilai hanya sekali, yaitu ketika pengguna menavigasi ke fragmen. Setelah itu pengguna dapat menempatkan kursor di mana saja mereka ingin mengedit teks di sana.
ViewModel
private var accessedPosition: Boolean = false
val cursorPosition = MediatorLiveData<Event<Int>>().apply {
addSource(yourObject) { value ->
if(!accessedPosition) {
setValue(Event(yourObject.note.length))
accessedPosition = true
}
}
}
Di sini, yourObject
adalah LiveData lain yang diambil dari database yang menyimpan teks String yang Anda tampilkan di EditText
.
Kemudian ikat ini MediatorLiveData
ke EditText Anda menggunakan adaptor yang mengikat.
XML
Menggunakan pengikatan data dua arah untuk menampilkan teks serta menerima input teks.
<!-- android:text must be placed before cursorPosition otherwise we'll get IndexOutOfBounds exception-->
<EditText
android:text="@={viewModel.noteText}"
cursorPosition="@{viewModel.cursorPosition}" />
Binding Adapter
@BindingAdapter("cursorPosition")
fun bindCursorPosition(editText: EditText, event: Event<Int>?) {
event?.getContentIfNotHandled()?.let { editText.setSelection(it) }
}
Event
kelas
The Event
kelas di sini adalah seperti SingleLiveEvent ditulis oleh Jose Alcérreca dari Google. Saya menggunakannya di sini untuk menjaga rotasi layar. Menggunakan single Event
akan memastikan bahwa kursor tidak akan melompat ke akhir teks ketika pengguna mengedit teks di suatu tempat di tengah dan layar berputar. Ini akan mempertahankan posisi yang sama ketika layar berputar.
Inilah Event
kelasnya:
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
}
Ini adalah solusi yang berfungsi untuk saya dan memberikan pengalaman pengguna yang baik. Semoga ini membantu dalam proyek Anda juga.