1

I would like to know if there some way to specify to Jetpack Compose plugin to remove default elevation from Image component, or the only wy is rebuild the image asset.

I have this:

Image(
                    painter = painterResource(id = if(sessionToken.isNotEmpty()) R.drawable.ic_disa_logo else R.drawable.ic_cepsa_logo),
                    contentDescription = "login_logo",
                    modifier = Modifier
                        .align(CenterHorizontally)
                        .fillMaxWidth()


Which show like this

enter image description here

As you can check the image have a elevatioon which I'm not adding to the component, so Should I recreate the asset, or is there some way to remove it.

Thanks in advance !

[EDIT]

As the suggestion I try to use a custom shape to hide the border of the image make an implementation of the solution like this:

 val offset = with(LocalDensity.current){
        4.dp.toPx()
    }


    val customCircleShape = GenericShape{ size: Size, layoutDirection: LayoutDirection ->
        addOval(
            Rect(
                offset = Offset(
                    offset, offset
                ),
                size = Size(
                    width = size.width - 2 * offset,
                    height = size.height - 2 * offset
                )
            )
        )
    }
Column(
                verticalArrangement = Arrangement.Top,
                modifier = Modifier
                    .clip(customCircleShape)
                    .shadow(4.dp, CircleShape)
                    .size(60.dp)
                    .background(Color.White)
            ) {
                Image(
                    painter = painterResource(id = if (sessionToken.isNotEmpty()) R.drawable.ic_disa_logo else R.drawable.ic_cepsa_logo),
                    contentDescription = "login_logo",
                    modifier = Modifier
                        .align(Alignment.CenterHorizontally)
                        .fillMaxWidth()
                        .fillMaxHeight(0.25f)
                        .border(BorderStroke(2.dp, Color.White), CircleShape)
                        .background(Color.White)
                )
            }

But the border is still showing as the firts picture I added it

What Am I missing here?

[EDIT]

Doesn't matter how big a do the circle which supose to hide the shadow, don't do it.

I add the picture i'm using as reference.

enter image description here

[SOLUTION]

I make works doing this:

val offset = with(LocalDensity.current){
        8.dp.toPx()
    }

    val customCircleShape = GenericShape { size: Size, layoutDirection: LayoutDirection ->
        addOval(
            Rect(
                offset = Offset(
                    offset, offset
                ),
                size = Size(
                    width = size.width - 2 * offset,
                    height = size.height - 2 * offset
                )
            )
        )
    }

Image(
                    painter = painterResource(id = if(sessionToken.isNotEmpty()) R.drawable.ic_disa_logo else R.drawable.ic_cepsa_logo),
                    contentDescription = "login_logo",
                    contentScale = ContentScale.FillBounds,
                    modifier = Modifier
                        .align(CenterHorizontally)
                        .padding(10.dp)
                        .background(Color.White)
                        .clip(customCircleShape)
                        .size(80.dp),

                )

enter image description here

Manuel Lucas
  • 636
  • 6
  • 17

2 Answers2

3

Since your logo can be contained inside a Circle you can do it in several ways.

1- Using a Path and clipPath function inside drawScope of Modifier.drawWithContent.

2- Creating a custom Circle shape that has smaller dimensions as in option 1 and applying Modifier.clip(customShape)

3- Using BlendMode with destination drawCircle inside Modifier.drawWithContent.

Since i don't have you logo. I created an Image that draws a red Circle with some shadow.

@Preview
@Composable
private fun MyImage() {
    Canvas(
        modifier = Modifier
            .shadow(4.dp, CircleShape)
            .size(60.dp)
            .background(Color.White)
    ) {

        drawCircle(color = Color.Red, radius = size.width / 2 - 5.dp.toPx())
    }
}

And implemented this Modifier as

@Preview
@Composable
fun Test() {
    Column(modifier = Modifier.fillMaxSize()) {

        Text(text = "Original")
        MyImage()

        Spacer(modifier = Modifier.height(10.dp))

        val path = remember {
            androidx.compose.ui.graphics.Path()
        }

        val offset = with(LocalDensity.current){
            4.dp.toPx()
        }


        val customCircleShape = GenericShape{size: Size, layoutDirection: LayoutDirection ->
            addOval(
                Rect(
                    offset = Offset(
                        offset, offset
                    ),
                    size = Size(
                        width = size.width - 2 * offset,
                        height = size.height - 2 * offset
                    )
                )
            )
        }

        Spacer(modifier = Modifier.height(10.dp))

        Text(text = "Clip with Shape")
        Box(modifier = Modifier.clip(customCircleShape)){
            MyImage()
        }
        Spacer(modifier = Modifier.height(10.dp))

        Text(text = "drawWithContent and clipPath")

        Box(
            modifier = Modifier.drawWithContent {


                if (path.isEmpty) {
                    path.addOval(
                        oval = Rect(
                            offset = Offset(
                                offset, offset
                            ),
                            size = Size(
                                width = size.width - 2 * offset,
                                height = size.height - 2 * offset
                            )
                        )
                    )
                }

                clipPath(path = path, clipOp = ClipOp.Intersect) {
                    this@drawWithContent.drawContent()

                }
            }
        ) {
            MyImage()
        }
    }
}

Result

enter image description here

The trick is to create a Rect for oval that which has offsets in both directions.

For BlendMode sample you can check out the link below. I clipped out an image and Button to squircle shape.

How to clip or cut a Composable?

Edit

With the image provided it's as

enter image description here

Only used clip with custom shape option but other options can be applied either to clip and add your custom shadow as i did.

@Preview
@Composable
private fun Test() {


    val offset = with(LocalDensity.current) {
        8.dp.toPx()
    }


    val customCircleShape = GenericShape { size: Size, layoutDirection: LayoutDirection ->
        addOval(
            Rect(
                offset = Offset(
                    offset, offset
                ),
                size = Size(
                    width = size.width - 2 * offset,
                    height = size.height - 2 * offset
                )
            )
        )
    }

    Column(
        Modifier
            .fillMaxSize()
            .padding(20.dp)
    ) {

        Text("ORIGINAL")

        Image(
            painter = painterResource(id = R.drawable.shell),
            contentDescription = null,
            contentScale = ContentScale.FillBounds,
        )

        Text("Clipped with Shape")

        Image(
            modifier = Modifier
                .border(1.dp, Color.Green)
                .clip(customCircleShape),
            painter = painterResource(id = R.drawable.shell),
            contentDescription = null,
            contentScale = ContentScale.FillBounds
        )


        Text("With Size and attached Modifier.shadow after")

        Image(
            modifier = Modifier
                .border(1.dp, Color.Green)
                .padding(10.dp)
                .shadow(6.dp, spotColor = Color.Cyan, shape = CircleShape)
                .background(Color.White)
                .clip(customCircleShape)
                .size(80.dp),
            painter = painterResource(id = R.drawable.shell),
            contentDescription = null,
            contentScale = ContentScale.FillBounds
        )
    }
}
Thracian
  • 43,021
  • 16
  • 133
  • 222
  • Thanks for your completed answer. I get a try to your guess, but still showing the border arround the image. I edit my original question adding the code – Manuel Lucas Aug 07 '23 at 14:49
  • The value i used is a fixed value that matches the shadow i added as sample. Have you tried increasing it? You clip the image from sides as much as the offset value – Thracian Aug 07 '23 at 14:59
  • And why do you add shadow again? – Thracian Aug 07 '23 at 15:01
  • If it's possible would you mind adding your image resource? Or another similar image with circle shape and elevation? – Thracian Aug 07 '23 at 15:29
  • I edit my post adding the image, and yes doesn't matter how big I do the Circle around – Manuel Lucas Aug 08 '23 at 08:04
  • It does. You should check my updated answer. I only posted with custom shape but other ones work as well. You can copy paste and try it. – Thracian Aug 08 '23 at 10:25
  • You might be not centering Image inside Column, that might be the case. If it's not centered you wouldn't be able to clip correctly especially area Bitmap is drawn is smaller than container. – Thracian Aug 08 '23 at 10:27
  • I make work changing a little bit your code. Thanks ! – Manuel Lucas Aug 08 '23 at 10:39
  • Also remember this is just an example to show that you can clip out some section of a Composable or Image. If you have an Image that is too big you should put `offset` inside shape and set it to something like `offset = size.width*0.05f` to set custom circle's radius in percentage. It might be better approach. This means you trim out 5% of image on each side instead of some predefined dp value. – Thracian Aug 08 '23 at 10:46
0

Have you considered trying to create a custom shadow effect?

modifier = Modifier
                .size(100.dp)
                .clip(CircleShape)
                .shadow(elevation = 0.dp, shape = CircleShape)
viethoang
  • 111
  • 3
  • Thanks for your coments, and yes, I've already tried doing this: .border(BorderStroke(2.dp, Color.White), CircleShape) .background(Color.White) and your code too, and doesn't works – Manuel Lucas Aug 07 '23 at 10:59