I have a `BasicTextField` that needs to respond to...
# compose
n
I have a
BasicTextField
that needs to respond to
onValueChange
to update the text, but also needs to respond to some external button clicks to update the text. For example, if I click an emoji button to select an emoji, I need to insert the shortcode string of the emoji after the
current cursor position
, but I can't seem to get the current cursor position of the TextField? 🤔
s
There should be an overload which instead of taking in a String it should take in a TextValue or something like that which does include the state of the cursor, could that be what you need?
n
I'm using TextField actually, but it usually update in
onValueChange
, such as
Copy code
BasicTextField(
  value = viewModel.replyField,
  onValueChange = viewModel::updateText
)
and VM :
Copy code
var replyField by mutableStateOf(TextFieldValue(""))
  private set
fun updateText(text: TextFieldValue) { replyField = text }
I need to update this TextFIeldValue elsewhere, like:
Copy code
EmojiSheet(
  ...
  onSelectEmoji = { shortcode ->
    viewModel.updateText(
      text = viewModel.replyField.copy(viewModel.replyField.text + shortcode)
    )
)
The problem is here, I directly called the vm to update TextFieldValue instead of updating onValueChange in BasicTextField, so I don't know how to insert text after the cursor here. @Stylianos Gakis
s
So inside the VM you will have access to the old TextFieldState, and the new emoji that you want to append to it. Can you not, as you add the emoji text, look at the current cursor position and add the emoji text there? 🤔 I must be missing something here.
j
TextFieldValue
contains a selection property. When you change the text you want to update the selection to be
TextRange(<index of the end of the characters you added>)
, in addition to changing the annotatedString property. something like this in VM, as one approach:
Copy code
fun appendText(newString: String) {
    val newText = replyField.text + newString
    replyField = replyField.copy {
         text = newText
         selection = TextRange(newText.length)
    }
}
Note that I’m using copy() here to preserve whatever
composition
state the TextFieldValue might currently hold.