I want to show a dialog and automatically set focus to a OutlinedTextField, so user can instantly start typing.
I ended up with text field does get focus, does get the cursor flickering, but the keyboard remains hidden. So user still has to click on a textField to make the keyboard appear.
Here is how I'm doing this
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
OutlinedTextField(
value = text,
modifier = Modifier
.focusRequester(focusRequester)
.fillMaxWidth(),
onValueChange = {
text = it
}
)
To make keyboard show up, you should place a delay before requesting the focus:
LaunchedEffect(Unit) {
delay(200)// <-- This is crucial.
focusRequester.requestFocus()
}
OutlinedTextField(
value = text,
modifier = Modifier
.focusRequester(focusRequester)
.fillMaxWidth(),
onValueChange = {
text = it
}
)
The delay time may be changed. For me it starts working starting from 100ms. If it still doesn't work with 200, increase it until it works. I believe it's all about performance of the devcie, so the higher the delay, the more slow devices can be used.
Related
After setting up a TextField in the TopAppBar. I encountered two problems:
Textfiled gains focused after folding keyboard. When textfield is not triggered, it looks like pic 1. And when I press it(it is focused), the keyboard shows up and tesxfield looks like pic 2. If I fold the keyboard manually, the textfiled keeps pic 2 look. I wish it can turn back to pic 1 look.
Editting cursor (the pin shape stuff) remains on the screen when I switch to a new screen. pic3 shows the cursor. The color is the same as the background. I'll change it. When I switch to another screen, it remains there like pic 4 shows. It only lasts for a split second and disappears. But it is there.
For the first problem, I must missed some parameter I gusess.
I have no idea for the second one. Is it a compose bug?
#Composable
fun SearchBar() {
var text by remember { mutableStateOf("") }
Box(
modifier = Modifier
.height(70.dp)
.fillMaxWidth()
.background(MaterialTheme.colors.primary),
contentAlignment = Alignment.BottomCenter
) {
TextField(
leadingIcon = {
Icon(imageVector = Icons.Default.Search, contentDescription = null)
},
placeholder = {
Text(
"find more...",
color = Color.White
)
},
shape = RectangleShape,
colors = TextFieldDefaults.textFieldColors(
textColor = Color.White,
backgroundColor = MaterialTheme.colors.primary,
focusedIndicatorColor = Color.White,
unfocusedIndicatorColor = Color.Gray,
disabledIndicatorColor = Color.Black
),
value = text,
singleLine = true,
onValueChange = { text = it },
modifier = Modifier
.padding( bottom = 10.dp)
.size(360.dp,60.dp),
)
}
}
Ok thanks for the extra details, try this!
For part 1) this code can be added to the TextField to remove focus:
val focusManager = LocalFocusManager.current
TextField(
...
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {
keyboardController?.hide()
focusManager.clearFocus(force = true)
}),
)
Note the Done option will show a little check box in the keyboard you can use to close the keyboard and then this code will remove focus. I'm hoping onDone will also be called when manually closing the keyboard.
For part 2) I would reuse the approach. It sounds like a bug, but basically I would try calling LocalFocusManager.current.clearFocus(force = true) from where ever you are doing the navigation away from this screen, right before leaving, to force the thing to disappear.
Hope this helps!
I have a BasicTextField in my jetpack compose function. When i click(user has input some text into the textfield by now) on a button to navigate to another composable in my NavHost, and from that new view click on back to the composable which i came from which has the textfield, the textfield is empty. I want to keep the text that the user typed in before navigating, but I can't figure it out how. Have looked here but found no answer.
Suggestions?
Here is my code:
#Composable
fun SearchBar(
modifier: Modifier = Modifier,
onSearch: (String) -> Unit = {}
) {
var text by remember {
mutableStateOf("")
}
Box(modifier = modifier) {
BasicTextField(
value = text,
onValueChange = {
text = it
onSearch(it)
},
maxLines = 1,
singleLine = true,
textStyle = TextStyle(color = Color.Black),
modifier = Modifier
.fillMaxWidth()
.shadow(5.dp, CircleShape)
.background(Color.White, CircleShape)
)
}
}
remember saves the value over recomposition (i.e., when your state changes, your composable automatically recomposes with the new state).
As per the Restore UI State guide, you can replace remember with rememberSaveable to save your state across:
Configuration changes
Process death and recreation
Your composable being put on the NavHost back stack
As well as any other case where your SearchBar could be removed from composition and then re-added (such as if you were using in Accompanist's Pager or in a LazyColumn or LazyRow).
var text by rememberSaveable {
mutableStateOf("")
}
I've a multi-line text field as below
val scrollState = rememberScrollState(0)
TextField(
modifier = Modifier
.fillMaxWidth()
.height(75.dp)
.verticalScroll(scrollState),
value = caption,
onValueChange = { onCaptionChanged(it) }
)
Currently, it support manual scrolling but i want it to scroll down automatically when user enter new line (\n). How do i achieve that?
You can scroll using scrollState.scrollTo. To track content height change, you can check scrollState.maxValue, for example like this:
LaunchedEffect(scrollState.maxValue) {
scrollState.scrollTo(scrollState.maxValue)
// or
// scrollState.animateScrollTo(scrollState.maxValue)
}
I have this TextFied Composable with both KeyboardOptions and KeyboardActions.
#Composable
fun TodoInputText(...) {
val keyboardController = LocalSoftwareKeyboardController.current
TextField( ....
onValueChange = onTextChanged,
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {
onImeAction()
keyboardController?.hide()
}))}
The TextField is working with the Done Action but I need to disable Done ImeAction on the keyboard whenever the TextFied is empty as illustrated on this GIF
I have already extracted a state to check if the TextField is empty.
#Composable
fun TodoItemEntryInput(...) {
//hold state for TextField
val (text, setText) = remember { mutableStateOf("") }
val isTextBlank = text.isNotBlank()
//declare lambda function submit that handles a submit event when done is pressed
val submitAction = { .... }
TodoItemInput(
text = text,
onTextChange = setText,
submitAction = submitAction,
)}
Now my question is how can I use the isTextBlank state to disable or Gray-out the Done ImeAction whenever the text is empty. This is to avoid bugs if the user enters blank text - I found input verification not very optimal for this case.
This is impossible in regular Android, so with Jetpack Compose this task also cannot be solved.
All you can do is check if the text in the onDone callback is valid, continue if it is, and show an error if it is not.
On tapping a TextField, created with Jetpack compose, the label of TextField moves upward. How do we disable this?
Or is there any other way the TexField would work like an EditText in View system where we have hint which disappears on tapping the EditText?
Jetpack compose version - 1.0.3
placeholder attribute might be what you are looking for.
But, the text doesn't disappear on clicking the TextField.
It disappears only when the user enters some input text.
Default state
Focused state
After entering input
Code
TextField(
placeholder = { Text(text = "Label") },
// Other attributes
)
UPDATE
You can use placeholder with state.
var focusState by remember { mutableStateOf(false) }
placeholder = {
Text(
text = if (focusState) "" else "label",
)
}
and focusState you take from onFocusChanged
TextField(
modifier = Modifier
.onFocusChanged { focus ->
focusState = focus.isFocused
}