TextFieldState
class TextFieldState
internal constructor(
initialText: String,
initialSelection: TextRange,
initialTextUndoManager: TextUndoManager,
)
The editable text state of a text field, including both the text
itself and position of the
cursor or selection.
To change the text field contents programmatically, call edit
, setTextAndSelectAll
,
setTextAndPlaceCursorAtEnd
, or clearText
. Individual parts of the state like text
,
selection
, or composition
can be read from any snapshot restart scope like Composable
functions. To observe these members from outside a restart scope, use snapshotFlow { textFieldState.text }
or snapshotFlow { textFieldState.selection }
.
When instantiating this class from a composable, use rememberTextFieldState
to automatically
save and restore the field state. For more advanced use cases, pass TextFieldState.Saver
to
rememberSaveable
.
Secondary Constructors
@RememberInComposition
constructor(
initialText: String = "",
initialSelection: TextRange = TextRange(initialText.length),
) : this(initialText, initialSelection, TextUndoManager())
Properties
val text: CharSequence
The current text content. This value will automatically update when the user enters text or
otherwise changes the text field contents. To change it programmatically, call edit
.
To observe changes to this property outside a restartable function, use snapshotFlow { text }
.
val selection: TextRange
The current selection range. If the selection is collapsed, it represents cursor location.
This value will automatically update when the user enters text or otherwise changes the text
field selection range. To change it programmatically, call edit
.
To observe changes to this property outside a restartable function, use snapshotFlow { selection }
.
val composition: TextRange?
The current composing range dictated by the IME. If null, there is no composing region.
To observe changes to this property outside a restartable function, use snapshotFlow { composition }
.
@ExperimentalFoundationApi val undoState: UndoState
Undo history controller for this TextFieldState.
Functions
inline fun edit(block: TextFieldBuffer.() -> Unit)
Runs block
with a mutable version of the current state. The block can make changes to the
text and cursor/selection. See the documentation on TextFieldBuffer
for a more detailed
description of the available operations.
Make sure that you do not make concurrent calls to this function or call it again inside
block
's scope. Doing either of these actions will result in triggering an
IllegalStateException
.
Code Examples
BasicTextFieldStateCompleteSample
fun BasicTextFieldStateCompleteSample() {
class SearchViewModel(val searchFieldState: TextFieldState = TextFieldState()) {
private val queryValidationRegex = """\w+""".toRegex()
// Use derived state to avoid recomposing every time the text changes, and only recompose
// when the input becomes valid or invalid.
val isQueryValid by derivedStateOf {
// This lambda will be re-executed every time inputState.text changes.
searchFieldState.text.matches(queryValidationRegex)
}
var searchResults: List<String> by mutableStateOf(emptyList())
private set
/** Called while the view model is active, e.g. from a LaunchedEffect. */
suspend fun run() {
snapshotFlow { searchFieldState.text }
.collectLatest { queryText ->
// Start a new search every time the user types something valid. If the previous
// search is still being processed when the text is changed, it will be
// cancelled
// and this code will run again with the latest query text.
if (isQueryValid) {
searchResults = performSearch(query = queryText)
}
}
}
fun clearQuery() {
searchFieldState.setTextAndPlaceCursorAtEnd("")
}
private suspend fun performSearch(query: CharSequence): List<String> {
TODO()
}
}
@Composable
fun SearchScreen(viewModel: SearchViewModel) {
Column {
Row {
BasicTextField(viewModel.searchFieldState)
IconButton(onClick = { viewModel.clearQuery() }) {
Icon(Icons.Default.Clear, contentDescription = "clear search query")
}
}
if (!viewModel.isQueryValid) {
Text("Invalid query", style = TextStyle(color = Color.Red))
}
LazyColumn { items(viewModel.searchResults) { TODO() } }
}
}
}