Tugas 8 Water Bottle Animation

Nama: Dafarel Fatih Wirayudha
NRP: 5025211120
Kelas: PPB A


Pada tugas kali ini saya membuat aplikasi animasi botol air sederhana

Berikut adalah penjelasan kode dari aplikasi ini:

- MainActivity.kt

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 {
mutableStateOf(100)
}
val totalWaterAmount = remember {
2500
}
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {

WaterBottle(
totalWaterAmount = totalWaterAmount,
unit = "ml",
usedWaterAmount = usedWaterAmount
)
Spacer(modifier = Modifier.height(20.dp))
Text(
text = "Total Amount is : $totalWaterAmount",
textAlign = TextAlign.Center
)
Button(
onClick = { usedWaterAmount += 200 },
colors = ButtonDefaults.buttonColors(containerColor = Color(0xffff007f))
) {
Text(text = "Drink")
}
}
}
}
}
}
}

  • Menjalankan setContent {} saat aplikasi dibuka.
  • Menampilkan WaterBottleTheme dengan tampilan dari WaterBottle(...).
  • usedWaterAmount: air yang sudah diminum, berubah saat tombol ditekan.
  • totalWaterAmount: total kapasitas botol (2500 ml), nilai tetap.
  • Column berisi tampilan botol, teks total, dan tombol.
  • Ditambahkan verticalScroll agar tidak overflow di layar kecil.
  • Memanggil WaterBottle dengan parameter dari state.
  • Setiap klik tombol “Drink” akan menambah 200ml ke usedWaterAmount.
- WaterBottle.kt
fun WaterBottle(
modifier: Modifier = Modifier,
totalWaterAmount: Int,
unit: String,
usedWaterAmount: Int,
waterWavesColor: Color = Color(0xff279EFF),
bottleColor: Color = Color.White,
capColor: Color = Color(0xFF0065B9)
)
  • Fungsi Ini Menggambar:
    • Botol air
    • Tutup botol
    • Air di dalam botol
    • Teks jumlah air (dalam ml)
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
  • Membuat animasi halus saat air bertambah.
  • Nilai air dan tinggi air di dalam botol berubah secara smooth.
Canvas(modifier = Modifier.fillMaxSize()) {
val width = size.width
val height = size.height

val capWidth = size.width * 0.55f
val capHeight = size.height * 0.13f

val bodyPath = Path().apply {
moveTo(width * 0.3f, height * 0.1f)
lineTo(width * 0.3f, height * 0.2f)
quadraticBezierTo(
0f, height * 0.3f,
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()
}
clipPath(
path = bodyPath
) {
drawRect(
color = bottleColor,
size = size,
topLeft = Offset(0f, 0f)
)

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,
)
}
drawRoundRect(
color = capColor,
size = Size(capWidth, capHeight),
topLeft = Offset(size.width / 2 - capWidth / 2f, 0f),
cornerRadius = CornerRadius(45f, 45f)
)
}
val text = buildAnnotatedString {
withStyle(
style = SpanStyle(
color = if (waterPercentage > 0.5f) bottleColor else waterWavesColor,
fontSize = 44.sp
)
) {
append(usedWaterAmountAnimation.toString())
}
withStyle(
style = SpanStyle(
color = if (waterPercentage > 0.5f) bottleColor else waterWavesColor,
fontSize = 22.sp
)
) {
append(" ")
append(unit)
}
}
  • clipPath(bodyPath): membatasi gambar hanya di dalam bentuk botol.
  • drawRect: mewarnai botol.
  • drawPath: menggambar permukaan air.
  • drawRoundRect: menggambar tutup botol.
  • Teks menampilkan usedWaterAmount disertai unit (ml).
  • Warna teks berubah tergantung tinggi air (di atas atau di bawah 50%).
Hasil:

Video Demo:

Link Source Lengkap: GitHub




Comments

Popular posts from this blog

ETS

Tugas 7 Login Page

Tugas 6 Money Converter