Langsung ke konten utama

Botol Minum Ucul

Membuat Animasi Botol Lucu

    Pada blog ini kita akan membuat aplikasi animasi botol yang lucu. Aplikasi ini dibuat dengan jetpack compose. Aplikasi ini dibuat mengikuti referensi Youtube dengan melakukan beberapa modifikasi pada kode dan fitur yang ada. Yuk langsung kita mulai saja!

Membuat Projek Baru

    Buat projek baru dengan jenis Empty Activity, lalu beri nama yang sesuai, saya memberi nama MyWaterBottle. Untuk minimum SDK yang saya gunakan adalah API 26 Oreo Android 8.0. Setelah terbuat, tambahkan file kt pada folder com.example.mywaterbottle dan pilih tipe File dan beri nama WaterBottle.

Sumber Kode MainActivity.kt

variabel
var totalWaterAmount = remember {
2400
}
var usedAmount by remember {
mutableStateOf(value = 400)
}
var incrementWaterAmount = 200
var unitValue = "ml"
view raw MainActivity.kt hosted with ❤ by GitHub

Pada bagian ini kita mendefinisikan beberapa variabel yang diperlukan, totalWaterAmount menyimpan total ukuran maksimal botol, usedAmount merupakan isi air pada kondisi awal, incrementWaterAmount merupakan nilai increment untuk sekali minum, dan unitValue merupakan satuan yang digunakan pada botol (saya menggunakan ml)

Struktur
Column (...)
{
...
Row {
Button() // minum
{ Text }
Spacer()
Button() // reset botol
{ Text }
}
...
}
view raw MainActivity.kt hosted with ❤ by GitHub

Struktur tampilan yang disusun berupa colom yang terdiri dari tampilan botol, keterangan ukuran botol, dan tombol dengan fungsi minum dan reset botol

Keterangan
WaterBottle(totalWaterAmount = totalWaterAmount, unit = unitValue, usedWaterAmount = usedAmount, modifier = Modifier.width(300.dp))
Spacer(modifier = Modifier.height(20.dp))
Text(text = "Total Amount Is: $totalWaterAmount $unitValue")
view raw MainActivity.kt hosted with ❤ by GitHub

Baris kode 1 merupakan pemanggilan fungsi WaterBottle yang akan kita definisikan pada WaterBottle.kt. Adapun, baris kode 3 digunakan untuk menunjukkan status ukuran botol dengan memanggil nilai dari variabel totalWaterAmount dan unitValue

Tombol
Button(onClick = {
if (usedAmount < totalWaterAmount) {
usedAmount += incrementWaterAmount
}
}, colors = ButtonDefaults.buttonColors(containerColor = Color(0xfff27bbd))
) {
Text(text = "Drink")
}
Spacer(modifier = Modifier.width(20.dp))
Button(onClick = { usedAmount = 0 },
colors = ButtonDefaults.buttonColors(containerColor = Color(0xfff27bbd))
)
{
Text(text = "Reset")
}
view raw MainActivity.kt hosted with ❤ by GitHub

Terdapat 2 tombol yang kita buat, yakni untuk minum dan reset. tombol minum menambahkan nilai air yang diminum dengan nilai increment yang sudah ditentukan, sedangkan tombol reset merubah nilai air menjadi 0. Fitur ini diimplementasikan dengan mengatur tindakan onClick merubah nilai usedAmount, tetapi sebelum melakukan penambahan, akan dilakukan pengecekan terlebih dahulu apakah nilai usedAmount sudah melebihi nilai maksimal botol. Selain itu, dilakukan modifikasi warna tombol dengan warna pink hehe, agar lebih sesuai dengan warna botolnya.

Kode Lengkap
package com.example.mywaterbottle
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
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.height
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
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.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.mywaterbottle.ui.theme.MyWaterBottleTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyWaterBottleTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
var totalWaterAmount = remember {
2400
}
var usedAmount by remember {
mutableStateOf(value = 400)
}
var incrementWaterAmount = 200
var unitValue = "ml"
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
WaterBottle(totalWaterAmount = totalWaterAmount, unit = unitValue, usedWaterAmount = usedAmount, modifier = Modifier.width(300.dp))
Spacer(modifier = Modifier.height(20.dp))
Text(text = "Total Amount Is: $totalWaterAmount $unitValue")
Row {
Button(onClick = {
if (usedAmount < totalWaterAmount) {
usedAmount += incrementWaterAmount
}
}, colors = ButtonDefaults.buttonColors(containerColor = Color(0xfff27bbd))
) {
Text(text = "Drink")
}
Spacer(modifier = Modifier.width(20.dp))
Button(onClick = { usedAmount = 0 },
colors = ButtonDefaults.buttonColors(containerColor = Color(0xfff27bbd))
)
{
Text(text = "Reset")
}
}
}
}
}
}
}
}
view raw MainActivity.kt hosted with ❤ by GitHub

Sumber Kode WaterBottle.kt

Definisi Atribut
modifier: Modifier = Modifier,
totalWaterAmount: Int,
unit: String,
usedWaterAmount: Int,
waterColor: Color = Color(color = 0xffC65BCF),
bottleColor: Color = Color.White,
capColor: Color = Color(0xfff27bbd)
view raw WaterBottle.kt hosted with ❤ by GitHub

Pada bagian in]i kita mendefinisikan beberapa atribut yang diperlukan, yakni modifier, total ukuran botol, satuan, jumlah isi air, warna botol, air, dan penutup botol. Dalam menentukan nilai warna dapat ditentukan dengan String seperti White atau dengan nilai hexadesimal, yakni diawali dengan 0xff yang mendefinisikan nilai alpha dan dilanjutkan 6 digit hexadesimal warna. Anda dapat menentukan warna yang cocok dengan melihat color.hunt.

Definisi Variable
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
view raw WaterBottle.kt hosted with ❤ by GitHub

2 variabel utama yang diperlukan adalah waterPercentage, yakni persentase isi air terhadap total ukuran botol. definisi ini menggunakan animateFloatAsState dengan animasi tween durasi 1 detik. Sama dengan sebelumnya, kita definisikan variabel usedWaterAmountAnimation, tetapi menggunakan animateIntAsState agar nilainya menjadi bilangan bulat.

Membentuk Path Botol
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 bottleBodyPath = Path().apply {
moveTo(
x = width * 0.3f, y = height * 0.1f
)
lineTo(
x = width * 0.3f, y = height * 0.2f
)
quadraticBezierTo(
x1 = 0f, y1 = height * 0.3f,
x2 = 0f, y2 = height * 0.4f
)
lineTo(
x = 0f, y = height * 0.95f
)
quadraticBezierTo(
x1 = 0f, y1 = height,
x2 = width * 0.05f, y2 = height
)
lineTo(
x = width * 0.95f, y = height
)
quadraticBezierTo(
x1 = width, y1 = height,
x2 = width, y2 = height * 0.95f
)
lineTo(
x = width, y = height * 0.4f
)
quadraticBezierTo(
x1 = width, y1 = height * 0.3f,
x2 = width * 0.7f, y2 = height * 0.2f
)
lineTo(
x = width * 0.7f, y = height * 0.1f
)
close()
}
clipPath(
bottleBodyPath
){
drawRect(
color = bottleColor,
size = size,
)
...
}
...
}
view raw WaterBottle.kt hosted with ❤ by GitHub

Botol dibuat dengan membentuk path dari botol sendiri. diawali dengan moveTo untuk menentukan titik awal, lineTo untuk membentuk garis lurus, quadraticBezierTo untuk membentuk garis lengkung dengan parameter titik tumpu dan titik akhir, dan close untuk menutup path yang sudah dibentuk. Pembentukan path dapat dilihat pada gambar berikut:



Membentuk Animasi Terisi Air
val waterWavesYPosition = (1 - waterPercentage) * size.height
val waterPath = 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 = waterPath,
color = waterColor
)
view raw WaterBottle.kt hosted with ❤ by GitHub

Animasi pengisian air diimplementasi dengan membentuk path air dengan menghitung tinggi air dengan perhitungan yang sesuai berdasar persentase banyak air pada botol. Lalu disesuaika dengan warna air dan menggambar path air.

Membentuk Tutup Botol
drawRoundRect(
color = capColor,
size = Size(capWidth, capHeight),
topLeft = Offset(size.width / 2 - capWidth / 2f, 0f),
cornerRadius = CornerRadius(45f, 45f)
)
view raw WaterBottle.kt hosted with ❤ by GitHub

Tutup botol dibuat menggunakan drawRoundRect sehingga bentuk tutup menjadi rounded.

Menuliskan Ukuran Air Sekarang
val text = buildAnnotatedString {
withStyle(
style = SpanStyle(
color = if (waterPercentage > 0.5f) bottleColor else waterColor,
fontSize = 66.sp
)
){
append(usedWaterAmountAnimation.toString())
}
withStyle(
style = SpanStyle(
color = if (waterPercentage > 0.5f) bottleColor else waterColor,
fontSize = 22.sp
)
){
append(" ")
append(unit)
}
}
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center){
Text(text = text)
}
view raw WaterBottle.kt hosted with ❤ by GitHub

Penulisan ukuran air sekarang dapat disesuaikan dengan isi air, apabila air melebehi tinggi dari posisi air, maka warna tulisan akan diubah menjadi warna putih. sehingga, tampilannya menjadi lebih menarik.

Full Kode
package com.example.mywaterbottle
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun WaterBottle(
modifier: Modifier = Modifier,
totalWaterAmount: Int,
unit: String,
usedWaterAmount: Int,
waterColor: Color = Color(color = 0xffC65BCF),
bottleColor: Color = Color.White,
capColor: Color = Color(0xfff27bbd)
) {
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
.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
val bottleBodyPath = Path().apply {
moveTo(
x = width * 0.3f, y = height * 0.1f
)
lineTo(
x = width * 0.3f, y = height * 0.2f
)
quadraticBezierTo(
x1 = 0f, y1 = height * 0.3f,
x2 = 0f, y2 = height * 0.4f
)
lineTo(
x = 0f, y = height * 0.95f
)
quadraticBezierTo(
x1 = 0f, y1 = height,
x2 = width * 0.05f, y2 = height
)
lineTo(
x = width * 0.95f, y = height
)
quadraticBezierTo(
x1 = width, y1 = height,
x2 = width, y2 = height * 0.95f
)
lineTo(
x = width, y = height * 0.4f
)
quadraticBezierTo(
x1 = width, y1 = height * 0.3f,
x2 = width * 0.7f, y2 = height * 0.2f
)
lineTo(
x = width * 0.7f, y = height * 0.1f
)
close()
}
clipPath(
bottleBodyPath
){
drawRect(
color = bottleColor,
size = size,
)
val waterWavesYPosition = (1 - waterPercentage) * size.height
val waterPath = 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 = waterPath,
color = waterColor
)
}
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 waterColor,
fontSize = 66.sp
)
){
append(usedWaterAmountAnimation.toString())
}
withStyle(
style = SpanStyle(
color = if (waterPercentage > 0.5f) bottleColor else waterColor,
fontSize = 22.sp
)
){
append(" ")
append(unit)
}
}
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center){
Text(text = text)
}
}
}
view raw WaterBottle.kt hosted with ❤ by GitHub

Hasil






Komentar

Postingan populer dari blog ini

Kalkulator Sederhana

Kalkulator Sederhana Membuat Projek Projek dibuat dengan memilih New Project dan menggunakan Empty Activities, beri nama projek sesuai selera, saya sendiri menggunakan nama MyCalculator dengan minimum SDK API 26 Oreo. Setelah itu klik Finish.  Menyusun Sumber Kode Aplikasi ini sangat sederhana, hanya cukup mengikuti beberapa langkah berikut: Buat variable num1 dan num2 untuk menyimpan nilai input dari user, jangan lupa untuk menambahkan import runtime.* Membuat TextField untuk menerima input dari user dengan mensingkronisasi variabel num1 dan num2 Membentuk operasi perhitungan dengan button dimana pada button menggunakan aktivitas perhitungan apabila diklik. input yang berupa string akan diubah menjadi integer dan dilakukan perhitungan yang sesuai. Hasil perhitungan akan ditampilkan sebagai pop up, hal ini dilakukan dengan Toast.  Hasil Akhir Referensi:  Referensi YT Sumber kode lengkap sebagai berikut:

Image Scroll

 Membuat Komponen Image Scroll Kita akan membuat aplikasi dengan tampilan komponen image scroll seperti card dengan isi gambar. Yuk kita mulai dengan mengikuti tutorial  referensi  ini. Load projek starter pada github ini download file pada branch starter dalam bentuk ZIP. Setelah terdownload, ekstrak. Pada android studio kita akan membuka projek dengan open dan mengarahkan ke folder hasil ekstraksi tadi. Dalam membuka projek memang memakan waktu yang cukup lama, jadi harap sabar. Ketika selesai load, maka coba run program, maka akan memiliki tampilan sebagai berikut: Membuat class data item daftar 1. Membuat class data untuk affirmation klik kanan pada folder com.example.affirmation pilin new, lalu package dan beri nama model. package ini akan berisi class data. 2. Membuat class affirmation klik kanan pada package model lalu pilih new, lalu Kotlin class/File, lalu pilih Data Class. Beri nama Affirmation. Ubah sumber kode menjadi seperti berikut: 3. Aktifkan sumber ko...

Aplikasi Woof

 Membuat Aplikasi Woof Pada kesempatan kali ini kita akan mencoba untuk membuat aplikasi woof, yakni aplikasi yang dapat menampilkan daftar anjing berisi gambar dan informasi lainnya. Ilustrasi dari hasil aplikasi yang akan dibuat seperti berikut. Yuk kita mulai mengikuti tutorial -nya. Memulai dengan starter project Pada halaman tutorial kita diberikan starter project dimana berisi resource-resource yang diperlukan, seperti gambar dan data informasi. Anda dapat mendownload pada github ini pada branch starter. dan kita akan mulai memodifikasi starter projek. Menambahkan warna Dalam menyusun warna yang baik, kita dapat menggunakan bantuan website ini. Pada starter projek kita sudah tersedia file Color.kt pada folder ui.theme. Ubah sumber kode menjadi berikut:   Perlu diingat, penamaan warna dimulai dengan nilai alpha, dimana 00 mengartikan opasitas minimum, yakni transparan total, sedangkan ff opasitas maksimum, yakni solid penuh. Pada file Color.kt ini lah kita menentukan war...