Search code examples
androidandroid-jetpack-composeiconbutton

How to place hanging icon in upper right corner of Card composable


How can I achieve the effect shown below in the picture on a Card composable, with the X icon, for instance, hanging in the upper right corner? I don't want the rounded corners nor the black background, just the icon hanging in the upper right corner of the Card. I couldn't achieve this despite several attempts.

enter image description here

Original Code on SO

Box(
    modifier = Modifier
        .background(LightGray)
        .padding(16.dp)
        .size(88.dp),
    contentAlignment = Alignment.TopEnd
) {
    Image(
        painter = painterResource(
            id = R.drawable.ic_launcher_foreground,
        ),
        contentDescription = "",
        modifier = Modifier
            .align(Alignment.Center)
            .clip(RoundedCornerShape(16.dp))
            .background(Black)
            .size(80.dp),
        contentScale = ContentScale.Crop,
    )
    IconButton(
        onClick = {},
        modifier = Modifier
            .clip(CircleShape)
            .background(White)
            .align(Alignment.TopEnd)
            .size(16.dp)
    ) {
        Icon(
            imageVector = Icons.Rounded.Close,
            contentDescription = "",
        )
    }
}

Possible Code Structure?

Box(...) {

    Card(...) {
        Image(...) {
        }
    }
    
    IconButton(...) {
        Icon(...) {
        }
    }
        
}

Solution

  • You can do it in many ways. One of them is using Modifier.offset{}, another one using Modifier.graphicsLayer{} and setting translationX and translationY params, or Layout that places your Icon based on Image Composables.

    @Composable
    private fun MyIconBox() {
    
        val iconSize = 24.dp
        val offsetInPx = LocalDensity.current.run { (iconSize / 2).roundToPx() }
    
        Box(modifier = Modifier.padding((iconSize / 2))) {
    
            Card {
                Image(
                    modifier = Modifier.size(200.dp),
                    painter = painterResource(id = R.drawable.landscape4),
                    contentDescription = null,
                    contentScale = ContentScale.FillBounds
                )
            }
    
            IconButton(
                onClick = {},
                modifier = Modifier
                    .offset {
                        IntOffset(x = +offsetInPx, y = -offsetInPx)
                    }
                    .clip(CircleShape)
                    .background(White)
                    .size(iconSize)
                    .align(Alignment.TopEnd)
            ) {
                Icon(
                    imageVector = Icons.Rounded.Close,
                    contentDescription = "",
                )
            }
        }
    }
    

    Result

    enter image description here