Search code examples
androidandroid-layoutandroid-jetpack-compose

Get Value Calculated in Layout Composable and Pass it in Children Composables


Here is my problem: I have a custom Layout

 Layout(content = content) { measurables, constraints ->
    val maxWidth = constraints.maxWidth
    val totalRows: Int = ceil(measurables.size / columnsCount.toFloat()).toInt()
    val itemWidth = maxWidth / columnsCount
    var itemHeight = 0 .....

I want to use itemWidth calculated there like this

 CustomLayout(columnsCount = 4) { itemWidth ->
            for (team in state.teams) {
                MyComponent(
                        size = itemWidth,
                        team = team)}}

How can i do this? Is it possible like this? What alternatives can I use?


Solution

  • Let`s say you have a chat log this: chat before

    And now you want to set the width of every composable to the width of the widest Composable chatAfter

    You can use the SubComposeLayout to get the height/width of every child composable and then you can resize the values to the one that you want.

    @Composable
    fun SubComposeLayoutDemo() {
    ResizeWidthColumn(Modifier.fillMaxWidth(), true) {
    
        Box(
            modifier = Modifier
                .background(Color.Red)
        ) {
            Text("Hello")
        }
    
        Box(
            modifier = Modifier
                .padding(top = 8.dp)
                .background(Color.Red)
         ) {
            Text("This is a long messsage \n and its longer")
         }
       }
      }
    
      @Composable
      fun ResizeWidthColumn(modifier: Modifier, resize: Boolean, 
        mainContent: @Composable () -> Unit) {
             SubcomposeLayout(modifier) { constraints ->
         val mainPlaceables = subcompose(SlotsEnum.Main, mainContent).map {
            // Here we measure the width/height of the child Composables
            it.measure(Constraints())
         }
    
         //Here we find the max width/height of the child Composables
         val maxSize = mainPlaceables.fold(IntSize.Zero) { currentMax, 
         placeable ->
            IntSize(
                width = maxOf(currentMax.width, placeable.width),
                height = maxOf(currentMax.height, placeable.height)
            )
        }
    
        val resizedPlaceables: List<Placeable> =
            subcompose(SlotsEnum.Dependent, mainContent).map {
                if (resize) {
                    /** Here we rewrite the child Composables to have the 
                     * width of
                     * widest Composable
                     */
                    it.measure(
                        Constraints(
                            minWidth = maxSize.width
                        )
                    )
                } else {
                    // Ask the child for its preferred size.
                    it.measure(Constraints())
                }
            }
    
        /**
         * We can place the Composables on the screen
         * with layout() and the place() functions
         */
    
        layout(constraints.maxWidth, constraints.maxHeight) {
            resizedPlaceables.forEachIndexed { index, placeable ->
                val widthStart = resizedPlaceables.take(index).sumOf { 
         it.measuredHeight }
                placeable.place(0, widthStart)
            }
        }
        } 
        }
    
    
        enum class SlotsEnum {
        Main,
        Dependent
    
        }
    

    @Credit : https://foso.github.io/Jetpack-Compose-Playground/ui/layout/subcomposelayout/