Skip to content

Latest commit

 

History

History
86 lines (74 loc) · 3.19 KB

README.md

File metadata and controls

86 lines (74 loc) · 3.19 KB

Reusable Compose Modifiers

I created this repository with the intention of sharing useful Compose UI modifiers as I come up with them.

Modifier.zoomable

The first one of many to come is the zoomable modifier that makes the modified element zoomable by capturing pinching and panning gestures. It also supports double-tap gesture for auto zooming in and out.

An obvious use case for this modifier is when you want to create a zoomable image viewer as follows:

@Composable
fun ZoomableImage(
    imageUri: String,
    modifier: Modifier = Modifier,
) {
    Box(modifier = Modifier) {
        AsyncImage(
            model = imageUri,
            placeholder = painterResource(R.drawable.placeholder),
            contentDescription = null,
            alignment = Alignment.Center,
            contentScale = ContentScale.Crop,
            modifier = modifier
                .fillMaxSize()
                .zoomable(
                    enabled = true,
                    minScale = 1f,
                    maxScale = 4f,
                    panningSpeedMultiplier = 2f,
                    doubleTapEnabled = true,
                    doubleTapScale = 3f,
                    animate = true,
                    scaleAnimationSpec = spring(
                        dampingRatio = Spring.DampingRatioLowBouncy,
                        stiffness = Spring.StiffnessLow
                    ),
                    panAnimationSpec = spring(
                        dampingRatio = Spring.DampingRatioLowBouncy,
                        stiffness = Spring.StiffnessVeryLow
                    ),
                    doubleTapScaleAnimationSpec = tween(durationMillis = 500),
                    doubleTapPanAnimationSpec = tween(durationMillis = 500),
                ),
            )
        Text(
            text = "Pinch to zoom, double-tap to zoom in/out, pan to explore zoomed image.",
            color = Color.LightGray,
            modifier = Modifier
                .align(Alignment.BottomCenter)
                .padding(16.dp)
        )
    }
}

Here is what it will look like:

zoomable-modifier-in-action

When your zoomable content is inside a container that has to detect touch gestures, like a HorizontalPager that relys on swipe gestures, you can apply the zoomable modifier to the container instead of the content. This way, the zoomable content will not interfere with the swipe gestures. Here is an example (you can see the full example here):

HorizontalPager(
    state = pagerState,
    modifier = modifier
        .fillMaxSize()
        .zoomable(),
) { page ->

    val image = images[page]
    AsyncImage(
        model = image,
        placeholder = painterResource(R.drawable.placeholder),
        contentDescription = null,
        alignment = Alignment.Center,
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .fillMaxSize()
    )
}

And here is what it will look like:

zoomable-modifier-in-action