Tutorial Pembuatan Aplikasi Dice Roller Interaktif dengan Jetpack Compose

Nama    : Iftala Zahri Sukmana

NRP      : 5025221002

Kelas    : G

Link GitHub : https://github.com/ifzahri/ppb/tree/main/DiceRoller

Pada kesempatan kali ini, kita akan mempelajari cara membuat aplikasi Dice Roller (Pelempar Dadu) yang interaktif menggunakan Jetpack Compose dan Kotlin. Aplikasi ini tidak hanya menampilkan animasi pelemparan dadu, tetapi juga menyimpan riwayat lemparan terakhir untuk pengalaman pengguna yang lebih menarik.

Persiapan Awal

Sebelum memulai, pastikan Anda telah menginstal Android Studio versi terbaru. Untuk tutorial ini, kita akan menggunakan Jetpack Compose - UI toolkit modern untuk Android yang ditulis dalam bahasa Kotlin.

Langkah 1: Membuat Proyek Baru

  1. Buka Android Studio
  2. Pilih "New Project"
  3. Pilih "Empty Compose Activity"
  4. Beri nama proyek "Dice Roller"
  5. Atur package name menjadi "com.example.diceroller"
  6. Pilih Kotlin sebagai bahasa pemrograman
  7. Klik "Finish"

Membuat Aset Gambar Dadu

Untuk aplikasi ini, kita membutuhkan gambar dadu dengan angka 1 sampai 6. Kita akan membuat gambar vektor (Vector Drawable) untuk setiap sisi dadu.

Langkah 2: Menambahkan Sumber Daya Gambar Dadu

  1. Klik kanan pada folder res/drawable
  2. Pilih "New" → "Vector Asset" atau "New" → "File"
  3. Buat file XML untuk setiap dadu (dice_1.xml hingga dice_6.xml)

Contoh kode untuk dice_1.xml:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:viewportWidth="200"
android:viewportHeight="200">
<path
android:fillColor="#FFFFFF"
android:pathData="M20,20L180,20L180,180L20,180z"
android:strokeWidth="8"
android:strokeColor="#000000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#000000"
android:pathData="M100,100m-15,0a15,15 0,1 1,30 0a15,15 0,1 1,-30 0" />
</vector>

Catatan: Ulangi langkah yang sama untuk dadu lainnya (dice_2.xml hingga dice_6.xml) dengan memodifikasi posisi titik sesuai dengan pola dadu.

Menambahkan String Resources

Langkah 3: Modifikasi File Strings.xml

Buka file res/values/strings.xml dan tambahkan string yang diperlukan:

<resources>
<string name="app_name">Dice Roller</string>
<string name="roll">Roll</string>
<string name="roll_history">Roll History</string>
</resources>

Kode MainActivity

Langkah 4: Menerapkan Kode MainActivity.kt

Ganti konten file MainActivity.kt dengan kode berikut:

package com.example.diceroller
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.diceroller.ui.theme.DiceRollerTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
DiceRollerTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
DiceRollerApp()
}
}
}
}
}
@Composable
fun DiceRollerApp() {
var diceValue by remember { mutableStateOf(1) }
var isRolling by remember { mutableStateOf(false) }
var diceHistory by remember { mutableStateOf(listOf<Int>()) }
val rotation by animateFloatAsState(
targetValue = if (isRolling) 360f else 0f,
animationSpec = tween(500),
finishedListener = {
isRolling = false
}
)
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = stringResource(R.string.app_name),
fontSize = 28.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(bottom = 24.dp)
)
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(200.dp)
.padding(16.dp)
.clip(RoundedCornerShape(8.dp))
.background(Color(0xFFE0E0E0))
.clickable {
rollDice(
onRollStart = { isRolling = true },
onNewValue = { newValue ->
diceValue = newValue
diceHistory = diceHistory + newValue
if (diceHistory.size > 10) {
diceHistory = diceHistory.drop(1)
}
}
)
}
) {
Image(
painter = painterResource(getDiceImageResource(diceValue)),
contentDescription = diceValue.toString(),
modifier = Modifier
.size(140.dp)
.rotate(rotation)
)
}
Spacer(modifier = Modifier.height(24.dp))
Button(
onClick = {
rollDice(
onRollStart = { isRolling = true },
onNewValue = { newValue ->
diceValue = newValue
diceHistory = diceHistory + newValue
if (diceHistory.size > 10) {
diceHistory = diceHistory.drop(1)
}
}
)
},
modifier = Modifier.padding(16.dp)
) {
Text(
text = stringResource(R.string.roll),
fontSize = 18.sp
)
}
Spacer(modifier = Modifier.height(32.dp))
if (diceHistory.isNotEmpty()) {
Text(
text = stringResource(R.string.roll_history),
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(8.dp)
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.Center
) {
diceHistory.forEach { value ->
Image(
painter = painterResource(getDiceImageResource(value)),
contentDescription = value.toString(),
modifier = Modifier
.size(40.dp)
.padding(horizontal = 4.dp)
)
}
}
}
}
}
private fun rollDice(onRollStart: () -> Unit, onNewValue: (Int) -> Unit) {
onRollStart()
val newValue = (1..6).random()
onNewValue(newValue)
}
private fun getDiceImageResource(diceValue: Int): Int {
return when (diceValue) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
}
@Preview(showBackground = true)
@Composable
fun DiceRollerPreview() {
DiceRollerTheme {
DiceRollerApp()
}
}

Penjelasan Kode

Mari kita bahas komponen utama dari aplikasi kita:

1. State Management

var diceValue by remember { mutableStateOf(1) }
var isRolling by remember { mutableStateOf(false) }
var diceHistory by remember { mutableStateOf(listOf<Int>()) }

Kode ini membuat tiga variabel state:

  • diceValue: menyimpan nilai dadu saat ini (1-6)
  • isRolling: status apakah dadu sedang berputar atau tidak
  • diceHistory: menyimpan riwayat hasil lemparan dadu sebelumnya

2. Animasi Rotasi

val rotation by animateFloatAsState(
targetValue = if (isRolling) 360f else 0f,
animationSpec = tween(500),
finishedListener = {
isRolling = false
}
)

Kode ini membuat animasi rotasi 360 derajat ketika dadu dilempar. Animasi berlangsung selama 500 milidetik, dan ketika selesai, status isRolling diubah menjadi false.

3. Fungsi Pelemparan Dadu

private fun rollDice(onRollStart: () -> Unit, onNewValue: (Int) -> Unit) {
onRollStart()
val newValue = (1..6).random()
onNewValue(newValue)
}

Fungsi ini menghasilkan angka acak antara 1 dan 6, dan memanggil callback-callback yang diberikan untuk menangani permulaan dan hasil lemparan.

4. Fitur Riwayat Lemparan

diceHistory = diceHistory + newValue
if (diceHistory.size > 10) {
diceHistory = diceHistory.drop(1)
}

Kode ini menambahkan hasil lemparan baru ke riwayat dan membatasi ukuran riwayat hingga maksimal 10 lemparan terakhir.

Fitur Utama Aplikasi

Aplikasi Dice Roller kita memiliki beberapa fitur menarik:

  1. Interaksi yang Intuitif: Pengguna dapat melempar dadu dengan menekan tombol "Roll" atau dengan mengklik langsung pada gambar dadu.

  2. Animasi Rotasi: Setiap kali dadu dilempar, gambar dadu akan berputar 360 derajat, memberikan efek visual yang lebih menarik.

  3. Riwayat Lemparan: Aplikasi menyimpan dan menampilkan hingga 10 hasil lemparan terakhir, sehingga pengguna dapat melihat pola atau tren dari lemparan sebelumnya.

  4. Antarmuka Modern: Dengan Jetpack Compose, aplikasi memiliki tampilan yang bersih dan modern dengan penempatan elemen yang tepat.


Kesimpulan

Dalam tutorial ini, kita telah berhasil membuat aplikasi Dice Roller interaktif menggunakan Jetpack Compose. Aplikasi ini menunjukkan bagaimana menggunakan fitur-fitur Compose seperti state management, animasi, dan layout yang responsif untuk menciptakan pengalaman pengguna yang menarik.

Aplikasi ini juga mendemonstrasikan pola desain yang baik seperti:

  • Komponen yang dapat digunakan kembali
  • Pemisahan antara UI dan logika
  • Penanganan state yang efektif
  • Penggunaan animasi untuk meningkatkan pengalaman pengguna

Komentar

Postingan populer dari blog ini

Aplikasi Starbucks Clone dengan Android Studio

Membuat Login Form Elegan dengan Jetpack Compose di Android Studio