Home > front end >  Make LazyColumn items be as large as the largest item in the list
Make LazyColumn items be as large as the largest item in the list

Time:11-24

@Composable
fun PreviewLayout() {
    fun getRandomString(length: Int): String {
        val allowedChars = ('A'..'Z')   ('a'..'z')   ('0'..'9')
        return (1..length)
            .map { allowedChars.random() }
            .joinToString("")
    }

    val horizontalScrollState = rememberScrollState()

    LazyColumn(
        modifier = Modifier
            .background(Color.Blue)
            .fillMaxHeight()
            .wrapContentWidth()
            .horizontalScroll(horizontalScrollState)
    ) {
        items(5) { index ->
            Text(
                text = getRandomString((index   1) * 4).uppercase(),
                color = Color.Black,
                fontSize = 16.sp,
                modifier = Modifier
                    .padding(8.dp)
                    .background(Color.Yellow)
            )
        }
    }
}

Preview of the layout:

Compose Layout Preview

I'd like to have the items width be the same as the largest item in the list.

Notice the .horizontalScroll(horizontalScrollState), this is to allow horizontal scrolling.

What I'd like:

Desirable Layout Preview

I need to use a LazyColumn but if I could use a Column I'd write it this way:

Column(
    modifier = Modifier
        .background(Color.Blue)
        .horizontalScroll(horizontalScrollState)
        .fillMaxHeight()
        .width(IntrinsicSize.Min)
) {
    repeat(5) { index ->
        Text(
            text = getRandomString((index   1) * 4).uppercase(),
            color = Color.Black,
            fontSize = 16.sp,
            modifier = Modifier
                .padding(8.dp)
                .fillMaxWidth()
                .background(Color.Yellow)
        )
    }
}

CodePudding user response:

This is not possible when horizontal srolling is enabled.

Regular Modifier.fillMaxWidth can't work inside the scrolling horizontally layouts as the items are measured with Constraints.Infinity as the constraints for the main axis.

If you want your Column solution to work, you need to place it inside another contain (like a Box) and apply horizontal scrolling to the parent. Scrolling on the Column itself needs to be removed:

Box(
    modifier = Modifier
        .requiredWidth(250.dp)
        .fillMaxHeight()
        .horizontalScroll(rememberScrollState())
) {
    Column(
        modifier = Modifier
            .background(Color.Blue)
            .fillMaxHeight()
            .width(IntrinsicSize.Min)

    ) {
        repeat(5) { index ->
            Text(
                text = getRandomString((index   1) * 40).uppercase(),
                color = Color.Black,
                fontSize = 16.sp,
                modifier = Modifier
                    .padding(8.dp)
                    .fillMaxWidth()
                    .background(Color.Yellow)
            )
        }
    }
}

CodePudding user response:

  1. You need to calculate width of the widest element separately. You can do it by placing an invisible copy of you cell with widest content in a Box along with LazyColumn.

    In your sample it's easy - just get the longest string. If in the real project you can't decide which of contents is gonna be the widest one, you have two options:

    1.1. Place all of them one on top of each other. You can do it only if you have some limited number of cells,

    1.2. Otherwise you have to made some approximation and filter a short list of the ones you expect to be the widest ones.

  2. Because of horizontalScroll maxWidth constraint is infinity, you have to pass calculated width manually. You can get it with onSizeChanged:

@Composable
fun TestScreen(
) {
    fun getRandomString(length: Int): String {
        val allowedChars = ('A'..'Z')   ('a'..'z')   ('0'..'9')
        return (1..length)
            .map { allowedChars.random() }
            .joinToString("")
    }

    val items = remember {
        List(30) { index ->
            getRandomString((index   1) * 4).uppercase()
        }
    }
    val maxLengthItem = remember(items) {
        items.maxByOrNull { it.length }
    }
    val (maxLengthItemWidthDp, setMaxLengthItemWidthDp) = remember {
        mutableStateOf<Dp?>(null)
    }

    val horizontalScrollState = rememberScrollState()

    Box(
        Modifier
            .background(Color.Blue)
            .horizontalScroll(horizontalScrollState)
    ) {
        LazyColumn(
            Modifier.fillMaxWidth()
        ) {
            items(items) { item ->
                Cell(
                    item,
                    modifier = if (maxLengthItemWidthDp != null) {
                        Modifier.width(maxLengthItemWidthDp)
                    } else {
                        Modifier
                    }
                )
            }
        }
        if (maxLengthItem != null) {
            val density = LocalDensity.current
            Cell(
                maxLengthItem,
                modifier = Modifier
                    .requiredWidthIn(max = Dp.Infinity)
                    .onSizeChanged {
                        setMaxLengthItemWidthDp(with(density) { it.width.toDp() })
                    }
                    .alpha(0f)
            )
        }
    }
}

@Composable
fun Cell(
    item: String,
    modifier: Modifier,
) {
    Text(
        text = item,
        color = Color.Black,
        fontSize = 16.sp,
        modifier = modifier
            .padding(8.dp)
            .background(Color.Yellow)
    )
}

Result:

CodePudding user response:

@Composable
fun PreviewLayout() {
    fun getRandomString(length: Int): String {
        val allowedChars = ('A'..'Z')   ('a'..'z')   ('0'..'9')
        return (1..length)
            .map { allowedChars.random() }
            .joinToString("")
    }
    val horizontalScrollState = rememberScrollState()

    LazyColumn(
        modifier = Modifier
            .background(Color.Blue)
            .fillMaxHeight()
            .horizontalScroll(horizontalScrollState)

    ) {
        items(5) { index ->
            Text(
                text = getRandomString((index   1) * 4).uppercase(),
                color = Color.Black,
                fontSize = 16.sp,
                modifier = Modifier
                    .padding(8.dp)
                    .width(width = 200.dp)
                    .background(Color.Yellow)
            )
        }
    }
}
  • Related