OutlinedTextField loses focus in jetpack compose when dropdown is shown - android

I have the following code:
Box(
Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
OutlinedTextField(
value = text,
onValueChange = {
text = it
if (text.length >= 3) {
viewModel.getSuggestions(text)
}
},
label = { Text("Search") },
modifier = Modifier.fillMaxWidth(),
singleLine = true,
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.ic_search),
contentDescription = null,
modifier = Modifier.padding(16.dp, 0.dp, 8.dp, 0.dp),
tint = Color.Unspecified
)
},
shape = RoundedCornerShape(50)
)
DropdownMenu(expanded = suggestions.value.isNotEmpty(),
modifier = Modifier
.fillMaxWidth(0.92f),
onDismissRequest = { }) {
for (suggestion in suggestions.value) {
DropdownMenuItem(onClick = {
viewModel.searchWord(suggestion)
}) {
Text(suggestion)
}
}
}
}
It's a dictionary, on top of the screen there is this OutlinedTextField.
When I search for a word I get suggestions based on the input and show them in a DropdownMenu.
The problem I am facing is that when the DropdownMenu is shown, the keyboard disappears but the focus remains on the Text field. How can I solve this problem and most importantly, why is this happening? I know it's redrawing the UI based on the status change but why it's not keeping the keyboard opened.

DropdownMenu(properties = PopupProperties(focusable = false))
Check this

Related

Cannot calculate specific dimensions for composable TextField

I am trying to create multiple items to encapsulate the specific behavior of every component but I cannot specify the dimensions for every view.
I want a Textfield with an X icon on its right
setContent {
Surface(
modifier = Modifier
.fillMaxSize()
.background(color = white)
.padding(horizontal = 15.dp)
) {
Row(horizontalArrangement = Arrangement.spacedBy(15.dp)) {
Searcher(
modifier = Modifier.weight(1f),
onTextChanged = { },
onSearchAction = { }
)
Image(
painter = painterResource(id = R.drawable.ic_close),
contentDescription = null,
colorFilter = ColorFilter.tint(blue)
)
}
}
}
The component is the following
#Composable
fun Searcher(
modifier: Modifier = Modifier,
onTextChanged: (String) -> Unit,
onSearchAction: () -> Unit
) {
Row {
SearcherField(
onTextChanged = onTextChanged,
onSearchAction = onSearchAction,
modifier = Modifier.weight(1f)
)
CircularSearch(
modifier = Modifier
.padding(horizontal = 10.dp)
.align(CenterVertically)
)
}
}
and the SearcherField:
#Composable
fun SearcherField(
modifier: Modifier = Modifier,
onTextChanged: (String) -> Unit,
onSearchAction: () -> Unit
) {
var fieldText by remember { mutableStateOf(emptyText) }
TextField(
value = fieldText,
onValueChange = { value ->
fieldText = value
if (value.length > 2)
onTextChanged(value)
},
singleLine = true,
textStyle = Typography.h5.copy(color = White),
colors = TextFieldDefaults.textFieldColors(
cursorColor = White,
focusedIndicatorColor = Transparent,
unfocusedIndicatorColor = Transparent,
backgroundColor = Transparent
),
trailingIcon = {
if (fieldText.isNotEmpty()) {
IconButton(onClick = {
fieldText = emptyText
}) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = emptyText
)
}
}
},
placeholder = {
Text(
text = stringResource(id = R.string.dondebuscas),
style = Typography.h5.copy(color = White)
)
},
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
keyboardActions = KeyboardActions(
onSearch = {
onSearchAction()
}
),
modifier = modifier.fillMaxWidth()
)
}
But I don´t know why, but the component Searcher with the placeholder is rendered in two lines.
It´s all about the placeholder that seems to be resized for not having enough space because if I remove the placeholder, the component looks perfect.
Everything is in one line, not having a placeholder of two lines. I m trying to modify the size of every item but I am not able to get the expected result and I don´t know if the problem is just about the placeholder.
How can I solve it? UPDATE -> I found the error
Thanks in advance!
Add maxlines = 1 to the placeholder Text's parameters.
Your field is single -lune but your text is multi-line. I think it creates conflict in implementation.
Okay... I find that the problem is about the trailing icon. Is not visible when there is no text in the TextField but is still occupying some space in the view, that´s why the placeholder cannot occupy the entire space. The solution is the following.
val trailingIconView = #Composable {
IconButton(onClick = {
fieldText = emptyText
}) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = emptyText
)
}
}
Create a variable with the icon and set it to the TextField only when is required
trailingIcon = if (fieldText.isNotEmpty()) trailingIconView else null,
With that, the trailing icon will be "gone" instead of "invisible" (the old way).
Still have a lot to learn.

Have LazyColumn and textfield pinned to bottom of screen. when textfield is focused, items in lazy column push it below keyboard

I have a lazy column that contains a number of Text(string = "...") and a textfield pinned to the bottom of the screen below the LazyColumn. when the textfield is focused, the keyboard shows up and it pushes the textfield above the keyboard which is expected. however, when the items in the LazyColumn r too much, the textfield goes below the keyboard instead of allowing the user to scroll the lazy column. any reason for this? I already have set
android:windowSoftInputMode="adjustResize" in my manifest's activity. here's the full code:
Column(modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.SpaceBetween) {
LazyColumn {
items(viewModel.options) { option ->
Text(option.message)
}
}
Row(modifier = Modifier.fillMaxWidth()) {
TextField(
modifier = Modifier.weight(1f),
value = optionsText,
onValueChange = {optionsText = it },
singleLine = true
)
Icon(
Icons.Filled.Send,
contentDescription = "",
modifier = Modifier.align(Alignment.CenterVertically).clickable {...}
)
}
}
Solution, WEIGHTS 🤪 !
LazyColumn(Modifier.weight(9f)) {
items(listItems) {
Text(it)
}
}
Row(modifier = Modifier.fillMaxWidth().weight(1f, /*false*/)) {
var loremText by remember { mutableStateOf("") }
TextField(
modifier = Modifier.weight(1f),
value = loremText,
onValueChange = { loremText = it },
singleLine = true
)
Icon(
Icons.Filled.Send,
contentDescription = "",
modifier = Modifier
.align(Alignment.CenterVertically)
.clickable { }
)
}
You may remove the adjustResize from your manifest.

Requesting focus on a BasicTextField in Jetpack Compose

I have simple LazyColumn where each row contains a BasicTextField (the rows contain label names which can be changed). The row's state is set to "editMode" when it is clicked. Only then I want the BasicTextField to be editable, which makes the edit icons visible. However, I have to click two times on the row, but I want it to set focus on the TextField when the row is clicked for the first time. Using the focusRequest just does not work (nothing happens). Where could the problem be? Here is the code:
val focusRequester = FocusRequester()
val inputService = LocalTextInputService.current
Row(
modifier = modifier
.fillMaxWidth()
.height(48.dp)
.clickable(enabled = true) {
onLabelClick() // here I set the editMode = true
inputService?.showSoftwareKeyboard()
focusRequester.requestFocus()
}
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Box(
modifier = Modifier.weight(1f)
) {
BasicTextField(
modifier = Modifier
.fillMaxSize()
.focusRequester(focusRequester)
.focusable(enabled = true),
value = tmpLabelName,
onValueChange = {
tmpLabelName = it
},
enabled = editMode,
singleLine = true,
textStyle = MaterialTheme.typography.body1,
decorationBox = { innerTextField ->
Box(
contentAlignment = Alignment.CenterStart
) {
if (tmpLabelName.isEmpty()) {
// show hint if text is empty
Text(
text = stringResource(id = R.string.enter_label_name)
)
} else {
innerTextField()
}
}
}
)
}
AnimatedVisibility(
visible = editMode,
enter = slideInHorizontally(
initialOffsetX = { fullWidth ->
fullWidth / 2
}
),
exit = fadeOut()
) {
Row {
IconButton(onClick = {
onLabelSaveClick(
label.name, tmpLabelName
)
}) {
Icon(
imageVector = Icons.Filled.Check,
contentDescription = stringResource(id = R.string.save_label_changes)
)
}
IconButton(onClick = {
onLabelDeleteClick(label.name)
}) {
Icon(
imageVector = Icons.Filled.Delete,
contentDescription = stringResource(id = R.string.delete_label)
)
}
}
}
}

Why the keyboard overlaps the content of my view when the keyboard is opened

I am using Android Compose to implement new UI in my app. Unfortunately the content of my view is hidden when the keyboard is opened.
Please find below some details :
#Composable
private fun OnBoardingAddressScreen() {
var address by remember { mutableStateOf("") }
val space = 35.dp
val horizontalPadding = resources.getDimension(R.dimen.horizontal_padding).dp
Column(modifier = Modifier.fillMaxSize()) {
OnBoardingTopContent()
Spacer(modifier = Modifier.size(space))
OnboardingAddressContent(
address = address,
onAddressChange = { address = it },
onBoardingButtonClick =
{
},
horizontalPadding
)
}
}
#Composable
private fun OnboardingAddressContent(
address: String,
onAddressChange: (String) -> Unit,
onBoardingButtonClick: () -> Unit,
horizontalPadding: Dp
) {
Column(modifier = Modifier
.fillMaxSize()) {
Text(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = horizontalPadding),
fontSize = 35.sp,
maxLines = 3,
text = "Welcome", fontWeight = FontWeight.Bold
)
Image(
modifier = Modifier
.align(alignment = Alignment.CenterHorizontally)
.size(330.dp, 330.dp),
painter = painterResource(R.drawable.onboarding_image),
contentDescription = null
)
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = horizontalPadding),
value = address,
onValueChange = onAddressChange,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
label = { Text("Your content") }
)
Box(modifier = Modifier.fillMaxSize()){
Image(
modifier = Modifier.align(Alignment.BottomStart),
painter = painterResource(R.drawable.onboarding_bottom_background),
contentDescription = null
)
Button(
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.align(Alignment.BottomCenter)
.padding(horizontal = horizontalPadding),
shape = RoundedCornerShape(10.dp),
content = { Text("Navigate") },
onClick = onBoardingButtonClick
)
}
}
}
And here the result :
Please notice :
I am using android:windowSoftInputMode="adjustPan" in my manifest and tried using android:windowSoftInputMode="adjustResize" but I still have the issue
Thank you in advance for your help
You can add an empty layout in the bottom of your screen when the keyboard will show then you will show the empty layout and when the keyboard is gone then you can hide the empty layout.
Can you check this link that provided from google : https://google.github.io/accompanist/insets/#animated-insets-support
ProvideWindowInsets(windowInsetsAnimationsEnabled = true) {
// content
}
and
OutlinedTextField(
// other params,
modifier = Modifier.navigationBarsWithImePadding()
)
Our problems seems to be very similar. I created some kind of tutorial basing on my code. Hope it will help:
(Compose UI) - Keyboard (IME) overlaps content of app

Jetpack Compose focus requester not working with Dialog

I'm using the below code to try and request focus to a textfield and have the keyboard come up. Currently the textfield does request focus but the keyboard fails to show. This same code works in another project im working on, but the difference here is this code is inside a Dialog composable, and the other code isn't, so I'm not sure if its the Dialog making the keyboard fail to show?
val textField = remember { FocusRequester() }
Dialog(onDismissRequest = {
openDialog.value = false
dialogInput.value = ""
}) {
Column(
modifier = Modifier
.height(274.dp)
.background(Color.Transparent)
.clickable {
openDialog.value = false
dialogInput.value = ""
}
) {
OutlinedTextField(
modifier = Modifier
.height(64.dp)
.background(Color.White)
.focusRequester(textField),
label = {
Text(
text = label,
style = MaterialTheme.typography.body2.copy(color = Color.Black)
)
},
value = dialogInput.value,
onValueChange = {
dialogInput.value = it
events.filterPlayers(it)
},
textStyle = MaterialTheme.typography.body2.copy(color = Color.Black),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.White,
unfocusedIndicatorColor = Color.White,
focusedIndicatorColor = Color.White
)
)
DisposableEffect(Unit) {
textField.requestFocus()
onDispose {}
}
}
val focusRequester = FocusRequester()
LocalView.current.viewTreeObserver.addOnWindowFocusChangeListener {
if (it) focusRequester.requestFocus()
}
this work for me, after window for dialog get focused, request focus for TextField would show soft keyboard automatically.

Categories

Resources