Modal Sheet library for Jetpack Compose

Last update: Aug 10, 2022

Modal Sheet

Modal Sheet library for Jetpack Compose.

Motivation

Sometimes we want bottom sheets to behave as real modals, thus overlaying all content on the screen. Official ModalBottomSheetState however, is laid out only in bounds of the parent Composable. This means that to display a bottom sheet above, for example bottom bar navigation, it must be placed "higher" in the hierarchy than usage in one of the tab screen.

The ModalSheet Composable from this library allows creating real modal bottom sheets which could be placed anywhere in the hierarchy.

Solution

The ModalSheet Composable internally uses FullScreenPopup which is basically a window placed above the current window and allows placing Composables inside. Then ModalSheet adds swipe-to-dismiss, scrim and shaping to simulate bottom sheet behavior.

The FullScreenPopup is public, thus can be used to create own "modal" Composables.

Usage

Get a dependency

Step 1. Add the JitPack repository to your build file. Add it in your root build.gradle at the end of repositories:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

Step 2. Add the dependency. Check latest version on the releases page.

dependencies {
    implementation 'com.github.oleksandrbalan:modalsheet:$version'
}

Use in Composable

The ModalSheet has 2 mandatory arguments:

  • visible - True if modal should be visible.
  • onDismiss - Lambda which is called when user touches the scrim or swipes the sheet away.
var visible by remember { mutableStateOf(false) }

Button(onClick = { visible = true }) {
    Text(text = "Show modal sheet")
}

ModalSheet(
    visible = visible,
    onDismiss = { visible = false },
) {
    
    Box(Modifier.height(200.dp))
}

See Demo application and examples for more usage examples.

Authors

TODO list

  • Add support for LazyColumn and LazyVerticalGrid inside modal sheet.
  • Provide swipe state to ModalSheetScope

GitHub

https://github.com/oleksandrbalan/modalsheet
Comments
  • 1. [ModalSheet] Add data based ModalSheet for dynamic content

    Should fix #1

    Do not really like the API though :/

    @wooodenleg What do you think?

    ModalSheet(
        data = error,
        visible = { this != null },
        onDismiss = onDismiss
    ) { data ->
        if (data == null) {
            [email protected]
        }
        // Use `data` for content
    }
    

    https://user-images.githubusercontent.com/20944869/167252435-6a31b477-d1a1-40bb-b6fb-9c14f65aee05.mp4

    Reviewed by oleksandrbalan at 2022-05-07 11:33
  • 2. Make fullscreen popup internal

    Fixes https://github.com/oleksandrbalan/modalsheet/issues/4

    I would keep FullscreenPopup inside this library for now to not support 2 small libraries at once.

    Also:

    • Remove cusom example 🪦
    • Change name a bit
    Reviewed by oleksandrbalan at 2022-05-13 12:56
  • 3. Change custom implementation to ModalBottomSheetLayout

    This PR replaces custom implementation of the bottom sheet with ModalBottomSheetLayout, take it as a suggestion.

    Pros:

    • Identical look&feel as official component.
    • Out-of-box same configuration options (shape, elevation, scrim).
    • Out-of-box LazyColumn and LazyVerticalGrid support.
    • Less code - less support 🤷‍♂️

    Cons:

    • ModalSheet is less configurable, because bound to possibilities and API of ModalBottomSheetLayout.
    • Could not provide content for scrim overlay (can be added in future).
    Reviewed by oleksandrbalan at 2022-05-13 12:17
  • 4. Move FullScreenPopup into separate artifact

    FullScreenPopup feels more like implementation detail for "modal sheet" rather than a feature I would look for in this library. Consider making it internal or moving it to separate public artifact so the API is opt-in.

    Reviewed by wooodenleg at 2022-05-07 15:07
  • 5. [ModalSheet] No exit animation when ModalSheet has dynamic content

    Description

    Sometimes it is needed to show dynamic data in modal sheet content. Imagine error bottom sheet use-case, where if Error is not null we need to show modal, otherwise hide it. We could either wrap ModalSheet in "if" condition to show only for non-null error, or adjust content (which is animated) for null error.

    Both possible solutions did not provide good experience. Either there is no exit animation, or content is "blinking" when animating out.

    Sample

    
    data class ErrorData(val title: String, val message: String)
    
    val error = rememberSaveable { mutableStateOf<ErrorData?>(null) }
    
    Box(
        contentAlignment = Alignment.Center,
        modifier = Modifier
            .fillMaxSize()
            .padding(padding)
    ) {
        Button(onClick = {
            error.value = ErrorData(
                title = "Error",
                message = "Oops, an error occurred"
            )
        }) {
            Text(text = "Error!")
        }
    }
    
    // Solution #1 - wrap in if condition
    val errorValue = error.value
    if (errorValue != null) {
        ModalSheet(
            visible = true,
            onDismiss = { error.value = null }
        ) {
            Column(
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.spacedBy(SpacingSmall),
                modifier = Modifier
                    .fillMaxWidth()
                    .navigationBarsPadding()
                    .padding(SpacingMedium)
            ) {
                Text(
                    text = errorValue.title,
                    style = MaterialTheme.typography.h4
                )
                Text(
                    text = errorValue.message,
                )
            }
        }
    }
    
    // Solution #2 - null content is visible when animated out
    ModalSheet(
        visible = error.value != null,
        onDismiss = { error.value = null }
    ) {
        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(SpacingSmall),
            modifier = Modifier
                .fillMaxWidth()
                .navigationBarsPadding()
                .padding(SpacingMedium)
        ) {
            Text(
                text = error.value?.title.orEmpty(),
                style = MaterialTheme.typography.h4
            )
            Text(
                text = error.value?.message.orEmpty(),
            )
        }
    }
    

    Video

    First solution to wrap in if condition, results in no exit animation. https://user-images.githubusercontent.com/20944869/167183075-409de54f-6954-4206-bc90-b488755e6958.mp4

    Second solution to use null in content, results in "empty" content during exit animation. https://user-images.githubusercontent.com/20944869/167187758-c1d16bb1-d21e-44ec-adf1-78bf76763c3a.mp4

    Reviewed by oleksandrbalan at 2022-05-06 17:48
  • 6. Add observable state

    Fixes https://github.com/oleksandrbalan/modalsheet/issues/5

    I have added swipeState to the content scope and also add derived normalizedFraction for ease-of-use.

    https://user-images.githubusercontent.com/20944869/168338837-4c2cc92f-4cc8-405a-9cf8-eac1d66167f5.mp4

    Reviewed by oleksandrbalan at 2022-05-13 17:46
  • 7. [ModalSheet] Observability of sheet state

    Description

    Currently there is no way to observe the state of the modal sheet.

    The use case for having this information is for example observing the "hidden" state of the sheet to chain appearance of other UI components like Dialog or even other bottom sheet. Another use case might be to modify/animate the content of the sheet in response to the expanded state. Feature request to the material bottom sheet by Colton Idle in Kotlin Slack:

    I have a bottom sheet. When collapsed the padding on top of the text is perfect (according to my designer), but when it's fully expanded, we want to add extra padding so that the text is pushed down. We want the bottom sheet to go all the way up because that's what our designer wants in our edge to edge application.

    Implementation

    No thoughts about implementation yet but we could take "inspiration" from Material ModalBottomSheetState

    Reviewed by wooodenleg at 2022-05-07 15:39
A collection of animations, compositions, UIs using Jetpack Compose. You can say Jetpack Compose cookbook or play-ground if you want!
A collection of animations, compositions, UIs using Jetpack Compose. You can say Jetpack Compose cookbook or play-ground if you want!

Why Not Compose! A collection of animations, compositions, UIs using Jetpack Compose. You can say Jetpack Compose cookbook or play-ground if you want!

Aug 14, 2022
Learn Jetpack Compose for Android by Examples. Learn how to use Jetpack Compose for Android App Development. Android’s modern toolkit for building native UI.
Learn Jetpack Compose for Android by Examples. Learn how to use Jetpack Compose for Android App Development. Android’s modern toolkit for building native UI.

Learn Jetpack Compose for Android by Examples. Learn how to use Jetpack Compose for Android App Development. Android’s modern toolkit for building native UI.

Aug 10, 2022
This is a sample app(For beginners - App #2) built using Jetpack Compose. It demonstrates the concept of State Hoisting in Jetpack Compose.
This is a sample app(For beginners - App #2) built using Jetpack Compose. It demonstrates the concept of State Hoisting in Jetpack Compose.

JetBMICalculator This is a sample app(For beginners - App #2) built using Jetpack Compose. It demonstrates the concept of State Hoisting in Jetpack Co

Feb 9, 2022
Jetpack-Compose-Demo - Instagram Profile UI using Jetpack Compose
Jetpack-Compose-Demo - Instagram Profile UI using Jetpack Compose

Jetpack-Compose-Demo Instagram Profile UI using Jetpack Compose

Aug 11, 2022
Jetpack-compose-animations-examples - Cool animations implemented with Jetpack compose
Jetpack-compose-animations-examples - Cool animations implemented with Jetpack compose

Jetpack-compose-animations-examples This repository consists of 4 animations: St

Aug 9, 2022
Compose-navigation - Set of utils to help with integrating Jetpack Compose and Jetpack's Navigation

Jetpack Compose Navigation Set of utils to help with integrating Jetpack Compose

Apr 5, 2022
Jetpack-compose-uis - A collection of some UIs using Jetpack Compose. built using Katalog

Jetpack Compose UIs This is a collection of some UIs using Jetpack Compose. It i

May 1, 2022
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

Aug 7, 2022
A Kotlin library to use Jetpack Compose in Android and iOS. Allow to write UI for both in Kotin. Still experimental as many compose features are not yet available.
A Kotlin library to use Jetpack Compose in Android and iOS. Allow to write UI for both in Kotin. Still experimental as many compose features are not yet available.

Multiplatform Compose A Kotlin library to use Jetpack Compose in Android and iOS. Allow to write UI for both in Kotin. Still experimental as many comp

Aug 11, 2022
Compose-Ratingbar-library - A simple implementation for rating bar in Jetpack Compose

Compose-Ratingbar-library - A simple implementation for rating bar in Jetpack Compose

Jul 5, 2022
Compose Curved-Scroll is an Android Jetpack Compose library made with ❤️
Compose Curved-Scroll is an Android Jetpack Compose library made with ❤️

Compose-Curved-Scroll-library Compose Curved-Scroll is an Android Jetpack Compos

Feb 17, 2022
Android.compose.squircle - Android LightWeight Squircle Library for JetPack Compose

Android LightWeight Squircle Library for JetPack Compose Usage Based on Compose

Jul 5, 2022
Compose-html - An Android library which provides HTML support for Jetpack Compose texts
Compose-html - An Android library which provides HTML support for Jetpack Compose texts

HtmlCompose An Android library which provides HTML support for Jetpack Compose t

Jul 31, 2022
An application that i developed with a aim of learning Jetpack compose and many other jetpack libraries
An application that i developed with a aim of learning Jetpack compose and many other jetpack libraries

An application that i developed with a aim of learning Jetpack compose and many other jetpack libraries, The application make use of jikan Api which displays a list of animations,there more details and even trailers of the animations.

Jul 27, 2022
Lightweight library to tweak the fling behaviour in Android. This library is only compatible with Jetpack-Compose.
Lightweight library to tweak the fling behaviour in Android. This library is only compatible with Jetpack-Compose.

Flinger (Only compatible with compose) What is Flinger? Flinger is a plugin that is made on top of jetpack compose that will help the developer to twe

Aug 5, 2022
K5-compose is a sketchy port of p5.js for Jetpack Compose
K5-compose is a sketchy port of p5.js for Jetpack Compose

k5-compose k5-compose is a sketchy port of P5.js for Jetpack Compose Desktop. This library provides you a playground to play with your sketches so you

Aug 12, 2022
Jetpack Compose based project, used to stress-testing compose features / integrations and explore non-trivial functionality

Project containing Jetpack Compose samples For pagination & network images it uses CATAAS. Known issues Navigation-Compose Issue with fast tapping on

Aug 3, 2022
Pokedex Compose is an independent re-write of a demo application by the name of Pokedex, but written in jetpack compose.
Pokedex Compose is an independent re-write of a demo application by the name of Pokedex, but written in jetpack compose.

Pokedex Compose Pokedex Compose is an independent re-write of a similar project by the name of Pokedex. I am recreating the UI but I am doing it using

May 1, 2022
Compose-Instagram-Profile-UI - Instagram profile screen UI using android jetpack compose
Compose-Instagram-Profile-UI - Instagram profile screen UI using android jetpack compose

Compose-Intsgram-Profile-UI Instagram profile screen UI using android jetpack co

Mar 8, 2022