πŸš€πŸŒ†πŸ™ Display differences or animate progress between 2 images or Composables with overlay and customization options, zoom, pan gestures, and progress to observe properties for animating before-after progress

Overview

Compose Before-After

Composables to display Images, or Composables as before and after composables to display differences or animate progress between 2 layouts or Composables with overlay and customization options and progress observe properties for animating before-after progress

before-after.mp4

Gradle Setup

To get a Git project into your build:

  • 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
dependencies {
    implementation 'com.github.SmartToolFactory:Compose-BeforeAfter:<version>'
}

BeforeAfterImage

Image that takes two `ImageBitmaps as parameter and displays them based on specified order. By default Labels and Overlay is provided and overload function that accept other Composables as overlay to customize

@Composable
fun BeforeAfterImage(
    modifier: Modifier = Modifier,
    beforeImage: ImageBitmap,
    afterImage: ImageBitmap,
    enableProgressWithTouch: Boolean = true,
    enableZoom: Boolean = true,
    contentOrder: ContentOrder = ContentOrder.BeforeAfter,
    overlayStyle: OverlayStyle = OverlayStyle(),
    beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder = contentOrder) },
    afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder = contentOrder) },
    contentScale: ContentScale = ContentScale.Fit,
    alignment: Alignment = Alignment.Center,
    contentDescription: String? = null,
) {
}

and

@Composable
fun BeforeAfterImage(
    modifier: Modifier = Modifier,
    beforeImage: ImageBitmap,
    afterImage: ImageBitmap,
    enableProgressWithTouch: Boolean = true,
    enableZoom: Boolean = true,
    contentOrder: ContentOrder = ContentOrder.BeforeAfter,
    @FloatRange(from = 0.0, to = 100.0) progress: Float = 50f,
    onProgressChange: ((Float) -> Unit)? = null,
    overlayStyle: OverlayStyle = OverlayStyle(),
    beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder = contentOrder) },
    afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder = contentOrder) },
    contentScale: ContentScale = ContentScale.Fit,
    alignment: Alignment = Alignment.Center,
    contentDescription: String? = null,
)

overloads has default DefaultOverlay

@Composable
internal fun DefaultOverlay(
    width: Dp,
    height: Dp,
    position: Offset,
    overlayStyle: OverlayStyle
) 
@Composable
fun BeforeAfterImage(
    modifier: Modifier = Modifier,
    beforeImage: ImageBitmap,
    afterImage: ImageBitmap,
    enableProgressWithTouch: Boolean = true,
    enableZoom: Boolean = true,
    contentOrder: ContentOrder = ContentOrder.BeforeAfter,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    contentDescription: String? = null,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
    filterQuality: FilterQuality = DrawScope.DefaultFilterQuality,
    beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder = contentOrder) },
    afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder = contentOrder) },
    overlay: @Composable BeforeAfterImageScope.() -> Unit
)

and

@Composable
fun BeforeAfterImage(
    modifier: Modifier = Modifier,
    beforeImage: ImageBitmap,
    afterImage: ImageBitmap,
    enableProgressWithTouch: Boolean = true,
    enableZoom: Boolean = true,
    contentOrder: ContentOrder = ContentOrder.BeforeAfter,
    @FloatRange(from = 0.0, to = 100.0) progress: Float = 50f,
    onProgressChange: ((Float) -> Unit)? = null,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    contentDescription: String? = null,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
    filterQuality: FilterQuality = DrawScope.DefaultFilterQuality,
    beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder = contentOrder) },
    afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder = contentOrder) },
    overlay: @Composable BeforeAfterImageScope.() -> Unit
)

has overlayparameters to add another Composable to draw overlay

Usage

BeforeAfterImage(
    modifier = Modifier
        .clip(RoundedCornerShape(10.dp))
        .fillMaxWidth()
        .aspectRatio(4 / 3f),
    beforeImage = imageBefore,
    afterImage = imageAfter,
    contentScale = contentScale
)

or

BeforeAfterImage(
    modifier = Modifier
        .clip(RoundedCornerShape(10.dp))
        .border(3.dp, Color(0xffE91E63), RoundedCornerShape(10.dp))
        .fillMaxWidth()
        .aspectRatio(4 / 3f),
    beforeImage = imageBefore3,
    afterImage = imageAfter3,
    progress = progress,
    onProgressChange = {},
    contentScale = contentScale,
)

Parameters

  • beforeImage image that show initial progress
  • afterImage image that show final progress
  • enableProgressWithTouch flag to enable drag and change progress with touch
  • enableZoom when enabled images are zoomable and pannable
  • contentOrder order of images to be drawn
  • alignment determines where image will be aligned inside BoxWithConstraints
  • contentScale how image should be scaled inside Canvas to match parent dimensions.
  • ContentScale.Fit for instance maintains src ratio and scales image to fit inside the parent.
  • alpha Opacity to be applied to beforeImage from 0.0f to 1.0f representing fully transparent to fully opaque respectively
  • colorFilter ColorFilter to apply to the beforeImage when drawn into the destination
  • filterQuality Sampling algorithm applied to the beforeImage when it is scaled and drawn into the destination. The default is FilterQuality.Low which scales using a bilinear sampling algorithm
  • overlay is a Composable that can be matched at exact position where beforeImage is drawn. This is useful for drawing thumbs, cropping or another layout that should match position with the image that is scaled is drawn

BeforeAfterLayout

Layout can draw any Composable, image, or video as before and after layout and can be zoomed and panned when [enableZoom] is true and returns a callback to animate before/after progress

@Composable
fun BeforeAfterLayout(
    modifier: Modifier = Modifier,
    enableProgressWithTouch: Boolean = true,
    enableZoom: Boolean = true,
    contentOrder: ContentOrder = ContentOrder.BeforeAfter,
    overlayStyle: OverlayStyle = OverlayStyle(),
    beforeContent: @Composable () -> Unit,
    afterContent: @Composable () -> Unit,
    beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder = contentOrder) },
    afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder = contentOrder) },
)

and

@Composable
fun BeforeAfterLayout(
    modifier: Modifier = Modifier,
    enableProgressWithTouch: Boolean = true,
    enableZoom: Boolean = true,
    contentOrder: ContentOrder = ContentOrder.BeforeAfter,
    @FloatRange(from = 0.0, to = 100.0) progress: Float = 50f,
    onProgressChange: ((Float) -> Unit)? = null,
    overlayStyle: OverlayStyle = OverlayStyle(),
    beforeContent: @Composable () -> Unit,
    afterContent: @Composable () -> Unit,
    beforeLabel: @Composable BoxScope.() -> Unit = { BeforeLabel(contentOrder = contentOrder) },
    afterLabel: @Composable BoxScope.() -> Unit = { AfterLabel(contentOrder = contentOrder) },
) 

Usage

Customize

        BeforeAfterLayout(
    modifier = Modifier
        .shadow(1.dp, RoundedCornerShape(10.dp))
        .fillMaxWidth()
        .aspectRatio(4 / 3f),
    beforeContent = {
        DemoImage(imageBitmap = imageBefore)
    },
    afterContent = {
        DemoImage(imageBitmap = imageAfter)
    },
    overlayStyle = OverlayStyle(
        dividerColor = Color(0xffF44336),
        dividerWidth = 2.dp,
        thumbShape = CutCornerShape(8.dp),
        thumbBackgroundColor = Color.Red,
        thumbTintColor = Color.White
    )
)

Display difference between Composables with Material Design2 and M3

        BeforeAfterLayout(
    modifier = Modifier
        .padding(8.dp)
        .fillMaxWidth(),
    progress = progress,
    beforeContent = {
        BeforeComposable(progress)
    },
    afterContent = {
        AfterComposable(progress)
    },
    enableProgressWithTouch = false,
    enableZoom = false,
    beforeLabel = null,
    afterLabel = null,
    overlay = null
)

Animate like a ProgressBar

val transition: InfiniteTransition = rememberInfiniteTransition()

// Infinite progress animation
val progress by transition.animateFloat(
    initialValue = 0f,
    targetValue = 100f,
    animationSpec = infiniteRepeatable(
        animation = tween(
            durationMillis = 4000,
            easing = FastOutSlowInEasing
        ),
        repeatMode = RepeatMode.Reverse
    )
)

BeforeAfterLayout(
    modifier = Modifier
        .padding(8.dp)
        .fillMaxWidth(),
    progress = progress,
    beforeContent = {
        BeforeComposable(progress)
    },
    afterContent = {
        AfterComposable(progress)
    },
    enableProgressWithTouch = false,
    enableZoom = false,
    beforeLabel = null,
    afterLabel = null,
    overlay = null
)

Display before and after videos with Exoplayer

⚠️ Note there is a bug with Exoplayer2.

If you have a fix please open a PR or answer this question Both are appreciated greatly

BeforeAfterLayout(
    modifier = Modifier
        .fillMaxSize()
        .aspectRatio(4 / 3f),
    beforeContent = {
        MyPlayer(
            modifier = Modifier
                .border(3.dp, Color.Red),
            uri = "asset:///floodplain_dirty.mp4"
        )
    },
    afterContent = {
        MyPlayer(
            modifier = Modifier
                .border(3.dp, Color.Yellow),
            uri = "asset:///floodplain_clean.mp4"
        )
    },
    enableZoom = false
)
You might also like...
Add IndustrialTNT like from old IC2 mod which keeps items after explosion and helps to mine resources
Add IndustrialTNT like from old IC2 mod which keeps items after explosion and helps to mine resources

IndustrialTNT Add IndustrialTNT like from old IC2 mod which keeps items after ex

Compose-buttons - A set of Loading animations used in Buttons to convey a
Compose-buttons - A set of Loading animations used in Buttons to convey a "loading" state after the button is clicked.

Loading Buttons A set of Loading animations used in Buttons to convey a "loading" state after the button is clicked. A simple demo application that sh

Easy zoom in with drag support for Jetpack Compose
Easy zoom in with drag support for Jetpack Compose

ComposeZoomableImage Jetpack Compose Zoomable Image Android Library Easy zoom in with drag support for Jetpack Compose Demo Setup Add Jitpack maven {

πŸš€πŸ“’πŸ“ Indicators for Horizontal or Vertical Pager with different orientation, color, size options and optional touch feature.

Compose Pager Indicator Indicators for Horizontal or Vertical pager with different orientation, color, size options and optional touch feature. indica

Sample repo that demonstrates various options for testing Jetpack Compose applications.

Composing With Confidence This is the sample repository for the Composing With Confidence presentation from Droidcon NYC in 2022. If you run the sampl

Simple composable for rendering transitions between backstacks.
Simple composable for rendering transitions between backstacks.

compose-backstack Simple library for Jetpack Compose for rendering backstacks of screens and animated transitions when the stack changes. It is not a

This library will make it easier to pass arguments between screens in Jetpack Compose.
This library will make it easier to pass arguments between screens in Jetpack Compose.

Compose Navigation This library will make it easier to pass arguments between screens in Jetpack Compose Setup allprojects { repositories { ...

πŸš€πŸžπŸ’ͺ 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

🎨 Jetpack Compose canvas library that helps you draw paths, images on canvas with color pickers and palettes
🎨 Jetpack Compose canvas library that helps you draw paths, images on canvas with color pickers and palettes

🎨 Jetpack Compose canvas library that helps you draw paths and images on canvas with color pickers and palettes. Sketchbook also provides useful components and functions that can easily interact with canvas.

Releases(1.0.0-alpha01)
Owner
Smart Tool Factory
πŸš€ Building colorful and shiny things with Compose(Jetpack Compose Artist🎨)
Smart Tool Factory
Dynamic Badge with customizable features as max number before displaying with +, color, shadow, border, corner radius, font properties and more written with Jetpack Compose

✏️?? Dynamic Badge with customizable features as max number before displaying with +, color, shadow, border, corner radius, font properties and more written with Jetpack Compose. Displays numbers either in circle or rounded rectangle shape based on badge count and selected threshold to transform from circle to rounded rectangle.

Smart Tool Factory 4 Jul 27, 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
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

Saurabh Pant 20 Dec 22, 2022
Common preference/settings Composables for Jetpack Compose.

ComposePrefs ComposePrefs is a preferences library for Jetpack Compose which makes it easy to implement preferences/settings in your Compose Android a

Jamal Mulla 54 Jan 5, 2023
Puck - Make composables draggable with kotlin

Puck Make Composables Draggable. Including in your project Gradle Add below code

Shivam Dhuria 44 Dec 10, 2022
ComposePrefs3 is a fully featured library of preference composables for Jetpack Compose.

ComposePrefs3 This is the M3 version of ComposePrefs. The M2 version can be found here. ComposePrefs3 is a preferences library for Jetpack Compose whi

Jamal Mulla 21 Dec 2, 2022
An exploratory playground library to figure out how to Draw and animate using Jetpack Compose

Jetpack Compose Chart Library This is an exploratory playground library to figure out how to Draw and animate using Android Jetpack Compose library. C

null 2 Sep 8, 2022
Grid Shimmer Animate With JetPack Compose

Grid Shimmer Animate With JetPack Compose

mohamed tamer 2 Jun 19, 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
A Jetpack Compose Modifier that enables Tinder-like card gestures.

Compose Tinder Card A Jetpack Compose Modifier that enables Tinder-like card gestures. Demo Click the play button to see the Modifier.swipeableCard()

Alex Styl 93 Dec 28, 2022