Search code examples
androidandroid-jetpack-composeglance-appwidget

Android Glance widget text not truncating properly inside row


I am using the Jetpack glance framework for creating widgets in Android, and I have encountered a problem when using text inside a row.

Expected behavior:- Text should truncate as soon as it touches the other element inside the row

Actual behavior:- Text first pushes the other elements out of the view and then truncates

Here is the screenshot of the issue

This is fine

This is fine

This is not

enter image description here

Box(modifier = GlanceModifier.background(ColorProvider(day = backgroundColor, night = backgroundColorDark))
            .padding(
                    horizontal = 14.dp,
                    vertical = 14.dp).clickable(onClick = actionStartActivity<MainActivity>(context, Uri.parse(widgetUri)))) {
   Column(
                    modifier = GlanceModifier.fillMaxSize(),
                    verticalAlignment = Alignment.Vertical.Top,
                    horizontalAlignment = Alignment.Horizontal.Start,
            ) {
                Row(
                        modifier = GlanceModifier.fillMaxWidth(),
                        horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
                        verticalAlignment = Alignment.Vertical.CenterVertically
                ) {


                    Row(
                            verticalAlignment = Alignment.Vertical.CenterVertically)
                    {
                        Box (
                                modifier = GlanceModifier.clickable(onClick = actionRunCallback<ToggleAction>(
                                        parameters = actionParametersOf(habitIdKey to habitId)
                                ))
                        ) {
                            Image(
                                    provider = ImageProvider(R.drawable.check_24), contentDescription = null,
                                    colorFilter = ColorFilter.tint(


                                            if (isTodayCompleted)
                                                ColorProvider(day = Color.White, night = Color.White)
                                            else
                                                ColorProvider(day = getColor(backgroundColor), night = getColor(backgroundColor))

                                    ),
                                    modifier = GlanceModifier
                                            .size(30.dp)
                                            .then(
                                                    if (isTodayCompleted) {
                                                        GlanceModifier.background(
                                                                imageProvider = ImageProvider(R.drawable.fab_shape),
                                                                colorFilter = ColorFilter.tint(ColorProvider(day = getColor(backgroundColor), night = getColor(backgroundColor)))
                                                        ) // Apply background when today is completed
                                                    } else {
                                                        GlanceModifier.background(
                                                                imageProvider = ImageProvider(R.drawable.fab_outline),
                                                                colorFilter = ColorFilter.tint(ColorProvider(day = getColor(backgroundColor), night = getColor(backgroundColor)))
                                                        ) // Apply border when today is not completed
                                                    }
                                            )
                            )
                        }
                     Column(modifier = GlanceModifier.padding(horizontal = 10.dp))

                        {
                         Text("${DateFormat.format("MMMM",today)}",
                                maxLines = 1,
                                 style = TextStyle(

                                         color = ColorProvider(day = Color.Gray, night = Color.Gray),
                                         fontWeight = FontWeight.Normal,
                                         textAlign = TextAlign.Start,
                                         fontSize = 12.sp))
                            Text("$title",
                                    maxLines = 1,

                                    style = TextStyle(
                                            color = ColorProvider(day = textColor, night = textColorDark),
                                            fontWeight = FontWeight.Medium,
                                            textAlign = TextAlign.Start,

                                            fontSize = 16.sp))

                     }

                    }
                    Spacer(GlanceModifier.defaultWeight())
                    Column(
                            verticalAlignment = Alignment.Vertical.CenterVertically,
                            horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
                    ) {
                        Row(
                                horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
                                verticalAlignment = Alignment.Vertical.CenterVertically
                        ) {

                            Text("$currentStreak",

                                    style = TextStyle(
                                            color = ColorProvider(day = textColor, night = textColorDark),
                                            fontWeight = FontWeight.Bold,
                                            textAlign = TextAlign.Start,
                                            fontSize = 14.sp))
                            Image(
                                    provider = ImageProvider(if (isTodayCompleted)
                                        R.drawable.fire_filled
                                    else R.drawable.fire_outline
                                    ), contentDescription = null,
                                    colorFilter = ColorFilter.tint(ColorProvider(day = getColor(backgroundColor), night = getColor(backgroundColor))),
                                    modifier = GlanceModifier.size(14.dp)
                            )
                        }
                        Text(
                                if (currentStreak.toInt() == 1) "DAY" else
                                    "DAYS",
                                modifier = GlanceModifier.padding(horizontal = 2.dp),
                                style = TextStyle(
                                        color = ColorProvider(day = textColor, night = textColorDark),
                                        fontWeight = FontWeight.Normal,
                                        textAlign = TextAlign.Start,
                                        fontSize = 10.sp))
                    }
                }
            }

Solution

  • Your middle column (or shall we call it group, as you don't have an explicit column for the first/leftmost vertical group) needs to be able to grow and acquire as much space as it can without stepping on the third (rightmost) column.

    To do so, you need to let the rightmost column take up the space it needs based on its content (WrapContentWidth), and allow the middle column to be flexible in its width by setting its weight (available in row scope) to 1f (which, in Glance, is defaultWeight()). Note that

    The parent will divide the horizontal space remaining after measuring unweighted child elements

    which means the unweighted siblings (including column 3) are measured first, thus assuring they are allocated the needed space.

    interface RowScope {
        /**
         * Size the element's width to split the available space with other weighted sibling elements
         * in the [Row]. The parent will divide the horizontal space remaining after measuring
         * unweighted child elements and distribute it according to the weights, the default weight
         * being 1.
         */
        fun GlanceModifier.defaultWeight(): GlanceModifier
    }
    

    Below is a simplified version. Previews with different width and how the text grows/truncates.

    Preview

    @Composable
    @OptIn(ExperimentalGlancePreviewApi::class)
    @Preview(widthDp = 340, heightDp = 100)
    @Preview(widthDp = 230, heightDp = 100)
    @Preview(widthDp = 130, heightDp = 100)
    fun Test(){
    
        Box(modifier = GlanceModifier.padding(14.dp)) {
                Row(
                    modifier = GlanceModifier.fillMaxWidth(),
                    horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
                    verticalAlignment = Alignment.Vertical.CenterVertically
                ) {
                    Image(
                        provider = ImageProvider(R.drawable.sun_68),
                        contentDescription = null,
                        modifier = GlanceModifier.size(30.dp),
                        contentScale = ContentScale.Crop)
    
                   Column (
                            modifier = GlanceModifier.padding(1.dp).defaultWeight(),
                            horizontalAlignment = Alignment.Horizontal.Start,
                            verticalAlignment = Alignment.Vertical.CenterVertically
                            )
                    {
                        Text(
                            text = "This text can be truncated or it can fit ",
                            modifier = GlanceModifier.padding(horizontal = 8.dp),
                            style = TextStyle(
                                color = ColorProvider(day = Color.White, night = Color.White),
                                fontSize = 14.sp
                            ),
                            maxLines = 1)
                        Text(
                            text = "But it will not push out rightmost column",
                            modifier = GlanceModifier.padding(horizontal = 8.dp),
                            style = TextStyle(
                                color = ColorProvider(day = Color.White, night = Color.White),
                                fontSize = 10.sp
                            ),
                            maxLines = 1)
                    }
                    Column (
                        modifier = GlanceModifier.wrapContentWidth(),
                        horizontalAlignment = Alignment.Horizontal.Start,
                        verticalAlignment = Alignment.Vertical.CenterVertically
                    ){
                        Text(
                            "Right",
                            maxLines = 1)
                        Text(
                            "side",
                            maxLines = 1)
                    }
           }
        }
    }