how to add numbers near the icon in android jetapck compose, i have attached snap below like that.please help me to solve the problem.
You can use this code below:
#Composable
fun IconsRow() {
// Update the texts according to your logic
var favoriteText by remember { mutableStateOf("34") }
var repeatText by remember { mutableStateOf("12") }
var chatText by remember { mutableStateOf("12") }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly
) {
IconWithNearbyText(
text = chatText,
icon = Icons.Outlined.ChatBubbleOutline
)
IconWithNearbyText(
text = repeatText,
icon = Icons.Outlined.Repeat
)
IconWithNearbyText(
text = favoriteText,
icon = Icons.Outlined.FavoriteBorder
)
}
}
}
#Composable
fun IconWithNearbyText(
text: String,
icon: ImageVector
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(2.dp)
) {
Icon(imageVector = icon, contentDescription = null)
Text(text = text)
}
}
You can use the BadgedBox.
Use the offset modifier to change the position of the badge, and the containerColor to change the background color.
In M2 the background color is defined by the backgroundColor attribute.
BadgedBox(
badge = {
Badge(
modifier = Modifier.offset(y=10.dp),
containerColor=LightGray
){
val badgeNumber = "8"
Text(
badgeNumber,
modifier = Modifier.semantics {
contentDescription = "$badgeNumber new notifications"
}
)
}
}) {
Icon(
Icons.Filled.Star,
contentDescription = "Favorite"
)
}
Related
I want to align two texts to be centered vertically to the start of the TaskCard. It works as intended if there are two texts present. However, if there is only one and the other one is null the null one will completely disappear, but will still leave a blank space in its place. How do I get rid of it so I can properly align the text?
#Composable
fun TaskCard(
modifier: Modifier = Modifier,
task: Task,
viewModel: TaskListViewModel = hiltViewModel()
) {
Card(
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant
), modifier = modifier.padding()
) {
Surface(
color = MaterialTheme.colorScheme.surfaceVariant, modifier = modifier
) {
Row(
verticalAlignment = Alignment.CenterVertically, modifier = modifier.padding(12.dp)
) {
Column(
modifier = modifier
.weight(1f)
.padding(12.dp)
) {
task.categoryName?.let {
Text(
text = it,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.primary
)
}
Text(
text = task.taskName,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onBackground,
)
}
IconButton(
onClick = { viewModel.onEvent(TaskListEvent.OnEditTask(task)) },
modifier = modifier.size(36.dp)
) {
Icon(
imageVector = Icons.Rounded.Edit,
contentDescription = "Edit",
modifier = modifier.padding(horizontal = 2.dp),
tint = MaterialTheme.colorScheme.onBackground
)
}
IconButton(
onClick = { }, modifier = modifier.size(36.dp)
) {
Icon(
imageVector = Icons.Rounded.Notifications,
contentDescription = "Notifications",
modifier = modifier.padding(horizontal = 2.dp),
tint = MaterialTheme.colorScheme.onBackground
)
}
}
}
}
}
As Gabriele Mariotti suggested I've changed the condition under which the code is executed.
from:
task.categoryName?.let
to:
if (!task.categoryName.isNullOrEmpty())
ISSUE
I am trying to align the text Enable Notifications and the switch on the same line. If I were to use XML layouts, then I would have gone with constraint layout, but I am trying to figure out how to do this with Compose.
SET UP
#Composable
fun Settings() {
val viewModel: SettingsViewModel = viewModel()
val uiState: SettingsState = viewModel.uiState.collectAsState().value
SettingsList(uiState = uiState, viewModel)
}
#Composable
fun SettingsList(uiState: SettingsState, viewModel: SettingsViewModel, modifier: Modifier = Modifier) {
val scaffoldState = rememberScaffoldState()
Scaffold(
modifier = Modifier, scaffoldState = scaffoldState,
backgroundColor = MaterialTheme.colors.background,
topBar = {
TopAppBar(
modifier = Modifier.semantics {
heading()
},
backgroundColor = MaterialTheme.colors.surface,
contentPadding = PaddingValues(start = 12.dp)
) {
Icon(
tint = MaterialTheme.colors.onSurface,
imageVector = Icons.Default.ArrowBack,
contentDescription = stringResource(id = R.string.header_settings_back)
)
Spacer(modifier = modifier.width(16.dp))
Text(
text = stringResource(id = R.string.header_settings),
fontSize = 18.sp,
color = MaterialTheme.colors.onSurface
)
}
}
) {
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.verticalScroll(scrollState).padding(paddingValues = it)
) {
NotificationSettingsComposable(uiState.notificationsEnabled, {
viewModel.toggleNotificationSettings()
}, Modifier.fillMaxWidth())
}
}
}
#Composable
fun NotificationSettingsComposable(checked: Boolean, onCheckedChanged: (Boolean) -> Unit, modifier: Modifier = Modifier) {
Surface(modifier = modifier.padding(12.dp)) {
Row {
Text(
text = stringResource(id = R.string.body_enable_notifications), fontSize = 16.sp,
color = MaterialTheme.colors.onSurface,
)
Switch(checked = checked, onCheckedChange = onCheckedChanged, modifier = Modifier.align(Alignment.Top))
}
}
}
However the text and the switch are not being aligned on the same line.
DESIRED OUTCOME
The text and the switch should be aligned on the same line as shown in this picture.
This is what I am getting
What I want to achieve
Add verticalAlignment = Alignment.CenterVertically in the Row:
Something like:
Row(
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "Enable Notification", fontSize = 16.sp,
)
Switch(
checked = checkedState.value,
onCheckedChange = { checkedState.value = it }
)
}
I am new in jetpack compose, and I am try to learn it, so I have simple onboarding screen in jetpack compose, when I update project to jetpack compose 1.1.1 , "Next" button not working for onboarding screen to scroll horizontally. it was working when I use jetpack compose 1.0.0 version, I do not know what change in new version, any idea?
#ExperimentalPagerApi
#Composable
fun OnBoardScreen() {
val scaffoldState = rememberScaffoldState()
val onBoardViewModel : OnBoardViewModel = viewModel()
val context = LocalContext.current
val currentPage = onBoardViewModel.currentPage.collectAsState()
Toast.makeText(context, "${currentPage.value}", Toast.LENGTH_SHORT).show()
val pagerState = rememberPagerState(
pageCount = onBoardItem.size,
initialOffscreenLimit = 2,
initialPage = 0,
infiniteLoop = false
)
Scaffold(
modifier = Modifier.fillMaxSize(),
scaffoldState = scaffoldState
) {
Surface(
modifier = Modifier.fillMaxSize()
) {
LaunchedEffect(scaffoldState.snackbarHostState){
pagerState.animateScrollToPage(
page = currentPage.value
)
}
Box(
modifier = Modifier
.fillMaxWidth()
.background(Gray200)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
HorizontalPager(
state = pagerState
) { page ->
Column(
modifier = Modifier
.padding(top = 65.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = onBoardItem[page].image),
contentDescription = "OnBoardImage",
modifier = Modifier
.size(250.dp)
)
Text(
text = onBoardItem[page].title,
modifier = Modifier
.padding(top = 50.dp),
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)
Text(
text = onBoardItem[page].desc,
modifier = Modifier
.padding(30.dp),
color = Color.White,
fontSize = 18.sp,
textAlign = TextAlign.Center
)
}
}
PagerIndicator(onBoardItem.size, pagerState.currentPage)
}
Box(
modifier = Modifier
.align(Alignment.BottomCenter)
) {
Row(
modifier = Modifier
.padding(bottom = 20.dp)
.fillMaxWidth(),
horizontalArrangement = if (pagerState.currentPage != 2 ) {
Arrangement.SpaceBetween
} else {
Arrangement.Center
}
) {
if (pagerState.currentPage == 2) {
OutlinedButton(
onClick = {
Toast.makeText(context, "Start the Screen", Toast.LENGTH_SHORT).show()
},
shape = RoundedCornerShape(45.dp)
) {
Text(
text = "Get Started",
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 40.dp
),
color = Color.Black
)
}
} else {
Text(
text = "Skip",
color = Color.White,
modifier = Modifier.padding(start = 20.dp),
fontSize = 18.sp,
fontWeight = FontWeight.Medium
)
Text(
text = "Next",
color = Color.White,
modifier = Modifier
.clickable {
onBoardViewModel.setCurrentPage(pagerState.currentPage + 1)
}
.padding(end = 20.dp),
fontSize = 18.sp,
fontWeight = FontWeight.Medium
)
}
}
}
}
}
}
}
It looks like you expect these lines to scroll the pager every time you change the value of currentPage:
LaunchedEffect(scaffoldState.snackbarHostState) {
pagerState.animateScrollToPage(
page = currentPage.value
)
}
But scaffoldState.snackbarHostState in this scope is a static value, which means LaunchedEffect is not gonna be relaunched.
One option is to pass currentPage instead, but also, as your currentPage is backed by flow, it's cleaner to collect it:
LaunchedEffect(Unit) {
onBoardViewModel.currentPage
.collect {
pagerState.animateScrollToPage(
page = currentPage.value
)
}
}
p.s.
Also, when you need to make a text button, instead of adding clickable to the Text you can use TextButton:
TextButton(
onClick = {
}
) {
Text(/*...*/)
}
So these are my Project Versions:
val compose_version by extra("1.0.0-beta07")
val kotlin_version by extra("1.4.32")
val hilt_version by extra("2.36")
So I have a LazyColum which displays a custom composable card list:
package com.veloce.montageservice.ui.composables
// Here are imports but its too much code for stackoverflow
#Composable
fun SimpleCard(
imageVector: ImageVector,
title: String,
description: String,
#DrawableRes trailingButton: Int? = null,
clickable: () -> Unit
) {
Card(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
.clickable {
clickable()
},
border = BorderStroke(
(0.5).dp,
brush = Brush.horizontalGradient(
colors = listOf(
MaterialTheme.colors.primary, MaterialTheme.colors.primaryVariant
)
)
),
elevation = 5.dp
// backgroundColor = Color.Gray
) {
Row(
modifier = Modifier.padding(8.dp),
horizontalArrangement = if (trailingButton != null) Arrangement.SpaceEvenly else Arrangement.Start
) {
Surface(
shape = CircleShape,
modifier = Modifier.size(50.dp),
color = MaterialTheme.colors.primaryVariant
) {
Icon(
modifier = Modifier.padding(4.dp),
imageVector = imageVector,
contentDescription = "Icon of a building",
tint = Color.White
)
}
Column(
modifier = Modifier.padding(8.dp),
verticalArrangement = Arrangement.SpaceEvenly
) {
Text(
title,
fontWeight = FontWeight.Bold
)
Text(description)
}
trailingButton?.let {
Surface(
shape = CircleShape,
modifier = Modifier.size(35.dp),
color = MaterialTheme.colors.primaryVariant
) {
Icon(
modifier = Modifier.padding(4.dp),
imageVector = ImageVector.vectorResource(id = it),
contentDescription = "Icon of a building",
tint = Color.White
)
}
}
}
}
}
And this should be clickable. It was, but now it's not anymore and I didn't have changed anything in this composable.
Has anyone an idea what went wrong? The scroll function of LazyColumnworks perfectly fine, it's just that I can't click it anymore from one day to the other.
In compose 1.0.0-beta08 there was a breaking API Change (https://developer.android.com/jetpack/androidx/releases/compose-material) which causes the clickable modifier to be ignored. You have to use the onClickparameter of Card instead:
Card(onClick = { count++ }) {
Text("Clickable card content with count: $count")
}
I have the following composable function to build a Chip:
#Composable
fun CategoryChip(
category: String,
isSelected: Boolean = false,
onSelectedCategoryChanged: (String) -> Unit,
onExecuteSearch: () -> Unit
) {
Surface(
modifier = Modifier.padding(end = 8.dp, bottom = 8.dp),
elevation = 8.dp,
shape = RoundedCornerShape(16.dp),
color = when {
isSelected -> colorResource(R.color.teal_200)
else -> colorResource(R.color.purple_500)
}
) {
Row(modifier = Modifier
.toggleable(
value = isSelected,
onValueChange = {
onSelectedCategoryChanged(category)
onExecuteSearch()
}
)) {
Text(
text = category,
style = MaterialTheme.typography.body2,
color = Color.White,
modifier = Modifier.padding(8.dp)
)
}
}
}
This creates the following chip:
But what I am trying to achieve is the following:
Is it possible to create a shape like that with Jetpack Compose?
Starting with M2 1.2.0-alpha02 you can use the Chip or FilterChip composable:
Chip(
onClick = { /* Do something! */ },
border = BorderStroke(
ChipDefaults.OutlinedBorderSize,
Color.Red
),
colors = ChipDefaults.chipColors(
backgroundColor = Color.White,
contentColor = Color.Red
),
leadingIcon = {
Icon(
Icons.Filled.Settings,
contentDescription = "Localized description"
)
}
) {
Text("Change settings")
}
With M3 (androidx.compose.material3) you can use one of these options:
AssistChip
FilterChip
InputChip
SuggestionChip
Something like:
AssistChip(
onClick = { /* Do something! */ },
label = { Text("Assist Chip") },
leadingIcon = {
Icon(
Icons.Filled.Settings,
contentDescription = "Localized description",
Modifier.size(AssistChipDefaults.IconSize)
)
}
)
Yes, all you have to do is add a border to your surface.
Surface(
modifier = Modifier.padding(end = 8.dp, bottom = 8.dp),
elevation = 8.dp,
shape = RoundedCornerShape(16.dp),
border = BorderStroke(
width = 1.dp,
color = when {
isSelected -> colorResource(R.color.teal_200)
else -> colorResource(R.color.purple_500)
}
)
)
Building on Code Poet's answer i wanted to show how to do a Material Chip with background color:
#Composable
fun buildChip(label: String, icon: ImageVector? = null) {
Box(modifier = Modifier.padding(8.dp)) {
Surface(
elevation = 1.dp,
shape = MaterialTheme.shapes.small,
color = Color.LightGray
) {
Row(verticalAlignment = Alignment.CenterVertically) {
if (icon != null) Icon(
icon,
modifier = Modifier
.fillMaxHeight()
.padding(horizontal = 4.dp)
)
Text(
label,
modifier = Modifier.padding(8.dp),
style = MaterialTheme.typography.button.copy(color = Color.DarkGray)
)
}
}
}
}
Simply use ChipDefaults.outlinedBorder and Defaults.outlinedChipColors():
Chip(
onClick = {},
border = ChipDefaults.outlinedBorder,
colors = ChipDefaults.outlinedChipColors(),
) {
Text(
text = "Trends",
)
}
compose version 1.2.1 , kotlinCompilerExtensionVersion 1.3.1
Also add accompanist Flow library
implementation
"com.google.accompanist:accompanist-flowlayout:0.26.4-beta"
We will use SuggestionChip composable function to create chips.
#Composable
fun SuggestionChipLayout() {
val chips by remember { mutableStateOf(listOf("India", "France", "Spain","Netherland","Austarlia","Nepal")) }
var chipState by remember { mutableStateOf("") }
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "Suggestion Chip Example")
Spacer(modifier = Modifier.height(20.dp))
FlowRow(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp),
mainAxisSpacing = 16.dp,
crossAxisSpacing = 16.dp,
) {
chips.forEach {
SuggestionChipEachRow(chip = it, it == chipState) { chip ->
chipState = chip
}
}
}
}
}
#OptIn(ExperimentalMaterial3Api::class)
#Composable
fun SuggestionChipEachRow(
chip: String,
selected: Boolean,
onChipState: (String) -> Unit
) {
SuggestionChip(onClick = {
if (!selected)
onChipState(chip)
else
onChipState("")
}, label = {
Text(text = chip)
},
border = SuggestionChipDefaults.suggestionChipBorder(
borderWidth = 1.dp,
borderColor = if (selected) Color.Transparent else PurpleGrey40
),
modifier = Modifier.padding(horizontal = 16.dp),
colors = SuggestionChipDefaults.suggestionChipColors(
containerColor = if (selected) Purple80 else Color.Transparent
),
shape = RoundedCornerShape(16.dp)
)
}
Filter Chips: In filter chip we can select multiple items at a time
compose version 1.2.1 , kotlinCompilerExtensionVersion 1.3.1 Also add accompanist Flow library
implementation
"com.google.accompanist:accompanist-flowlayout:0.26.4-beta"
we will use FilterChip composable function to create Filter Chip
#SuppressLint("MutableCollectionMutableState")
#Composable
fun FilterChipLayout() {
val originalChips by remember {
mutableStateOf(
listOf(
"chip1",
"chip2",
"chip3",
"chip4",
"chip5"
)
)
}
val temp: Set<Int> = emptySet()
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "Filter Chip Example")
Spacer(modifier = Modifier.height(20.dp))
FilterChipEachRow(chipList = originalChips, tempList = temp)
}
}
#OptIn(ExperimentalMaterial3Api::class)
#Composable
fun FilterChipEachRow(
chipList: List<String>,
tempList: Set<Int>
) {
var multipleChecked by rememberSaveable { mutableStateOf(tempList) }
FlowRow(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp),
mainAxisSpacing = 16.dp,
crossAxisSpacing = 16.dp,
) {
chipList.forEachIndexed { index, s ->
FilterChip(selected = multipleChecked.contains(index), onClick = {
multipleChecked = if (multipleChecked.contains(index))
multipleChecked.minus(index)
else
multipleChecked.plus(index)
}, label = {
Text(text = s)
},
border = FilterChipDefaults.filterChipBorder(
borderColor = if (!multipleChecked.contains(index)) PurpleGrey40 else Color.Transparent,
borderWidth = if (multipleChecked.contains(index)) 0.dp else 2.dp
),
shape = RoundedCornerShape(8.dp),
leadingIcon = {
(if (multipleChecked.contains(index)) Icons.Default.Check else null)?.let {
Icon(
it,
contentDescription = ""
)
}
}
)
}
}
}