Tugas 8: Membuat Aplikasi Water Bottle menggunakan Material Design
Nama : Fathin Muhashibi Putra
NRP : 5025211229
Kelas : PPB - A
Tugas 8:
Membuat Aplikasi Water Bottle menggunakan Material Design
Pada tugas kali ini, saya membuat aplikasi Water Bottle menggunakan Material Design. Aplikasi ini dapat melacak konsumsi air harian dengan visualisasi botol air dan animasi pengisian air.
1. Buat Proyek Baru
Buka Android Studio dan buat proyek baru dengan memilih Empty Compose Activity. Beri nama proyek "Water Bottle" dan biarkan pengaturan lainnya dalam kondisi default.
2. Komponen WatterBottle
Langkah selanjutnya adalah membuat komponen utama aplikasi yaitu visualisasi botol air. Buat file baru bernama WatterBottle.kt dan implementasikan komponen Composable untuk menampilkan botol air dengan animasi.
@Composable
fun WatterBottle(
modifier: Modifier = Modifier,
totalWaterAmount: Int,
unit: String,
usedWaterAmount: Int,
waterWavesColor: Color = Color(0xff279EFF),
bottleColor: Color = Color.White,
capColor: Color = Color(0xFF0065B9)
) {
val waterPercentage = animateFloatAsState(
targetValue = (usedWaterAmount.toFloat() / totalWaterAmount.toFloat()),
label = "Water Waves animation",
animationSpec = tween(durationMillis = 1000)
).value
val usedWaterAmountAnimation = animateIntAsState(
targetValue = usedWaterAmount,
label = "Used water amount animation",
animationSpec = tween(durationMillis = 1000)
).value
Box(
modifier = modifier
.size(width = 200.dp, height = 600.dp)
) {
Canvas(modifier = Modifier.fillMaxSize()) {
val width = size.width
val height = size.height
val capWidth = size.width * 0.55f
val capHeight = size.height * 0.13f
// Draw the bottle body
val bodyPath = Path().apply {
moveTo(width * 0.3f, height * 0.1f)
lineTo(width * 0.3f, height * 0.2f)
quadraticBezierTo(
0f, height * 0.3f, // The pulling point
0f, height * 0.4f
)
lineTo(0f, height * 0.95f)
quadraticBezierTo(
0f, height,
width * 0.05f, height
)
lineTo(width * 0.95f, height)
quadraticBezierTo(
width, height,
width, height * 0.95f
)
lineTo(width, height * 0.4f)
quadraticBezierTo(
width, height * 0.3f,
width * 0.7f, height * 0.2f
)
lineTo(width * 0.7f, height * 0.2f)
lineTo(width * 0.7f, height * 0.1f)
close()
}
// Implementasi lainnya...
}
// Text untuk menampilkan jumlah air
val text = buildAnnotatedString {
// Implementasi annotated string...
}
Box(
modifier = Modifier
.fillMaxSize()
.fillMaxHeight(),
contentAlignment = Alignment.Center
) {
Text(text = text)
}
}
}
Dalam komponen ini, saya menggunakan Canvas API untuk menggambar bentuk botol air dengan Path. Komponen ini juga termasuk animasi untuk level air dan jumlah yang ditampilkan. Warna air, botol, dan tutup botol dapat disesuaikan melalui parameter.
3. Layout Utama (MainActivity)
Setelah komponen botol air selesai, saya mengimplementasikan layout utama aplikasi di MainActivity.kt yang terdiri dari botol air, informasi total target, dan tombol interaktif.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
WaterBottleTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
var usedWaterAmount by remember {
mutableIntStateOf(0)
}
val totalWaterAmount = remember {
2400
}
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
WatterBottle(
totalWaterAmount = totalWaterAmount,
unit = "ml",
usedWaterAmount = usedWaterAmount
)
Spacer(modifier = Modifier.height(20.dp))
Text(
text = "Total Amount is : $totalWaterAmount ml",
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(20.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Button(
onClick = {
if (usedWaterAmount + 200 <= totalWaterAmount) {
usedWaterAmount += 200
} else {
usedWaterAmount = totalWaterAmount
}
},
colors = ButtonDefaults.buttonColors(containerColor = Color(0xff279EFF))
) {
Text(text = "Drink")
}
Button(
onClick = { usedWaterAmount = 0 },
colors = ButtonDefaults.buttonColors(containerColor = Color.Red)
) {
Text(text = "Reset")
}
}
}
}
}
}
}
}
4. Fitur Utama
Aplikasi Water Bottle memiliki beberapa fitur utama:
- Visualisasi Botol Air Interaktif: Botol air dengan animasi level air yang berubah sesuai dengan jumlah yang diminum
- Pelacakan Konsumsi Air: Menampilkan jumlah air yang telah diminum dan total target harian
- Tombol Drink: Menambahkan 200ml air setiap kali ditekan, dengan validasi untuk tidak melebihi target harian
- Tombol Reset: Mengatur ulang jumlah air yang diminum kembali ke 0
- Animasi Smooth: Transisi halus saat level air berubah
5. Implementasi Canvas dan Path
Bagian yang paling menantang dalam proyek ini adalah membuat bentuk botol air menggunakan Canvas API dan Path. Dengan menggunakan quadraticBezierTo() dan lineTo(), saya membuat bentuk botol yang terlihat alami. Berikut adalah bagian kode untuk menggambar botol:
val bodyPath = Path().apply {
moveTo(width * 0.3f, height * 0.1f)
lineTo(width * 0.3f, height * 0.2f)
quadraticBezierTo(
0f, height * 0.3f, // The pulling point
0f, height * 0.4f
)
lineTo(0f, height * 0.95f)
quadraticBezierTo(
0f, height,
width * 0.05f, height
)
lineTo(width * 0.95f, height)
quadraticBezierTo(
width, height,
width, height * 0.95f
)
lineTo(width, height * 0.4f)
quadraticBezierTo(
width, height * 0.3f,
width * 0.7f, height * 0.2f
)
lineTo(width * 0.7f, height * 0.2f)
lineTo(width * 0.7f, height * 0.1f)
close()
}
6. Animasi Level Air
Untuk membuat animasi level air, saya menggunakan animateFloatAsState() dan animateIntAsState() untuk membuat transisi yang halus pada perubahan nilai. Path digunakan untuk membuat bentuk "waves" yang mengisi botol berdasarkan persentase air yang diminum.
val waterPercentage = animateFloatAsState(
targetValue = (usedWaterAmount.toFloat() / totalWaterAmount.toFloat()),
label = "Water Waves animation",
animationSpec = tween(durationMillis = 1000)
).value
val waterWavesYPosition = (1 - waterPercentage) * size.height
val wavesPath = Path().apply {
moveTo(
x = 0f,
y = waterWavesYPosition
)
lineTo(
x = size.width,
y = waterWavesYPosition
)
lineTo(
x = size.width,
y = size.height
)
lineTo(
x = 0f,
y = size.height
)
close()
}
drawPath(
path = wavesPath,
color = waterWavesColor,
)
7. Validasi Input dan Interaktivitas
Untuk memastikan bahwa pengguna tidak dapat menambahkan air melebihi target harian, saya menambahkan validasi pada tombol "Drink":
Button(
onClick = {
if (usedWaterAmount + 200 <= totalWaterAmount) {
usedWaterAmount += 200
} else {
usedWaterAmount = totalWaterAmount
}
},
colors = ButtonDefaults.buttonColors(containerColor = Color(0xff279EFF))
) {
Text(text = "Drink")
}
Tombol "Reset" memungkinkan pengguna untuk mengatur ulang jumlah air yang diminum kembali ke 0, sehingga mereka dapat memulai pelacakan baru kapan saja.
8. Hasil Akhir
- Screenshot Hasil:
- Kode Lengkap (Github Code):
- Video Demo Compile/Run Application Water Bottle:
Comments
Post a Comment