https://kotlinlang.org logo
#compose
Title
# compose
a

andrew

08/24/2022, 2:34 PM
quick q, is there a easy way to make sure a border is drawn outside of the box in compose
I know order matters and such, but borders are still drawn inside of the box
c

Chris Sinco [G]

08/24/2022, 2:43 PM
cc @Nader Jawad
a

andrew

08/24/2022, 2:45 PM
Just for context
n

Nader Jawad

08/24/2022, 7:30 PM
Borders right now are implemented as interior strokes. You could probably achieve a similar effect by growing the content and drawing a border that way using padding
a

andrew

08/24/2022, 7:53 PM
Even if its fillMaxWidth?
n

Nader Jawad

08/24/2022, 7:59 PM
Yes so you can either make a custom size modifier that adds the border width or grow the corresponding container by the border width as well and use fillMaxWidth
a

andrew

08/24/2022, 8:21 PM
Gotcha 🙂
n

Nader Jawad

08/24/2022, 8:22 PM
A future version of compose will more than likely expose a parameter to specify an interior, center or exterior stroke directly on the border modifier API and make this a bit easier. No ETA on this unfortunately
c

Chris Sinco [G]

08/24/2022, 9:42 PM
Yeah that would be great to have since that would align better with how borders are specified from designers
c

Colton Idle

05/15/2023, 3:42 AM
@andrew I basically have to make the same thing now. How'd you go about this? I'd love to be able to just add a custom clip modifier to that lock icon that knows how to clip/mask the wifi logo. lol
seems like thats not possible though?
a

andrew

05/15/2023, 1:47 PM
It's just baked into the icon itself, nothing special or dynamic about it
n

Nader Jawad

05/15/2023, 2:10 PM
In the meantime you can enlarge the size of the composable to incorporate the width of the border if you want an exterior/centered border
a

andrew

05/15/2023, 2:10 PM
I just want to clarify real quick when I say it's baked into the icon itself, I mean the lock is baked into the icon, but the backdrop is separate, and is a box
And the outer border for the container, I have a separate modifier for 🙂
n

Nader Jawad

05/15/2023, 2:14 PM
If you want to mask icons you can do a similar strategy that was done on the thread for masking out circular profile images in this thread https://kotlinlang.slack.com/archives/CJLTWPH7S/p1622156832115600?thread_ts=1622125126.047600&cid=CJLTWPH7S
c

Colton Idle

05/15/2023, 8:12 PM
@Nader Jawad yeah I tried that snippet, but in this case I need the mask/clipped part to change sizes as my item changes size and so if I could just use some imaginary api of
.border(1.dp, BorderStyle.Clip)
on my icon it'd be clutch. And thats just because the
Copy code
drawCircle(
                Color.Black,
                size.minDimension / 2,
                size.center,
                style = stroke,
                blendMode = BlendMode.Clear
            )
doesn't scale correctly with my image. While a border works just fine if I set the border to white. But if I use a different background color then the effect is broken. 😅
n

Nader Jawad

05/15/2023, 8:35 PM
Do you have a mock/screenshot of what you are trying to build? Generally speaking you can mask out content by leveraging an off screen layer with corresponding blend modes.
c

Colton Idle

05/15/2023, 8:38 PM
I can DM you the mock
n

Nader Jawad

05/16/2023, 7:53 PM
Just fyi here's another example that shows how to apply a similar masking technique to add a badge to an icon (or any composable)
Copy code
Box(modifier = Modifier.fillMaxSize()
        .wrapContentSize(Alignment.Center)
        // Leverage an offscreen rasterization of the box composable so we can use use the clear
        // blend mode to erase/mask out some pixels without clearing the original destination pixels
        .graphicsLayer{ compositingStrategy = CompositingStrategy.Offscreen }
    ) {
        Image(
            Icons.Outlined.AccountCircle,
            "ProfileImage",
            Modifier.size(48.dp).padding(top = 5.dp),
            contentScale = ContentScale.FillBounds
        )
        Text(text = "2",
            color = Color.White,
            textAlign = TextAlign.Center,
            modifier = Modifier.align(Alignment.TopEnd).size(20.dp).drawWithContent {
            // Color doesn't matter here but clear out a circle of pixels slightly larger
            // than the area of the text composable
            drawCircle(color = Color.Black, blendMode = BlendMode.Clear, radius = this.size.minDimension / 2 + 5f)
            // Draw a red background circle smaller than the area that was masked out above
            drawCircle(color = Color.Red)
            drawContent()
        })
    }
This generates the following:
2 Views