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:
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.
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.
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.
Why It Matters:
This gives you the freedom to experiment and see immediate results, helping you learn how different UI elements work together.
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.
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.
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.
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
- Open Android Studio.
- Create a new project with an Empty Compose Activity template.
- 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:
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,
)
}
}