Flexible Chat Row and Resizable SubcomposeLayout

Overview

Flexible Chat Row and Resizable SubcomposeLayout

Flexible chat row, ChatFlexBoxLayout, that positions its elements based on number of lines message text has, parent width, message and message status width. And SubcomposeColumn created using SubComposeLayout which remeasures its children based on longest children. This is useful for matching quote message and message length after position calculation. These two composables are useful for creating dynamic message rows that positions children and positions message, message date and message status.

There are 3 implementation files to try ChatFlexBoxLayout, and SubcomposeColumn which are FullChatImplementation.kt, ChatAndWidthImplementation.kt, and ResizableColumnImplementation.kt

Full Chat Chat Width Resizable

ChatFlexBoxLayout

This is a layout that measures and positions message and another container that uses message date or message date and message received status like messaging apps does.

There are 4 possible conditions to position message and stats

  • Single line message text and status is shorter than parent width(Magenta in sample)
  • Single line message text and status is longer than parent width(Green in sample)
  • Multiple line message with last line width and message status is shorter message text length + right padding(Red in sample)
  • Multiple line message with last line width and message status is longer message text length + right padding(Yellow in sample)

Usage

ChatFlexBoxLayout(
    modifier: Modifier = Modifier,
    text: String,
    color: Color = Color.Unspecified,
    fontSize: TextUnit = 16.sp,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    lineHeight: TextUnit = TextUnit.Unspecified,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
    messageStat: @Composable () -> Unit,
    onMeasure: ((ChatRowData) -> Unit)? = null
)

Since TextLayout is required to get text length, last line width and other properties it's internal to this composable but properties of Textcomposable can be set with same as it's done using Text.

onMeasure returns internal layout data of this row, that's how i set colors differently in chat width sample. messageStat is composable that contains message text or status if you need to.

    ChatFlexBoxLayout(
        modifier = Modifier
            .background(color, shape = RoundedCornerShape(8.dp))
            .padding(start = 2.dp, top = 2.dp, end = 4.dp, bottom = 2.dp),
        text = text,
        messageStat = {
            MessageTimeText(
                modifier = Modifier.wrapContentSize(),
                messageTime = messageTime,
                messageStatus = messageStatus
            )
        },
        onMeasure = { chatRowData ->
            color = when (chatRowData.measuredType) {
                0 -> Color.Yellow
                1 -> Color.Red
                2 -> Color.Green
                else -> Color.Magenta
            }
        }
    )

Another overload of ChatFlexBoxLayout takes two Composables as arguments which custom message Composable can be used instead of String or AnnotatedString.

@Composable
fun ChatFlexBoxLayout(
    modifier: Modifier,
    message: @Composable () -> Unit,
    messageStat: @Composable () -> Unit = {},
    chatRowData: ChatRowData,
    onMeasure: ((ChatRowData) -> Unit)? = null
) {
  //...
}

Use with remember { ChatRowData() } to provide stats and invoke measureText(chatRowData, it) to set text properties to this data


            val chatRowData = remember { ChatRowData() }

            ChatFlexBoxLayout(
                modifier = Modifier.padding(
                    start = 2.dp,
                    top = 2.dp,
                    end = 8.dp,
                    bottom = 2.dp
                ),
                message = {
                    Text(
                        modifier = Modifier.padding(horizontal = 6.dp, vertical = 4.dp),
                        text = text,
                        fontSize = 16.sp,
                        onTextLayout = {
                            // โš ๏ธ THIS IS REQUIRED TO MEASURE Text size and get line count
                            measureText(chatRowData, it)
                        }
                    )
                },
                messageStat = {
                    MessageTimeText(
                        modifier = Modifier.wrapContentSize(),
                        messageTime = messageTime,
                        messageStatus = messageStatus
                    )
                },
                chatRowData = chatRowData
            )
        }

SubcomposeColumn

This is a layout that uses SubcomposeLayout to find longest child and then remeasure again and set every child to this max width. There are 2 overloads of this Composable if you only need to use direct 2 children you can use which returns size of main component as IntSize

fun SubcomposeColumn(
    modifier: Modifier = Modifier,
    mainContent: @Composable () -> Unit = {},
    dependentContent: @Composable (IntSize) -> Unit
) {
...
}

This overloaded function is suitable for layout with any number of children

@Composable
fun SubcomposeColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit = {},
) {

    SubcomposeLayout(modifier = modifier) { constraints ->

        var recompositionIndex = 0

        var placeables: List
   
     = subcompose(recompositionIndex++, content).map {
            it.measure(constraints)
        }

        val maxSize =
            placeables.fold(IntSize.Zero) { currentMax: IntSize, placeable: Placeable ->
                IntSize(
                    width = maxOf(currentMax.width, placeable.width),
                    height = currentMax.height + placeable.height
                )
            }

        // Remeasure every element using width of longest item as minWidth of Constraint
        if (!placeables.isNullOrEmpty() && placeables.size > 1) {
            placeables = subcompose(recompositionIndex, content).map { measurable: Measurable ->
                measurable.measure(Constraints(maxSize.width, constraints.maxWidth))
            }
        }

        layout(maxSize.width, maxSize.height) {
            var yPos = 0
            placeables.forEach { placeable: Placeable ->
                placeable.placeRelative(0, yPos)
                yPos += placeable.height
            }

        }
    }
}

   
You might also like...
Rick-and-morty - Rick and Morty app using Jetpack Compose
Rick-and-morty - Rick and Morty app using Jetpack Compose

Rick and Morty Rick and Morty app using rickandmortyapi.com Current Screens: Cha

A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose
A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose

Authentication A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose Scree

Examples of ParallaxView and ParallaxScrollEfect are in the repo. You can find the necessary titles and outputs in the continuation of the Readme file. ๐Ÿชž
Examples of ParallaxView and ParallaxScrollEfect are in the repo. You can find the necessary titles and outputs in the continuation of the Readme file. ๐Ÿชž

Parallax Examples : Examples of ParallaxView and ParallaxScrollEfect are in the repo. You can find the necessary titles and outputs in the continuatio

๐Ÿš€๐Ÿž๐Ÿ’ช Collection of Images, Modifiers, utility functions for Jetpack Compose to expand and enrich displaying, manipulating, scaling, resizing, zooming, and getting cropped ImageBitmap based on selection area

Collection of Images, Modifiers, utility functions for Jetpack Compose to expand and enrich displaying, manipulating, scaling, resizing, zooming, and getting cropped ImageBitmap based on selection area, before/after image to with handle to show partial of both images and more is cooking up

Sample project to demonstrate how to have clear and better interactions between composables and viewmodels.

Form Validation Sample project to demonstrate how to have clear and better interactions between composables and viewmodels. Concepts used uiState conc

An Android application consuming the GitHub API to search for users on Github, display their followers, following and repositories. The project is built with Compose, MVVM pattern as well as other architectural components and libraries. OTPView is a view made in Jetpack compose. It is highly customisable and can be used to show OTP view with different length and shapes.
OTPView is a view made in Jetpack compose. It is highly customisable and can be used to show OTP view with different length and shapes.

OTPView OTPView is a highly costumizable OTP view made in the Jetpack compose UI. Usage: CircleOtpView is a sample composable that calls the OtpView w

A Collection on all Jetpack compose UI elements, Layouts, Widgets and Demo screens to see it's potential
A Collection on all Jetpack compose UI elements, Layouts, Widgets and Demo screens to see it's potential

ComposeCookBook Declarative UI A Collection of all Jetpack compose UI elements, Layouts, Widgets and Demo screens to see it's potential. Jetpack Compo

Owner
Smart Tool Factory
Developer From Thrace fueled with ๐Ÿบ โ˜•๏ธ and ๐Ÿค˜
Smart Tool Factory
Row Coloumn Box Compose Constraint Layout Modifier.xyz Animator Tween animation MutableState Creating custom composable Corners Canvas LaunchedEffect

Row Coloumn Box Compose Constraint Layout Modifier.xyz Animator Tween animation MutableState Creating custom composable Corners Canvas LaunchedEffect

Shivaraj M Patil 1 Apr 13, 2022
Foldable-chat-android - Foldable chat Android demonstrates adaptive and responsive UIs with Jetpack WindowManager API

Foldable Chat Android A foldable chat Android demonstrates adaptive and responsi

Stream 31 Oct 29, 2022
A flexible theme provider for Jetpack Compose. Supports dynamic theme changes and saving theme preference.

JetTheme JetTheme is a flexible theme provider for Jetpack Compose. Change the theme and recompose the UI dynamically. Save theme preference to local

Mao Yufeng 48 Oct 19, 2022
๐Ÿ“ฑ WhatsApp clone project demonstrates modern Android development built with Jetpack Compose and Stream Chat SDK for Compose.

This is a WhatsApp clone app built with Jetpack Compose and Stream Chat SDK for Compose. The purpose of this repository is to demonstrate below: Imple

Stream 689 Dec 25, 2022
Notes is a simple and private notes app. Organize your thoughts, discoveries, and ideas and simplify planning important moments in your life with your digital notepad.

Notes Example Download Download the latest version of the Android app from this link. Building Using Android Studio Clone the repo, open it in Android

Dmitry Savin 1 Jan 3, 2022
Zoom Modifiers, zoomable image and layouts with limit pan bounds, fling and moving back to valid bounds and callbacks that return current transformation or visible image section

Zoom Modifiers, zoomable image and layouts with limit pan bounds, fling and moving back to valid bounds and callbacks that return current transformation or visible image section

Smart Tool Factory 20 Dec 13, 2022
๐Ÿ‚ Jetpack Compose image loading library which can fetch and display network images using Glide, Coil, and Fresco.

Landscapist ?? Jetpack Compose image loading library which can fetch and display network images using Glide, Coil, Fresco Usecase You can see the use

Jaewoong Eum 1.4k Jan 1, 2023
Example Jetpack Compose Android App, that uses the newest mechanisms, like StateFlow, SharedFlow, etc. to manage states and handle events. ViewModel, UI and Screenshot tests included :)

AndroidMVIExample Example Jetpack Compose Android App, that uses the newest mechanisms, like StateFlow, SharedFlow, etc. to manage states and handle e

Patryk Kosieradzki 55 Nov 18, 2022
Scrobble is a wip music tracking and browsing app. It uses the Lastf.fm and spotify APIs to deliver data. The whole UI is created using Jetpack compose.

Scrobble (WIP, name not final) Scrobble is a wip music tracking and browsing app. It uses the Lastf.fm API to realize music tracking and browsing and

Niklas Schnettler 55 Oct 31, 2022
Burak Akgรผn 84 Oct 30, 2022