Jetpack Compose: Pass onClick event to a function

Introduction

Jetpack Compose, Android's modern toolkit for building native UI, emphasizes declarative programming to make UI design simpler and more intuitive. In traditional Android development, managing user interactions, such as button clicks, often involves multiple layers of XML layouts and listener implementations. However, Jetpack Compose removes this complexity, making it easier to manage UI interactions through composable functions.

This example demonstrates how to handle onClick events in Jetpack Compose by passing these events to functions. By breaking down this Kotlin example, we can explore how button clicks increment or decrement a counter and how UI components are structured within a Scaffold. This code provides a clean and organized way to manage state and UI actions, illustrating key Compose concepts like state management and composable functions.

MainActivity Setup

In the MainActivity.kt file, the code starts with the MainActivity class, extending AppCompatActivity, which is the base class for activities in Android. The onCreate function, the entry point of the activity, uses setContent to set up the Compose UI. Instead of using an XML layout, setContent takes a composable function—in this case, GetScaffold—which defines the overall structure of the UI. This pattern demonstrates how Jetpack Compose allows developers to completely eliminate XML layouts, relying solely on Kotlin code to manage the UI.

The activity lifecycle is still managed by the underlying Android framework, but Compose handles the UI rendering. This paradigm shift from XML to declarative UI programming greatly simplifies the development process by allowing UI and logic to be handled in one place.

Creating the Scaffold

The GetScaffold function sets up a basic scaffold layout, which is a common pattern in Jetpack Compose. The Scaffold component provides a structure with slots for standard UI elements like a TopAppBar, floating action buttons, and a body for content. In this case, a TopAppBar displays a title, and the main content is rendered by the MainContent composable.

The TopAppBar has a simple setup, with a text title and a background color. Meanwhile, the scaffold's background color is customized to a light tone. This shows how easily Jetpack Compose allows developers to modify layout properties using arguments like backgroundColor.

MainContent and State Management

In MainContent, a column layout is used to align UI components vertically. The code demonstrates a key concept in Jetpack Compose—state management—using the remember and mutableStateOf functions to manage the counter value. remember ensures that the state persists across recompositions, and mutableStateOf provides a reactive state variable that updates the UI whenever the counter value changes.

The Column composable arranges the Text and buttons with spacing and alignment settings. The Text composable displays the current value of the counter, while multiple buttons allow users to manipulate this value.

Handling onClick Events

The core functionality of this example revolves around the buttons, each of which modifies the counter value in different ways. The GetButton composable is a reusable component that takes two parameters: a text string for the button label and an onClick function, which is passed as an event handler.

Several buttons are defined in MainContent, with each one triggering a different modification of the counter when clicked. The onClick lambda is where the event-handling logic resides. For example, the button labeled "Add One" increments the counter by one, while "Add Two" and "Add Five" increase it by two and five, respectively. The "Minus Three" button, on the other hand, decrements the counter by three.

Reusable Button Component

The GetButton composable is designed to be flexible and reusable. It uses the Button composable from the Material Design library, which takes an onClick parameter and a shape to customize its appearance. The RoundedCornerShape(8.dp) argument ensures that the button has rounded corners, giving it a more polished look.

By defining the button layout and padding within GetButton, this composable can be reused with different click handlers and text labels without repeating the layout logic. The separation of concerns—defining how the button looks and how it behaves—makes this a highly modular and readable approach to UI design.

Summary

This Kotlin example effectively demonstrates how Jetpack Compose simplifies state management and UI interactions by passing onClick events to functions. With composables like GetScaffold, MainContent, and GetButton, the code highlights the declarative nature of Compose, making it easy to manage both UI layout and state logic in a clean, readable manner.

By leveraging features like mutableStateOf and reusable components, this example illustrates the power of Jetpack Compose to create dynamic and responsive user interfaces. The simplicity of managing onClick events directly within composable functions underscores how Jetpack Compose transforms Android development into a more intuitive and fluid experience for developers.


MainActivity.kt

package com.cfsuman.jetpackcompose

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedObjectState: Bundle?) {
        super.onCreate(savedObjectState)
        setContent {
            GetScaffold()
        }
    }


    @Composable
    fun GetScaffold() {
        Scaffold(
            topBar = {
                TopAppBar(
                    title = {
                        Text(
                            text = "Compose - Pass onClick event to function"
                        )
                    },
                    backgroundColor = Color(0xFFB9966a),
                )
            },
            content = { MainContent() },
            backgroundColor = Color(0xFFfaf0e6)
        )
    }


    @Composable
    fun MainContent() {
        val counter = remember { mutableStateOf(0)}

        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(8.dp),
            modifier = Modifier
                .fillMaxSize()
                .padding(12.dp)
        ) {
            Text(
                text = "Counter " + counter.value,
                style = MaterialTheme.typography.h4,
                modifier = Modifier.padding(24.dp)
            )

            GetButton(text = "Add One", onClick = {counter.value++})

            GetButton(text = "Add Two") {
                counter.value +=2
            }

            GetButton(text = "Add Five") {
                counter.value +=5
            }

            GetButton(text = "Minus Three") {
                counter.value -=3
            }
        }
    }


    @Composable
    fun GetButton(
        text:String,
        onClick: ()-> Unit,
    ){
        Button(
            onClick = onClick,
            shape = RoundedCornerShape(8.dp)
        ){
            Text(
                text = text,
                Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
            )
        }
    }
}
More android jetpack compose tutorials

Jetpack Compose: Long click listener

Introduction

Jetpack Compose is Google's modern toolkit for building native Android UI, allowing developers to write less code and make it more readable and maintainable. One of its standout features is how it simplifies handling gestures like taps, swipes, and long presses. In this article, we’ll explore a practical example of handling long-click actions using Jetpack Compose. We'll break down the code in a programmer-friendly way, so even if you're new to Compose, you'll grasp how to implement interactive UI components with long-press gestures.

Our example demonstrates a simple long-click listener that changes the shape of a box when either clicked or long-clicked, using Kotlin and Jetpack Compose. Let’s break down the code and understand how this is achieved in an easy-to-follow manner.

Breakdown of the Code: MainActivity Setup

The MainActivity class is where our Compose content begins. In the onCreate method, instead of using XML layouts, Jetpack Compose allows us to define UI directly in Kotlin code. The setContent method is called, and inside it, we load the GetScaffold() composable function, which sets up our main screen layout using a Scaffold.

The Scaffold Layout

Scaffold is a powerful layout in Jetpack Compose that provides a consistent structure for screens. It typically contains a top bar, content area, and other components like bottom navigation or floating action buttons. In our example, the Scaffold contains a TopAppBar with a title that reads "Compose - Long click listener" and a background color of green (0xFF4f7942). The content of the screen is provided by the MainContent() composable, which holds the core logic for handling click and long-click events.

MainContent: Handling Click and Long Click

The heart of the example is within the MainContent composable. Here, we declare two remember states: one for the message displayed in the UI, and another for the shape of the box that changes based on user interaction. The remember function is key in Jetpack Compose as it allows the state to persist across recompositions, ensuring that UI changes are reflected properly when the state updates.

Next, we define a Column that centers its content horizontally and vertically. Inside this column is a Box, which acts as the interactive UI element that responds to clicks and long clicks. The Box is styled with a background color (0xFF50c878), and its shape is initially set to a RoundedCornerShape.

Handling Gestures with CombinedClickable

The key functionality of the code lies in the combinedClickable modifier attached to the Box. This modifier allows us to handle multiple gestures—both click and long-click—on a single UI element. The onClick lambda is triggered when the user performs a standard click, resetting the box’s shape to the default RoundedCornerShape(48.dp) and updating the message to "Clicked." Similarly, the onLongClick lambda handles long presses, changing the shape to a CircleShape and updating the message to "Long Clicked."

The onClickLabel and onLongClickLabel provide accessibility hints, ensuring that the UI remains user-friendly and accessible, particularly for screen readers.

UI Updates with Text and Animation

Inside the Box, a Text composable displays the current value of message. When the user interacts with the Box, the message updates dynamically, providing immediate feedback. Additionally, the size of the box is animated using the animateContentSize() modifier, giving it a smooth transition effect when its shape changes, although this isn't explicitly defined in the example provided.

Summary

This example demonstrates how easily you can handle click and long-click actions in Jetpack Compose using Kotlin. The use of combinedClickable makes it straightforward to differentiate between standard taps and long presses, while remember allows the state to persist across recompositions.

Jetpack Compose’s declarative approach simplifies creating dynamic and interactive UIs like this. By just tweaking a few modifiers and states, we can make a UI component that reacts to user gestures fluidly. Whether you're building a small demo or a full-fledged app, this pattern is a great starting point for adding interactivity to your 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.animateContentSize
import androidx.compose.animation.core.tween
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedObjectState: Bundle?) {
        super.onCreate(savedObjectState)
        setContent {
            GetScaffold()
        }
    }


    @Composable
    fun GetScaffold() {
        Scaffold(
            topBar = {
                TopAppBar(
                    title = {
                        Text(
                            text = "Compose - Long click listener"
                        )
                    },
                    backgroundColor = Color(0xFF4f7942),
                )
            },
            content = { MainContent() },
            backgroundColor = Color(0xFFaddfad)
        )
    }


    @OptIn(ExperimentalFoundationApi::class)
    @Composable
    fun MainContent() {
        val message = remember { mutableStateOf("Click Action")}
        val shape = remember { mutableStateOf(RoundedCornerShape(48.dp))}

        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
            modifier = Modifier.fillMaxSize().padding(12.dp)
        ) {
            Box(
                modifier = Modifier
                    .size(300.dp)
                    .clip(shape.value)
                    .background(SolidColor(Color(0xFF50c878)))
                    .combinedClickable(
                        enabled = true,
                        onClick = {
                            shape.value = RoundedCornerShape(48.dp)
                            message.value = "Clicked"
                        },
                        onClickLabel = "Click to apply rounded shape",
                        onLongClick = {
                            shape.value = CircleShape
                            message.value = "Long Clicked"
                        },
                        onLongClickLabel = "Long click to apply circle shape",
                    )
                    .padding(12.dp),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = message.value,
                    style = MaterialTheme.typography.h5,
                    fontWeight = FontWeight.Bold
                )
            }
        }
    }
}
More android jetpack compose tutorials

Jetpack compose: How to implement double click listener

This code snippet demonstrates how to implement a double click listener in Jetpack Compose.

Here's a breakdown of the code:

  1. Scaffold: The Scaffold function is the foundation of the user interface in Jetpack Compose. It provides a basic structure for the screen, including an optional top app bar, content area, and bottom navigation bar.

  2. TopAppBar: The TopAppBar composes the app bar at the top of the screen. It displays the app title ("Compose - Double click listener" in this case) and can optionally include navigation icons or other elements.

  3. MainContent: The MainContent function defines the content of the screen. In this example, it's a clickable box that changes its shape and displays a message based on the user's interaction.

  4. Box: The Box function creates a container that can hold other composables. It can be sized and positioned using modifiers.

  5. combinedClickable: The combinedClickable modifier allows you to attach both click and double-click listeners to a composable. In this case, the box changes its shape to a circle on a double click and displays the message "Double Clicked". When clicked once, it reverts to its original rounded corner shape and displays the message "Clicked".

  6. Text: The Text function displays text on the screen. The text displayed here updates based on the user's interaction with the box.

In summary, this code shows how to create a clickable element that responds differently to single and double clicks using Jetpack Compose. This can be useful for implementing features like zooming in on an image with a double click.


MainActivity.kt

package com.cfsuman.jetpackcompose

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.unit.dp


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedObjectState: Bundle?) {
        super.onCreate(savedObjectState)
        setContent {
            GetScaffold()
        }
    }


    @Composable
    fun GetScaffold() {
        Scaffold(
            topBar = {
                TopAppBar(
                    title = {
                        Text(
                            text = "Compose - Double click listener"
                        )
                    },
                    backgroundColor = Color(0xFF1ca9c9),
                )
            },
            content = { MainContent() },
            backgroundColor = Color(0xFFF3ebad)
        )
    }


    @OptIn(ExperimentalFoundationApi::class)
    @Composable
    fun MainContent() {
        val message = remember { mutableStateOf("Click Action")}
        val shape = remember { mutableStateOf(RoundedCornerShape(24.dp))}

        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
            modifier = Modifier.fillMaxSize().padding(12.dp)
        ) {
            Box(
                modifier = Modifier
                    .size(250.dp)
                    .clip(shape.value)
                    .background(SolidColor(Color(0xFFE1ae84)))
                    .combinedClickable(
                        enabled = true,
                        onClick = {
                          shape.value = RoundedCornerShape(24.dp)
                            message.value = "Clicked"
                        },
                        onDoubleClick = {
                            shape.value = CircleShape
                            message.value = "Double Clicked"
                        }
                    )
                    .padding(12.dp),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = message.value,
                    style = MaterialTheme.typography.h5
                )
            }
        }
    }
}
More android jetpack compose tutorials