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)?
Related
I have been doing dictionary app for a while. when I delete dictionary snackBar shows and writes dictionary is deleted but there is a floating action button and when the snackBar appears on the screen ,the snackbar appears above the floating action button, I don't want it to appear on it. It just stays on the screen for 1-2 seconds. I want the floating action button and snackbar to appear on top of each other. I couldn't adapt this to my own code. How can I do it ? I will share my code and image
CreateYourOwnDictionaryScreen
#Composable
fun CreateYourOwnDictionaryScreen(
navController: NavController,
viewModel: CreateYourOwnDictionaryViewModel = hiltViewModel()
) {
val scaffoldState = rememberScaffoldState()
val state = viewModel.state.value
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
backgroundColor = bar,
title = {
androidx.compose.material3.Text(
text = "your dictionaries",
modifier = Modifier.fillMaxWidth(),
color = Color.White,
fontSize = 22.sp
)
},
navigationIcon = {
IconButton(onClick = {
navController.navigate(Screen.MainScreen.route)
}) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = "Go Back"
)
}
}
)
},
floatingActionButtonPosition = FabPosition.Center,
floatingActionButton = {
FloatingActionButton(
onClick = { navController.navigate(Screen.CreateDicScreen.route) },
backgroundColor = bar,
) {
Icon(Icons.Filled.Add, "fab")
}
}
) {
Box(modifier = Modifier.background(MaterialTheme.colors.background)) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
items(state.dictionaries) { dictionary ->
CreateYourOwnDictionaryItem(
dictionary = dictionary,
modifier = Modifier
.fillMaxWidth()
.clickable {
},
onDeleteClick = {
viewModel.onEvent(
CreateYourOwnDictionaryEvents.DeleteDictionary(dictionary)
)
scope.launch {
val result = scaffoldState.snackbarHostState.showSnackbar(
message = "dictionary is deleted",
actionLabel = "Undo",
duration = SnackbarDuration.Short
)
}
},
onEditClick = {
})
}
}
}
}
}
}
Image
I'm afraid this is difficult in Compose, you can dig the ScaffoldLayout and you'll find this code block.
val snackbarOffsetFromBottom = if (snackbarHeight != 0) {
snackbarHeight + (fabOffsetFromBottom ?: bottomBarHeight)
} else {
0
}
Scaffold will always offset the snackbar on top of a fab or a bottombar
And based on the answer in this post regarding material specs
This is specifically one of the "Don't" examples from the Material guidelines: https://material.io/components/snackbars#behavior
Making sure visual elements don't move out from underneath (say, when users are about to tap the FAB) is one of the key points to making a predictable UI
Also based on the Material Guidelines
Consecutive snackbars should appear above persistent bottom navigation
Given the following code:
#Composable
fun CustomBar(title: String, onBackPressed: (() -> Unit)? = null) {
TopAppBar(
title = {
Text(
title,
style = TextStyle(
fontFamily = appFontFamily,
fontSize = 24.sp,
fontWeight = FontWeight(600)
)
)
},
navigationIcon = {
if (onBackPressed != null) {
IconButton(onClick = { onBackPressed() }) {
Icon(
painterResource(id = drawable.ic_topbar_back),
contentDescription = null
)
}
}
},
backgroundColor = Color.White,
elevation = 0.dp,
contentColor = MaterialTheme.colors.primary
)
}
My intention is to:
Create a reusable component to add custom TopAppBar in my application
I need to provide a title to all bars
I optionally can send a callback to react to back presses, if the callback is not null then I want to show the back icon, if the callback is null then no navigationIcon must be rendered
The above code works. The only problem is that if I send a null callback, an empty space is rendered as if Compose is leaving space for a navigationIcon.
What I want to achieve: if I send the parameter onBackPressed as NULL then it should be equals as setting navigationIcon to NULL when creating the TopAppBar.
How can I achieve that? Many Thanks.
navigationIcon is nullable. If you don't want your TopAppBar to have a navigation icon, you have to pass null. Currently, you always pass a non null composable function, which is empty if onBackPressed is null. You have to move your if condition one level up:
navigationIcon = if (onBackPressed == null) null else {
{
IconButton(onClick = onBackPressed) {
Icon(
painterResource(id = drawable.ic_topbar_back),
contentDescription = null
)
}
}
}
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.
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.
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
}
}