Text Clock in Android using Jetpack Compose

Text Clock in Android using Jetpack Compose
A text clock is a type of clock that displays the time using digits, as opposed to an analog clock, which uses rotating hands to indicate the time. Digital clocks typically show hours, minutes, and sometimes seconds in numerical form, usually on an LED or LCD screen.

Why Digital Clocks Are Perfect for Learning Jetpack Compose?

When diving into Android development with Jetpack Compose, choosing the right project to start with is crucial. While there are countless possibilities, building a digital clock stands out as an ideal beginner project. Here’s why:

1. Simplicity Meets Functionality

A digital clock, at its core, is straightforward: it displays the current time. You don't have to deal with complex data structures or intricate logic—your focus is on building a clean, functional UI.

Why It Matters:
Starting with a simple project reduces the learning curve. You can focus on understanding Compose’s syntax, UI components, and state management without being bogged down by complicated requirements.

2. Real-Time Data Handling

A digital clock updates every second, providing a perfect scenario to learn how Jetpack Compose handles real-time data. You'll need to continuously update the displayed time, which introduces you to State and Effect APIs in Compose.

Why It Matters:
Handling real-time updates is a common requirement in many apps, from clocks to live feeds. Learning this early on will prepare you for more complex scenarios in the future.

3. Understanding State Management

In Jetpack Compose, a digital clock needs to maintain and update its state to reflect the current time accurately. By building a digital clock, you’ll gain hands-on experience with managing state in a Compose-friendly way.

Why It Matters:
Mastering state management is crucial for building responsive and dynamic UIs in Android apps. A digital clock gives you a practical, real-world example of how state management works in Compose.

4. Customization and Styling

Once you have the basic digital clock working, there’s plenty of room for customization. You can experiment with different fonts, colors, and layouts, learning how to apply themes and styles in Jetpack Compose.

Why It Matters:
This gives you the freedom to experiment and see immediate results, helping you learn how different UI elements work together.

5. Introduction to Animations

Adding animations to a digital clock, like smooth transitions between seconds or a fade effect, introduces you to the animation APIs in Jetpack Compose. Animations can bring your UI to life, making the clock not only functional but also visually engaging.

Why It Matters:
Learning animations in Compose early on will give you the tools to enhance user experience in future projects, making your apps more interactive and polished.

6. Expandable to Advanced Features

While the basic digital clock is a simple project, it can easily be expanded into more complex features. For example, you could add:

Date Display: Show the current date alongside the time.
World Clock: Display times from different time zones.
Alarm Functionality: Allow users to set alarms with notifications.
Widgets: Create a homescreen widget for the clock.
Why It Matters:
Starting with a simple clock and gradually adding features allows you to learn progressively, building on your knowledge without getting overwhelmed.

7. Immediate Feedback and Satisfaction

One of the most satisfying aspects of building a digital clock is that you see immediate results. As you code, you watch the clock tick, confirming that your app is functioning correctly. This instant feedback loop is incredibly motivating, especially for beginners.

Why It Matters:
Quick, visible progress keeps you engaged and motivated to continue learning. It also helps you quickly identify and fix issues as you develop.

Lets build a Text Clock?

In this tutorial, you'll learn how to build a basic digital clock using Android Jetpack Compose. This project is perfect for beginners who want to get hands-on experience with Jetpack Compose, working with real-time updates and dynamic UI elements.

Steps

  1. Open Android Studio.
  2. Create a new project with an Empty Compose Activity template.
  3. Creating the Basic Digital Clock UI
Now, let's create a simple UI for our digital clock. We'll start by defining a Composable function that displays the current time.

MainActivity

Copy this code →

package com.codingbihar.jetpackcomposeskill

impoort ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
            enableEdgeToEdge()
            setContent {
                JetpackComposeSkillTheme {
                 ClockScreen()
                }
            }
        }
    }

ClockScreen

Copy this code →

package com.codingbihar.jetpackcomposeskill

impoort ...

@Composable
fun ClockScreen() {
    val time12Hour = remember { mutableStateOf("") }
    val time24Hour = remember { mutableStateOf("") }
    LaunchedEffect(Unit) {
        while (true) {
            val currentTime = Calendar.getInstance().time
            time12Hour.value = SimpleDateFormat("hh:mm:ss a", Locale.getDefault()).format(currentTime)
            time24Hour.value = SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(currentTime)
            delay(1000L)
        }
    }

        Box(modifier = Modifier
            .padding(top = 46.dp)
            .fillMaxSize()
            .background(color = Color.Black),
            contentAlignment = Alignment.TopCenter
           
        ){
            Column {
             
                DrawClockCircle(time = time12Hour.value, label = "12-hour format")
                Spacer(modifier = Modifier.height(32.dp))
                DrawClockCircle(time = time24Hour.value, label = "24-hour format")

        }
    }
}

@Composable
fun DrawClockCircle(time: String, label: String) {
    Box(
        modifier = Modifier
            .size(200.dp),
        contentAlignment = Alignment.Center
    ) {
        Canvas(modifier = Modifier.fillMaxSize()) {
            drawCircle(
                color = Color.Yellow,              
            )
        }
        Column(
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                text = time,
                color = Color.Black,
                fontSize = 24.sp,
                fontWeight = FontWeight.Bold
            )
            Spacer(modifier = Modifier.height(8.dp))
            Text(
                text = label,
                color = Color.Gray,
                fontSize = 16.sp
            )
        }
    }
}

OUTPUT:

Text Clock in Android using Jetpack Compose
Text Clock Output in Android using Jetpack Compose

Lets create an another animated digital clock

Clock Screen Composable

ClockScreen is the main composable function responsible for displaying the clock. It handles the logic of updating the time every second.



currentTime(): A helper function that fetches the current time and returns it as a Time object.


remember & mutableStateOf: Used to remember and update the time state within the composable.


LaunchedEffect: A coroutine that continuously updates the time every second.

NumberColumn: Displays a single column of digits, animating between them as the time changes.

Spacer: Adds space between the hour, minute, and second columns.

animateDpAsState: Used to animate the vertical position of the numbers.

reset: Checks if the current number is at the start of the range, triggering a spring animation for a bounce effect.

animateColorAsState: Animates the background color based on whether the number is active or not.

Copy this code →

package com.codingbihar.jetpackcomposeskill

import ...
          
data class Time(val hours: Int, val minutes: Int, val seconds: Int)

@Composable
fun ClockScreen() {
    fun currentTime(): Time {
        val cal = Calendar.getInstance()
        return Time(
            hours = cal.get(Calendar.HOUR_OF_DAY),
            minutes = cal.get(Calendar.MINUTE),
            seconds = cal.get(Calendar.SECOND),
        )
    }

    var time by remember { mutableStateOf(currentTime()) }
    LaunchedEffect(0) {
        while (true) {
            time = currentTime()
            delay(1000)
        }
    }

    Clock(time)
}

@Composable
fun Clock(time: Time) {
    Row(
        modifier = Modifier.fillMaxSize(),
        horizontalArrangement = Arrangement.Center,
        verticalAlignment = Alignment.CenterVertically,
    ) {
        val padding = Modifier.padding(horizontal = 4.dp)

        NumberColumn(time.hours / 10, 0..2, padding)
        NumberColumn(time.hours % 10, 0..9, padding)

        Spacer(Modifier.size(16.dp))

        NumberColumn(time.minutes / 10, 0..5, padding)
        NumberColumn(time.minutes % 10, 0..9, padding)

        Spacer(Modifier.size(16.dp))

        NumberColumn(time.seconds / 10, 0..5, padding)
        NumberColumn(time.seconds % 10, 0..9, padding)
    }
}

@Composable
fun NumberColumn(
    current: Int,
    range: IntRange,
    modifier: Modifier = Modifier,
) {
    val size = 40.dp

    val mid = (range.last - range.first) / 2f
    val reset = current == range.first
    val offset by animateDpAsState(
        targetValue = size * (mid - current),
        animationSpec = if (reset) {
            spring(
                dampingRatio = Spring.DampingRatioLowBouncy,
                stiffness = Spring.StiffnessLow,
            )
        } else {
            tween(
                durationMillis = 300,
                easing = LinearOutSlowInEasing,
            )
        }
    )

    Column(
        modifier
            .offset(y = offset)
            .clip(RoundedCornerShape(percent = 25))
    ) {
        range.forEach { num ->
            Number(num == current, num, Modifier.size(size))
        }
    }
}

@Composable
fun Number(active: Boolean, value: Int, modifier: Modifier = Modifier) {
    val backgroundColor by animateColorAsState(
        if (active) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.primaryContainer,
        label = "clock",
    )

    Box(
        modifier = modifier.background(backgroundColor),
        contentAlignment = Alignment.Center,
    ) {
        Text(
            text = value.toString(),
            fontSize = 20.sp,
            color = Color.White,
        )
    }
}

OUTPUT:

Output animated digital clock
Previous Post Next Post