Row drawn over columns in compose for desktop - kotlin

I am developing a little application in compose for desktop on my windows machine. I put a OutlinedTextField into a column, which is in row. The problem is, that I cant see any text within it. Neither the default, nor am I able to edit the text. The box is focusable, but not editable.
I discovered, that the row is drawn above of my column. I assume that the row is swallow the event, or overpaint the text. I tried to set the z-index to high, but it didn't have any effect.
#Composable
fun menuInLeftSplitContent() = Row(Modifier.padding(all 5.dp).zIndex(-1F).background(Color
.Black)) {
Column {
IconButton(modifier = Modifier.padding(end = 5.dp), onClick = {}) {
Icon(Icons.Rounded.Add, "Add")
}
}
Column(modifier = Modifier.zIndex(20F)) {
val mutableText = mutableStateOf("Hello World")
OutlinedTextField(
value = mutableText.value,
onValueChange = { },
modifier = Modifier.fillMaxSize(),
singleLine = true,
leadingIcon = { Icons.Filled.Search },
enabled = true,
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Characters,
autoCorrect = false,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.None
),
maxLines = 1,
readOnly = false
)
}}
If the column wasn't overpainted by the row, you would see the picture beneath.
This is how it should look like.

Related

Jetpack Compose - Can't change AlertDialog white window background

I'm new to Kotlin Multiplatform Desktop development and I'm using Compose to build UI. I have one AlertDialog with custom, rounded background, problem is, it still has white corners which I can not remove for some reasons. The dialog:
The code I've written to achieve this:
AlertDialog(
title = { Text("თქვენ ტოვებთ პროგრამას") },
text = { Text("ნამდვილად გსურთ პროგრამიდან გასვლა?") },
onDismissRequest = {},
backgroundColor = Colors.DARKER_GRAY,
contentColor = Colors.WHITE,
shape = RoundedCornerShape(16.dp),
confirmButton = {
TextButton(onClick = onPositiveClick) {
Text(text = "დიახ", color = Colors.RED)
}
},
dismissButton = {
TextButton(onClick = onNegativeClick) {
Text(text = "არა", color = Colors.LIGHTER_GRAY)
}
},
modifier = Modifier.defaultMinSize(300.dp).border(0.dp, Color.Transparent, RoundedCornerShape(0))
)
Anyone has any idea how can I solve this? Thank You in advance.
გაუმარჯოს! Try to add the same shape size to Modifier's border as you applied to Dialog's shape:
modifier = Modifier.defaultMinSize(300.dp).border(0.dp, Color.Transparent, RoundedCornerShape(16.dp))
Or you just remove it. The AlertDialogs come without borders.
Perhaps there might be difference between Android and Desktop and you really need that.
At least from Android point of view that's not necessary.
წარმატება!
If I may ask you, is that the preview because if I wrap your code in a column and change its background colour and runs it, it works perfectly okay.
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.Red),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
///Your code is here
AlertDialog(
title = { Text("თქვენ ტოვებთ პროგრამას") },
text = { Text("ნამდვილად გსურთ პროგრამიდან გასვლა?") },
onDismissRequest = {},
backgroundColor = Color.Gray,
contentColor = Color.White,
shape = RoundedCornerShape(16.dp),
confirmButton = {
TextButton(onClick = { /*onPositiveClick*/ }) {
Text(text = "დიახ", color = Color.Red)
}
},
dismissButton = {
TextButton(onClick = { /*onNegativeClick*/ }) {
Text(text = "არა", color = Color.LightGray)
}
},
modifier = Modifier
.defaultMinSize(300.dp)
.border(0.dp, Color.Transparent, RoundedCornerShape(0))
)
}
The bug is related to the native android theme color.
Just change background color on your theme:
<item name="android:background">#android:color/transparent</item>

Jetpack Compose intrinsicWidth of Row in DropDownMenu

I am trying to display a longer text in a context menu, without cutting it off. I do not understand how the width is actually measured. It seems to me that I need to define the IntrinsicWidth of the Row somehow, but I am note sure how to do it.
Given the following code:
DropdownMenu(
modifier = Modifier,
expanded = shouldShowContextMenu,
onDismissRequest = { openedContextMenu.value = null }
) {
listOf("first", "something very-very long", "short").forEach {
Row {
Icon(
imageVector = Icons.Filled.Check,
contentDescription = null,
tint = LocalTextStyle.current.color,
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = it,
)
}
}
}
I am getting this DropdownMenu:
If I change the Text arguments to maxLines=1, like this:
// only change is this:
Text(
text = it,
maxLines = 1,
overflow = TextOverflow.Visible,
)
The second text line will be cut off, but it will not be force into a single line:
But if I reorder them, so the Text comes first, then the column will stretch accordingly and the Icon will be cut off:
DropdownMenu(
modifier = Modifier,
expanded = shouldShowContextMenu,
onDismissRequest = { openedContextMenu.value = null }
) {
listOf("first", "something very-very long with more text", "short").forEach {
Row {
Text(
text = it,
)
Spacer(modifier = Modifier.width(8.dp))
Icon(
imageVector = Icons.Filled.Check,
contentDescription = null,
tint = Color.White,
)
}
}
}
Like this:
How can I configure the text menu to show the icon and the text in one line (in that order)?

Jetpack Compose - Disable TextField long press handler

I have an IconButton in the trailingIcon of OutlinedTextField like:
OutlinedTextField(
modifier = Modifier.weight(1f),
label = { Text(text = "Label") },
value = text,
onValueChange = { text = it },
trailingIcon = {
IconButton2(onClick = {
println("onClick")
}, onLongClick = {
println("onLongClick shows TextToolbar")
}) {
Icon(
imageVector = Icons.Filled.Menu,
contentDescription = null
)
}
}
)
IconButton2 is just a copy of IconButton but with combinedClickable to include onLongClick instead of clickable.
The problem is that when I long click IconButton2, it shows the TextToolbar for the TextField. Doesn't matter what I do, the text field will handle long click, show the TextToolbar and provide haptic feedback.
Even if I use pointerInput with awaitPointerEvent and consumeAllChanges (like here) it still triggers it. The TextField doesn't answer to any tap or anything but if I long click it, it answers!
The workaround I'm doing for now is wrapping the text field in a Row and add the IconButton beside it instead of "inside" but I needed to have the icon button as the trailingIcon.
Is there any way to properly do it?
Compose 1.0.3 and 1.1.0-alpha05 both behaves the same.
I ended up making a small hack that seems to be working fine, so basically I add a dummy Box as the trailingIcon to get the position of it, then I add an IconButton outside of it (both wrapped in a Box) and I also get the position of it + I offset it using the position of the dummy box. Not the ideal solution but works fine.
Here's the full source if anyone needs it:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.padding(16.dp),
color = MaterialTheme.colors.background
) {
var text by remember { mutableStateOf("") }
var trailingIconOffset by remember { mutableStateOf(Offset.Zero) }
var iconButtonOffset by remember { mutableStateOf(Offset.Zero) }
val colors = TextFieldDefaults.outlinedTextFieldColors()
Column {
//With hack
Box {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
label = { Text(text = "With hack") },
value = text,
onValueChange = { text = it },
trailingIcon = {
Box(modifier = IconButtonSizeModifier
.onGloballyPositioned {
trailingIconOffset = it.positionInRoot()
}
)
},
colors = colors
)
val contentColor by colors.trailingIconColor(
enabled = true,
isError = false
)
CompositionLocalProvider(
LocalContentColor provides contentColor,
LocalContentAlpha provides contentColor.alpha
) {
IconButton2(
modifier = Modifier
.onGloballyPositioned {
iconButtonOffset = it.positionInRoot()
}
.absoluteOffset {
IntOffset(
(trailingIconOffset.x - iconButtonOffset.x).toInt(),
(trailingIconOffset.y - iconButtonOffset.y).toInt()
)
},
onClick = {
text = "onClick"
},
onLongClick = {
text = "onLongClick"
}
) {
Icon(imageVector = Icons.Filled.Menu, contentDescription = null)
}
}
}
//Without hack
Box {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
label = { Text(text = "Without hack") },
value = text,
onValueChange = { text = it },
trailingIcon = {
IconButton2(
onClick = {
text = "onClick"
},
onLongClick = {
text = "onLongClick"
}
) {
Icon(
imageVector = Icons.Filled.Menu,
contentDescription = null
)
}
},
colors = colors
)
}
}
}
}
}
}
}
private val RippleRadius = 24.dp
private val IconButtonSizeModifier = Modifier.size(48.dp)
#OptIn(ExperimentalFoundationApi::class)
#Composable
fun IconButton2(
modifier: Modifier = Modifier,
onClick: () -> Unit,
onLongClick: (() -> Unit)? = null,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: #Composable () -> Unit
) {
Box(
modifier = modifier
.combinedClickable(
onClick = onClick,
onLongClick = onLongClick,
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = rememberRipple(bounded = false, radius = RippleRadius)
)
.then(IconButtonSizeModifier),
contentAlignment = Alignment.Center
) {
val contentAlpha = if (enabled) LocalContentAlpha.current else ContentAlpha.disabled
CompositionLocalProvider(LocalContentAlpha provides contentAlpha, content = content)
}
}

DecorationBox in Jetpack Compose BasicTextField

I use jetpack compose create a editText,I want to show a hint like before "android:hint",
so I try to use decorationBox,but after I created it the input isn't displayed and the log can display my input content.
this is my code,
val passState= remember { mutableStateOf(TextFieldValue("")) }
BasicTextField(
decorationBox = {
Text("password",color = loginGrayColor)
},
value = passState.value,
onValueChange = { passState.value = it ; Log.d("password",it.text) },
singleLine = true,
maxLines = 1,
textStyle = TextStyle(
fontSize = 15.sp,
color = loginInputTextColor
),
modifier = Modifier
.padding(start = 10.dp, top = 10.dp)
.height(20.dp)
)
You have to add the innerTextField provided by the decorationBox.
Something like:
var value by remember { mutableStateOf(TextFieldValue("")) }
BasicTextField(
value = value,
onValueChange = { value = it },
decorationBox = { innerTextField ->
Row(
Modifier
.background(Color.LightGray, RoundedCornerShape(percent = 30))
.padding(16.dp)
) {
if (value.text.isEmpty()) {
Text("Label")
}
innerTextField() //<-- Add this
}
},
)
If you would like to have the cursor start at the beginning of the placeholder label, put the decorationBox content inside a Box rather than a Row.

Aligning a resized TextField in Jetpack Compose

I am having problem aligning a resized TextField in Jetpack Compose for Desktop. When I resize the width of the TextField, the TextField automatically adjust itself to center position on screen. I have tried using Modify.Align and it did not work.
Can someone help? Here is my code
#Composable
fun addSales(sales: Sales,
actionChangeSales: (sales: Sales) -> Unit,
actionQuantityInc: (() -> Unit),
actionItemNameInc: (() -> Unit)){
Column{
TextField(
value = sales.itemName,
textStyle = TextStyle(color = Color.DarkGray),
onValueChange = {
actionChangeSales(Sales(itemName = it))
actionItemNameInc.invoke()
},
label = { Text("Item name")}
)
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = roundQuantity(sales.quantitySold),
textStyle = TextStyle(color = Color.DarkGray),
onValueChange = {
actionChangeSales(Sales(quantitySold = getDoubleFromEditText(it)))
actionQuantityInc.invoke()
},
label = { Text("Quantity")},
modifier = Modifier.width(120.dp)
)
}
}
As a workaround, try to wrap OutlinedTextField with Box and apply the width modifier there:
Box(modifier = Modifier.width(120.dp)) {
OutlinedTextField(
value = "123456789",
textStyle = TextStyle(color = Color.DarkGray),
onValueChange = {},
label = { Text("Quantity") },
)
}
You have to wrap them in a Column again.
Pseudo code as below
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifiler.fillMaxWidth() // needed so it knows the full width to center the content within it
) {
// This wraps your content and centers it
Column( horizontalAlignment = Alignment.Start ){
// This wraps and aligns the content to the left/start
// place your content here
}
}