This can be achieved using Layout and placeable.placeWithLayer and Modifier.layoutId to select which Composable is to be used with default alpha as.
This is a custom Column, you can customize Layout as required, purpose is to show Modifier.layoutId
usage and Placeable.placeRelativeWithLayer
to apply any desired graphic layer property to specific Composable in layout phase.
Result

Usage
MyLayout(
alpha = .5f
) {
Text("Default Alpha", fontSize = 20.sp)
Text("Default Alpha", fontSize = 20.sp)
Text("Custom Alpha", fontSize = 20.sp), modifier = Modifier.layoutId("full_alpha"))
Text("Default Alpha", fontSize = 20.sp)
Image(painter = painterResource(id = R.drawable.landscape5), contentDescription = "")
}
Implementation
@Composable
private fun MyLayout(
modifier: Modifier = Modifier,
alpha: Float = 1f,
content: @Composable () -> Unit
) {
val measurePolicy = MeasurePolicy { measurables, constraints ->
val fullAlphaIndex = measurables.indexOfFirst {
it.layoutId == "full_alpha"
}
val placeablesWidth = measurables.map { measurable ->
measurable.measure(constraints)
}
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val width =
if (hasBoundedWidth && hasFixedWidth) constraints.maxWidth
else placeablesWidth.maxOf { it.width }
val height = placeablesWidth.sumOf {
it.height
}
var posY = 0
layout(width, height) {
placeablesWidth.forEachIndexed { index, placeable ->
placeable.placeRelativeWithLayer(0, posY) {
if (index == fullAlphaIndex) {
this.alpha = 1f
} else {
this.alpha = alpha
}
}
posY += placeable.height
}
}
}
Layout(
modifier = modifier,
content = content,
measurePolicy = measurePolicy
)
}
If you wish to create a Row you need to place items one after other horizontally instead of increasing y position
Result

@Composable
fun MyLayout(
modifier: Modifier = Modifier,
alpha: Float = 1f,
content: @Composable () -> Unit
) {
val measurePolicy = MeasurePolicy { measurables, constraints ->
val fullAlphaIndex = measurables.indexOfFirst {
it.layoutId == "full_alpha"
}
val placeablesWidth = measurables.map { measurable ->
measurable.measure(
constraints.copy(
minWidth = 0,
maxWidth = Constraints.Infinity,
minHeight = 0,
maxHeight = Constraints.Infinity
)
)
}
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val hasBoundedHeight = constraints.hasBoundedHeight
val hasFixedHeight = constraints.hasFixedHeight
val width =
if (hasBoundedWidth && hasFixedWidth) constraints.maxWidth
else placeablesWidth.sumOf { it.width }.coerceAtMost(constraints.maxWidth)
val height =
if (hasBoundedHeight && hasFixedHeight) constraints.maxHeight
else placeablesWidth.maxOf { it.height }.coerceAtMost(constraints.maxHeight)
var posX = 0
layout(width, height) {
placeablesWidth.forEachIndexed { index, placeable ->
placeable.placeRelativeWithLayer(posX, 0) {
if (index == fullAlphaIndex) {
this.alpha = 1f
} else {
this.alpha = alpha
}
}
posX += placeable.width
}
}
}
Layout(
modifier = modifier,
content = content,
measurePolicy = measurePolicy
)
}
Same usage but this time with Icons
MyLayout(
modifier = Modifier.drawChecker(),
alpha = .4f
) {
Icon(
imageVector = Icons.Default.NotificationsActive,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.background(Color.Red, CircleShape)
.size(100.dp)
.padding(10.dp)
)
Icon(
imageVector = Icons.Default.NotificationsActive,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.background(Color.Red, CircleShape)
.size(100.dp)
.padding(10.dp)
)
Icon(
imageVector = Icons.Default.NotificationsActive,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.layoutId("full_alpha")
.background(Color.Red, CircleShape)
.size(100.dp)
.padding(10.dp)
)
Icon(
imageVector = Icons.Default.NotificationsActive,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.background(Color.Red, CircleShape)
.size(100.dp)
.padding(10.dp)
)
}
Checker Modifier if anyone wonders is as
fun Modifier.drawChecker() = this.then(
drawBehind {
val width = this.size.width
val height = this.size.height
val checkerWidth = 10.dp.toPx()
val checkerHeight = 10.dp.toPx()
val horizontalSteps = (width / checkerWidth).toInt()
val verticalSteps = (height / checkerHeight).toInt()
for (y in 0..verticalSteps) {
for (x in 0..horizontalSteps) {
val isGrayTile = ((x + y) % 2 == 1)
drawRect(
color = if (isGrayTile) Color.LightGray else Color.White,
topLeft = Offset(x * checkerWidth, y * checkerHeight),
size = Size(checkerWidth, checkerHeight)
)
}
}
}
)