Hello guys I am using a Layout composable to imple...
# compose
j
Hello guys I am using a Layout composable to implement Animated drawer but whenever I set the background of the Layout to Transparent it become Black instead.
Copy code
Layout(
    modifier = modifier.background(Colors.Transparent),
    content = {
        drawerContents()
        content()
    }
)
But if i provide other colors, they are applied. How do i work around this. Thanks
t
You could just not include a background to the layout when the color would be transparent, right? I'm assuming your colors are variable, so this would look something like
Copy code
@Composable
fun MyLayout(
    drawerContents: @Composable () -> Unit,
    modifier: Modifier = Modifier, 
    backgroundColor: Color = Color.Transparent,
    content: @Composable () -> Unit,
) {
  val backgroundModifier = 
      if(backgroundColor != Color.Transparent) Modifier.background(backgroundColor) 
      else Modifier
  Layout(
      modifier = modifier.then(backgroundModifier),
      content = {
          drawerContents()
          content()
      }
  )
}
j
I tried that but omitting the background still has that background on it
t
Presumably you have some content behind this layout you want to see through it. Are you doing something like putting a GLSurfaceView inside it or something like that? Some wacky canvas stuff like transparent paint on hardware layers?
j
I am using the layout for animate drawer. It's content is a BottomSheetScaffold whose shape is rounded at the top. However, the background color is making the bottom sheet look weird. I modified my background color in themes to transparent and now the color is white
t
Oh! That's probably something the scaffold is doing. Yep, there it is - backgroundColor in BottomSheetScaffold is the MaterialTheme.colors.background. You should pass Transparent in there too
Basically the
content()
block of your layout contains the background color you're seeing. Though that wouldn't explain why a Modifier.background on the Layout with, say, Color.Blue would show up blue, since your scaffold should cover that up too.
j
I have set the Scaffold background to Transparent as well
t
And is there anything behind the Layout?
j
The content of the BottomSheet is a Google map and a NavHost
t
MapView uses a GL surface, right? That sort of thing can result in black if it's covered up and it thinks it doesn't have to draw. We had a similar issue on a camera feed app I worked with. The easiest solution to something like that is to move the stuff that's "underneath" your layout into it as part of the content. The scaffold stuff typically kind of assumes it's at the root of your app anyway
One test you can run to see if this is the issue is to wrap the whole thing in a frame layout and put a magenta box at the center between the compose view and the background view. If you see the box the problem is the map. If you don't it really is the compose layer and a layout inspector might do you more good than I have 😕
j
I don't understand
Let me share a snippet of my code so you'll see
Copy code
@Composable
fun MyLayout(
    modifier: Modifier,
    state: AnimatedDrawerState = rememberAnimatedDrawerState(
        drawerWidth = 280.dp,
    ),
    drawer: @Composable ()  -> Unit,
    bottomSheetScaffold: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = {
            drawer()
            bottomSheetScaffold()
        }
    ) { measurables, constraints ->
        val (drawerContentMeasurable, contentMeasurable) = measurables
        val drawerContentConstraints = Constraints.fixed(
            width = state.drawerWidth.coerceAtMost(constraints.maxWidth.toFloat()).toInt(),
            height = constraints.maxHeight,
        )
        val drawerContentPlaceable = drawerContentMeasurable.measure(drawerContentConstraints)
        val contentConstraints = Constraints.fixed(
            width = constraints.maxWidth,
            height = constraints.maxHeight,
        )
        val contentPlaceable = contentMeasurable.measure(contentConstraints)
        layout(
            width = constraints.maxWidth,
            height = constraints.maxHeight,
        ) {
            contentPlaceable.placeRelativeWithLayer(
                IntOffset.Zero,
            ) {
                transformOrigin = state.contentTransformOrigin
                scaleX = state.contentScaleX
                scaleY = state.contentScaleY
                translationX = state.contentTranslationX
            }
            drawerContentPlaceable.placeRelativeWithLayer(
                IntOffset.Zero,
            ) {
                translationX = state.drawerTranslationX
                shadowElevation = state.drawerElevation
            }
        }
    }
}
This is my layout
and this is how I am using it with the BottomSheetScaffold
Copy code
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun MyIndex(
    modifier: Modifier = Modifier,
    peekHeight: Float
) {
    val sheetPeekHeight by animateDpAsState(
        targetValue = peekHeight.dp,
        animationSpec = spring(stiffness = Spring.StiffnessLow)
    )

    val animation = remember { Animatable(0f) }
    val drawerState = rememberAnimatedDrawerState(
        drawerWidth = (LocalConfiguration.current.screenWidthDp - 68).dp ,
        animation
    )
    val scope = rememberCoroutineScope()
    val scaffoldState = rememberBottomSheetScaffoldState(
        bottomSheetState = rememberBottomSheetState(initialValue = BottomSheetValue.Collapsed),
    )
    MyLayout(
        modifier = modifier,
        state = drawerState,
        drawer = {
        //Drawer Content
        }
    ) {
        BottomSheetScaffold(
            sheetContent = {
                //Sheet content
            },
            sheetShape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp),
            sheetPeekHeight = sheetPeekHeight,
            scaffoldState = scaffoldState

        ) {
            AndroidView(
                factory = {context ->
                    MapView(context).apply {
                        onCreate(null)
                        onResume()
                        getMapAsync {

                        }
                    }
                },
                modifier = modifier.background(Color.Transparent),
            )

            NavHost(
                navController = rememberNavController(),
                startDestination = "start_route",
                modifier = modifier.background(Color.Yellow)
            ){
                //My Routes Here
            }
        }
    }
}
t
So you're passing Modifier.background(Color.Transparent) to MyIndex and you're seeing black? Is there anything behind MyIndex? Like is that the root of the UI hierarchy? Or is it in a box with something behind it? The background you pass to MyLayout should only cover up anything outside the scope of MyIndex. That is, if you had a Box with two elements: A list of to-do tasks and MyIndex. In that case the background of MyIndex would cover up your to-do list via the MyLayout modifier. But if the root of your app is MyIndex then you'd expect a black background if the index bg is transparent because that's just the default background for an empty app.
To clarify - The MapView inside the AndroidView is inside the content of MyLayout. This means that a background on MyLayout would have no effect on the mapview because it'd show up behind the MapView.