Reputation: 542
I was developing some app in jetpack compose, and I get into the issue of trying to add an onClick event to some custom component and doesn't works, due to the onClickk method is not been called.
Here the way I'm try to add the on click:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DashboardScreen(
context: Context,
navController: NavController,
dashboardViewModel: DashboardViewModel,
authViewModel: AuthViewModel,
) {
val list = listOf(
DashboardItem(R.drawable.baseline_payment_24, context.getString(R.string.sellTitle)),
DashboardItem(R.drawable.baseline_credit_score_24, context.getString(R.string.preCheck)),
DashboardItem(R.drawable.baseline_money_24, context.getString(R.string.price)),
DashboardItem(R.drawable.twotone_list_alt_24, context.getString(R.string.list))
)
... some code
Theme {
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier.padding(top = 16.dp)
) {
LazyVerticalGrid(
modifier = Modifier
.fillMaxSize()
.padding(end = 16.dp),
columns = GridCells.Fixed(2),
verticalArrangement = Arrangement.Top,
horizontalArrangement = Arrangement.Center
) {
items(list.size) { index ->
DashboardComponent(
item = list[index],
modifier = Modifier
.padding(paddingValues)
.background(Color.White)
.clickable {
setOnClick(
list,
index,
context,
dashboardViewModel,
navController
)
}
)
}
}
}
private fun setOnClick(
list: List<DashboardItem>,
index: Int,
context: Context,
dashboardViewModel: DashboardViewModel,
navController: NavController,
) {
when (list[index].title) {
context.getString(R.string.sellTitle) -> {
dashboardViewModel.setIsPreCheck(false)
navController.navigate(Screens.Sell.route)
}
context.getString(R.string.preCheck) -> {
dashboardViewModel.setIsPreCheck(true)
navController.navigate(Screens.Sell.route)
}
context.getString(R.string.list) -> {
navController.navigate(Screens.TransactionList.route)
}
context.getString(R.string.price) -> {
navController.navigate(Screens.ListProducts.route)
}
}
}
here is my UI which do nothing:
I've found the onClick event is not been called when I try to debug the app, so I guess this solution doesn't work.
Do you know some way to add on click into a list of components which actually works.
Thanks in advance !
[EDIT]
Add DashboardComponent.kt
@Composable
fun DashboardComponent(
modifier: Modifier,
item: DashboardItem,
) {
CepsaStandaloneAppTheme {
Card(
modifier = modifier
.size((LocalConfiguration.current.screenWidthDp.dp)/3),
colors = CardDefaults.cardColors(
containerColor = Color.White
),
elevation = CardDefaults.cardElevation(8.dp),
shape = RoundedCornerShape(10),
) {
Row(
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.Center,
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize(),
) {
Icon(
painter = painterResource(id = item.icon),
contentDescription = "icon",
tint = PrimaryColor,
modifier = Modifier.size(50.dp)
)
Text(
text = item.title,
color = PrimaryColor,
fontSize = 24.sp
)
}
}
}
}
}
[Solution]
Finally I get into a working solution adding a Box around the content of my Card in DashboardComponent, and passing the onClick as argument:
DashboardComponent.kt
@Composable
fun DashboardComponent(
modifier: Modifier,
item: DashboardItem,
onClick: () -> Unit
) {
CepsaStandaloneAppTheme {
Card(
modifier = modifier
.size((LocalConfiguration.current.screenWidthDp.dp)/3),
colors = CardDefaults.cardColors(
containerColor = Color.White
),
elevation = CardDefaults.cardElevation(8.dp),
shape = RoundedCornerShape(10),
) {
Box(modifier = Modifier
.fillMaxSize()
.clickable { onClick.invoke() }) {
Row(
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.Center,
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize(),
) {
Icon(
painter = painterResource(id = item.icon),
contentDescription = "icon",
tint = PrimaryColor,
modifier = Modifier.size(50.dp)
)
Text(
text = item.title,
color = PrimaryColor,
fontSize = 24.sp
)
}
}
}
}
}
}
Upvotes: 3
Views: 4087
Reputation: 7278
The problem is that the clickable
modifier is applied to Card
. Card
delegates to Surface
and Surface
effectively disables clickable
modifier by applying Modifier.pointerInput(Unit) {}
at the end of the modifier chain. You can see that here: Surface.kt
Why? Because applying the clickable
modifier yourself wouldn't work as expected - Card/Surface
has a Shape
that won't be applied to the clickable modifier, so the ripple effect (indication) wouldn't respect rounded corners and it will look ugly. Because of that, clickable
modifier is disabled and there are overloads for Card
and Surface
that have onClick
argument - you should use these overloads.
So instead of this:
Card(modifier = Modifier.clickable {})
you do this:
Card(onClick = {})
Upvotes: 11