Jetpack Compose: Swiping example

Introduction

Jetpack Compose, the modern toolkit for building native UI in Android applications, offers a flexible and powerful way to create smooth and interactive user interfaces with minimal code. One of the most engaging aspects of user interaction in apps is swiping gestures, which can enhance the overall experience by allowing users to navigate content or perform actions fluidly. In this article, we'll dive into an example that demonstrates how to create a swiping UI component using Jetpack Compose, while also incorporating animated transitions to add a bit of flair.

This guide will walk you through a practical implementation of a swiping feature in Jetpack Compose, where users can swipe a colorful box horizontally. Along the way, we'll explore how to handle state, manage animations, and use gestures in Compose to achieve a smooth and interactive design. Let’s break down how the example code works, step by step.

Setting Up the Main Content

At the core of this example is the MainContent() function, which serves as the main composable that renders the user interface. The design centers around a swiping component where a colorful box can be moved horizontally across the screen. To achieve this, Jetpack Compose's swipeable modifier is employed. This modifier allows the box to respond to swipe gestures and change its position based on user input.

A key element here is the swipeAbleState, which uses rememberSwipeableState() to track the current position of the swipe. The swipeable state works in conjunction with anchors to define where the swipeable box can snap to. In this example, there are two anchor points: one at the starting position (0) and another at the end position, defined based on the size of the box in pixels. The use of anchors ensures that the box either snaps back to its original position or moves fully to the other side when released.

Implementing Animated Color Changes

One of the visually appealing aspects of this swiping example is the animated color change of the box. To accomplish this, the code uses animateColorAsState(), which smoothly transitions the background color of the swipable box whenever the color state changes. The color transition is controlled with a tween() function that specifies a duration of 2,000 milliseconds, creating a gradual and pleasing animation effect.

To change the color dynamically, two IconButton components are included in the UI. These buttons allow users to set the background color of the swipable box to either blue or red. Clicking on one of these buttons updates the state variable bgColor, which triggers the animateColorAsState() function to animate the color change. This integration of gestures and animations showcases the flexibility and power of Jetpack Compose for creating interactive UIs.

Utilizing Swipeable Modifiers and Offsets

The Box composable used for the swiping component includes several modifiers that control its layout and behavior. The swipeable modifier is configured with parameters like anchors, thresholds, and orientation. The FractionalThreshold parameter ensures that the swipe gesture must cover at least 30% of the total distance before it transitions to the next anchor point. This helps create a more intuitive user experience, where the swipable box doesn't move too easily or unintentionally.

In addition, the offset modifier uses the swipeable state’s offset value to position the box dynamically as the user swipes. This offset value is continuously updated based on the swipe gestures, ensuring smooth motion as the box slides back and forth. The IntOffset is used to convert the floating-point offset into integer coordinates, which are then applied to adjust the box's horizontal position on the screen.

Composing a Flexible Layout

The layout of the entire swiping interface is organized using a Column, ensuring that all elements are centered both vertically and horizontally on the screen. This layout structure is wrapped in a Box with rounded corners and padding, providing a clean and visually appealing design. The background color of the entire screen is set to a neutral tone to make the colored swipable box stand out.

The swipable box itself is defined within another Box that fills most of the screen’s width and maintains a fixed height. This design approach keeps the focus on the interactive element, making it the centerpiece of the user interface. By combining layout composables like Box and Column with gesture handling, the code efficiently manages both content organization and interactivity.

Summary

This Jetpack Compose swiping example demonstrates how to leverage the toolkit's powerful capabilities to build engaging and responsive UI components. By integrating gesture handling, animations, and state management, you can create interactive elements that enhance the user experience. The use of swipeable modifiers, state variables, and animated transitions allows for a seamless blend of functionality and aesthetics.

Whether you're looking to implement a swiping feature for navigation, action triggers, or purely visual effects, this example serves as a solid foundation. Jetpack Compose’s concise and intuitive API makes it easier than ever to build dynamic interfaces with minimal effort, paving the way for more creative and interactive Android applications.


MainActivity.kt

package com.cfsuman.jetpackcompose

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ColorLens
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import kotlin.math.roundToInt

class MainActivity : AppCompatActivity() {
    @ExperimentalMaterialApi
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            MainContent()
        }
    }


    @ExperimentalMaterialApi
    @Composable
    fun MainContent(){
        var bgColor:Color by remember {
            mutableStateOf(Color(0xFF88540B))
        }

        val color = animateColorAsState(
            targetValue = bgColor,
            animationSpec = tween(
                durationMillis = 2000
            )
        )

        val squareSize = 150.dp
        val swipeAbleState = rememberSwipeableState(0)
        val sizePx = with(LocalDensity.current) { squareSize.toPx() }
        val anchors = mapOf(0f to 0, sizePx to 1)

        Column(
            modifier = Modifier
                .background(Color(0xFFEDEAE0))
                .fillMaxSize()
                .padding(16.dp),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .clip(RoundedCornerShape(16.dp))
                    .background(Color(0xFFBFAFB2))
                    .padding(8.dp)
                    .swipeable(
                        state = swipeAbleState,
                        anchors = anchors,
                        thresholds = { _, _ ->
                            FractionalThreshold(0.3f)
                        },
                        orientation = Orientation.Horizontal
                    )
            ) {
                Column(
                    modifier = Modifier.padding(16.dp)
                ) {
                    IconButton(onClick = {
                        bgColor = Color(0xFF2A52BE)
                    }) {
                        Icon(
                            Icons.Filled.ColorLens,
                            contentDescription = "Localized description",
                            tint = Color(0xFF2A52BE)
                        )
                    }
                    IconButton(onClick = {
                        bgColor = Color(0xFFE30022)
                    }) {
                        Icon(
                            Icons.Filled.ColorLens,
                            contentDescription = "Localized description",
                            tint = Color(0xFFE30022)
                        )
                    }
                }

                Box(
                    Modifier
                        .offset {
                            IntOffset(
                                swipeAbleState.offset.value.roundToInt(),
                                0
                            )
                        }
                        .clip(RoundedCornerShape(16.dp))
                        .fillMaxWidth(0.95F)
                        .height(150.dp)
                        .background(color.value)
                )
            }
        }
    }


    @Preview
    @Composable
    fun ComposablePreview(){
        //MainContent()
    }
}
More android jetpack compose tutorials