How to set a OutlinedTextField occupy the remaining space Jetpack Compose? - android

I want to create a top app bar that contains a back icon and a search. Here is what I have tried.
SmallTopAppBar(
title = {
Text(
text = "MyApp"
)
},
navigationIcon = {
IconButton(
onClick = navController.popBackStack()
) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = null
)
}
},
actions = {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(1f) //Here is the issue.
.padding(2.dp)
value = search,
maxLines = 1,
singleLine = true
)
}
)
The problem comes when I try to use .fillMaxWidth(1f), it doesn't take only the remaining space, but it get over the arrow button?
This is what I expect:
How to solve this?

You can put the OutlinedTextField inside the title attribute instead of the actions attribute
SmallTopAppBar(
title = {
OutlinedTextField(
value = text,
onValueChange = {text = it},
modifier = Modifier.fillMaxWidth(1f)
.padding(2.dp),
maxLines = 1,
singleLine = true
)
},
navigationIcon = {
//IconButton
},
actions = {
//IconButton
}
)

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.

How to add drawable's next to textfield in jetpack compose?

I am trying to figure out how to add a drawable to a text within a textfield (OutlinedTextField) but without any success. I have already created a drawable in the drawable folder. Do I need to create a seperate composable to insert it or can I directly add it inside the textfield ?
This is my textfield in the composable:
Spacer(modifier = Modifier.height(20.dp))
OutlinedTextField(
value = username.value,
onValueChange = { newText ->
username.value = newText
},
label = { Text(text = "Username") },
placeholder = { Text("") }, // placeholder / hint
modifier = Modifier
.fillMaxWidth(180F)
)
Use leadingIcon instead of placeHolder
OutlinedTextField(
value = username.value,
onValueChange = { newText ->
username.value = newText
},
label = { Text(text = "Username") },
leadingIcon = { Icon(imageVector = Icons.Default.Place, contentDescription = null)},
modifier = Modifier
.fillMaxWidth(180F)
)

Show trailing icon after text input from user in TextField Jetpack Compose

I am trying to:
make the trailingIcon of TextField composable visible only if the user enters some text other than white spaces.
Later when the user clicks the trailingIcon the text in the TextField should get cleared and the trailingIcon should disappear.
Again when the user enters a text other than space, the trailingIcon should appear and enable this text clearing feature.
and so on...
I tried searching for solutions to this problem but mostly they were focused on "visible trailingIcons" and not what I was trying to implement.
Depending on text state you can specify null or actual view for trailingIcon parameter:
var text by remember { mutableStateOf("") }
val trailingIconView = #Composable {
IconButton(
onClick = {
text = ""
},
) {
Icon(
Icons.Default.Clear,
contentDescription = "",
tint = Color.Black
)
}
}
TextField(
value = text,
onValueChange = { text = it },
trailingIcon = if (text.isNotBlank()) trailingIconView else null,
)
You can add a condition to make visible the trailingIcon.
Something like:
var text by remember { mutableStateOf("") }
val isVisible by remember {
derivedStateOf {
text.isNotBlank()
}
}
OutlinedTextField(
value = text,
onValueChange = {
text = it
},
trailingIcon = {
if (isVisible) {
IconButton(
onClick = { text = "" }
) {
Icon(
imageVector = Icons.Default.Clear,
contentDescription = "Clear"
)
}
}
}
)

OutlinedTextField loses focus in jetpack compose when dropdown is shown

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

Categories

Resources