androidx / constraintlayout

ConstraintLayout is an Android layout component which allows you to position and size widgets in a flexible way
Apache License 2.0
1.06k stars 177 forks source link

Constraint layout chains are messed #764

Open iZakirSheikh opened 1 year ago

iZakirSheikh commented 1 year ago

I don't know how but the constraint layout's chains are not working with latest version of compose (1.4 -alpha2).

Here is the code

private val HeaderArtWorkShape = RoundedCornerShape(20) context(TracksViewModel) @Composable fun Header( modifier: Modifier = Modifier ) { ConstraintLayout(modifier = modifier) {

    val meta by header
    val title = stringResource(value = title)
    val (Artwork, Play, Title, Subtitle, Share, Shuffle, Sort, Divider) = createRefs()

    // create the chain
    // this will determine the size of the
    // Header
    constrain(
        ref = createVerticalChain(Artwork, Share, Divider, chainStyle = ChainStyle.Packed),
        constrainBlock = {
            // Divider will act as the center anchor of Play Button
            top.linkTo(parent.top, ContentPadding.normal)
            bottom.linkTo(parent.bottom, ContentPadding.large)
        }
    )

    Surface(
        shape = HeaderArtWorkShape,
        elevation = ContentElevation.high,

        content = {
            val artwork = meta?.artwork
            Image(data = artwork)
        },

        modifier = Modifier
            .constrainAs(Artwork) {
                start.linkTo(parent.start, ContentPadding.normal)
                width = Dimension.value(76.dp)
                height = Dimension.ratio("0.61")
            },
    )

    val context = LocalContext.current
    val channel = LocalSnackDataChannel.current
    val enabled by remember { derivedStateOf { selected.size > 0 } }
    //Share
    IconButton(
        onClick = { share(context, channel) },
        imageVector = Icons.TwoTone.Share,
        contentDescription = null,
        enabled = enabled,
        modifier = Modifier
            .padding(top = ContentPadding.large)
            .constrainAs(Share) {}
    )

    // Divider
    Divider(
        modifier = Modifier
            .constrainAs(Divider) {}
    )

    // line 2 is the line of Button aligned with share
    constrain(
        ref = createHorizontalChain(Share, Shuffle, Sort, chainStyle = ChainStyle.Packed(0f)),
        constrainBlock = {
            start.linkTo(Artwork.start)
        }
    )

    //Shuffle
    IconButton(
        imageVector = Icons.TwoTone.Shuffle,
        contentDescription = null,

        onClick = { onRequestPlay(context, true, channel = channel) },

        modifier = Modifier.constrainAs(Shuffle) {
            bottom.linkTo(Share.bottom)
        }
    )

    // Sort
    var show by rememberState(initial = false)
    IconButton(
        onClick = { show = true },

        modifier = Modifier.constrainAs(Sort) {
            bottom.linkTo(Share.bottom)
        },

        content = {
            Icon(imageVector = Icons.TwoTone.Sort, contentDescription = null)
            SortBy(expanded = show) {
                show = false
            }
        }
    )

    // Play Button
    NeumorphicButton(
        shape = CircleShape,
        onClick = { onRequestPlay(context, false, null, channel = channel) },

        colors = NeumorphicButtonDefaults.neumorphicButtonColors(
            lightShadowColor = Material.colors.lightShadowColor,
            darkShadowColor = Material.colors.darkShadowColor
        ),

        modifier = Modifier
            .constrainAs(Play) {
                top.linkTo(Divider.top)
                bottom.linkTo(Divider.bottom)
                end.linkTo(parent.end, ContentPadding.large)
                width = Dimension.value(60.dp)
                height = Dimension.value(60.dp)
            },

        content = {
            Icon(
                painter = painterResource(id = R.drawable.ic_play_arrow),
                contentDescription = null,
                modifier = Modifier.requiredSize(20.dp)
            )
        }
    )

    // Title
    Header(
        text = title,
        style = Material.typography.h5,
        maxLines = 2,
        textAlign = TextAlign.Start,

        modifier = Modifier.constrainAs(Title) {
            start.linkTo(Artwork.end, ContentPadding.normal)
            end.linkTo(parent.end, ContentPadding.normal)
            top.linkTo(Artwork.top)
            width = Dimension.fillToConstraints
        }
    )

    // Subtitle
    val subtitle = stringResource(value = meta?.subtitle) ?: AnnotatedString("")
    Label(
        text = subtitle,
        textAlign = TextAlign.Start,
        style = Material.typography.caption2,
        fontWeight = FontWeight.SemiBold,
        color = LocalContentColor.current.copy(ContentAlpha.medium),
        maxLines = 2,
        modifier = Modifier
            .constrainAs(Subtitle) {
                end.linkTo(parent.end, ContentPadding.normal)
                top.linkTo(Title.bottom)
                start.linkTo(Title.start)
                width = Dimension.fillToConstraints
            },
    )

    // line 3 of details
    val (Duration, Divider1, Tracks, Divider2, Size) = createRefs()
    constrain(
        ref = createHorizontalChain(
            Duration,
            Divider1,
            Tracks,
            Divider2,
            Size,
            chainStyle = ChainStyle.SpreadInside
        ),

        constrainBlock = {
            start.linkTo(Title.start)
            end.linkTo(parent.end, ContentPadding.normal)
        }
    )

    //Duration
    val duration = Util.formatAsDuration((meta?.duration ?: 0).toLong())
    Text(
        reference = Duration,
        value = duration,
        title = "Duration",

        block = {
            top.linkTo(Subtitle.bottom, ContentPadding.normal)
        }
    )

    // Divider 1
    Divider(
        modifier = Modifier.constrainAs(Divider1) {
            top.linkTo(Duration.top, -ContentPadding.small)
            height = Dimension.value(56.dp)
            width = Dimension.value(1.dp)
        }
    )

    //Tracks
    val count = meta?.cardinality ?: 0
    Text(
        reference = Tracks,
        value = "$count",
        title = "Tracks",

        block = {
            top.linkTo(Duration.top)
        },
    )

    //Divider 2
    Divider(
        modifier = Modifier.constrainAs(Divider2) {
            height = Dimension.value(56.dp)
            top.linkTo(Duration.top, -ContentPadding.small)
            width = Dimension.value(1.dp)
        }
    )

    // Size
    val size = FileUtils.toFormattedDataUnit(context, meta?.size ?: 0L)
    Text(
        reference = Size,
        value = size,
        title = "Size",
        block = {
            top.linkTo(Duration.top)
        },
    )
}

}

Note: The code was working properly in 1.3.0-beta01. Here the chains logic is all messed up.

iZakirSheikh commented 1 year ago

during my tests I found out the issue is releated to compose ui version not compose compiler.