📱 Membuat Aplikasi Woof dengan Desain Material 3 – Tugas Mobile Programming
✨ Pendahuluan
Pada tugas kali ini, saya Rakha Fathin Izzan Consetta (5025221156) membuat sebuah aplikasi sederhana bernama Woof, yang menampilkan daftar anjing menggunakan Jetpack Compose dan Material 3 Design. Aplikasi ini dibangun dengan prinsip UI modern, penggunaan tema terang dan gelap, serta mendukung desain responsif.
🎨 Penerapan Tema dan Warna di Aplikasi
1. File Shape.kt
File Shape.kt digunakan untuk mendefinisikan bentuk sudut (corner shape) dari komponen UI di aplikasi. Jetpack Compose menyediakan cara mudah untuk membuat bentuk elemen UI seperti tombol atau card. Berikut adalah isi dari file:
package com.example.woof.ui.theme
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp
val Shapes = Shapes(
small = RoundedCornerShape(50.dp),
medium = RoundedCornerShape(bottomStart = 16.dp, topEnd = 16.dp)
)
✅ Penjelasan Singkat:
-
RoundedCornerShape(50.dp)digunakan untuk komponen kecil, misalnya tombol bulat. -
RoundedCornerShape(bottomStart = 16.dp, topEnd = 16.dp)digunakan untuk komponen sedang dengan sudut berbeda, memberikan kesan unik pada UI.
2. File Theme.kt
File Theme.kt merupakan inti dari sistem tema di aplikasi. Di dalamnya terdapat definisi tema terang (light), tema gelap (dark), dan juga dukungan untuk dynamic color di Android 12+.
@Composable
fun WoofTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = false,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> darkScheme
else -> lightScheme
}
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
setUpEdgeToEdge(view, darkTheme)
}
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
shapes = Shapes,
content = content
)
}
/**
* Sets up edge-to-edge for the window of this [view]. The system icon colors are set to either
* light or dark depending on whether the [darkTheme] is enabled or not.
*/
private fun setUpEdgeToEdge(view: View, darkTheme: Boolean) {
val window = (view.context as Activity).window
WindowCompat.setDecorFitsSystemWindows(window, false)
window.statusBarColor = Color.Transparent.toArgb()
val navigationBarColor = when {
Build.VERSION.SDK_INT >= 29 -> Color.Transparent.toArgb()
Build.VERSION.SDK_INT >= 26 -> Color(0xFF, 0xFF, 0xFF, 0x63).toArgb()
// Min sdk version for this app is 24, this block is for SDK versions 24 and 25
else -> Color(0x00, 0x00, 0x00, 0x50).toArgb()
}
window.navigationBarColor = navigationBarColor
val controller = WindowCompat.getInsetsController(window, view)
controller.isAppearanceLightStatusBars = !darkTheme
controller.isAppearanceLightNavigationBars = !darkTheme
}
✅ Penjelasan Singkat:
-
Fungsi
WoofTheme()menentukan warna tema berdasarkan mode gelap/terang. -
dynamicColordigunakan untuk menyesuaikan warna berdasarkan wallpaper sistem (khusus Android 12+). -
Fungsi
setUpEdgeToEdge()mengatur tampilan edge-to-edge agar UI lebih immersive tanpa batasan status bar dan navigation bar.
3. File Type.kt
File Theme.kt mengatur gaya teks (font, ukuran, ketebalan) untuk tampilan aplikasi dengan font AbrilFatface dan Montserrat.
package com.example.woof.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.example.woof.R
val AbrilFatface = FontFamily(
Font(R.font.abril_fatface_regular)
)
val Montserrat = FontFamily(
Font(R.font.montserrat_regular),
Font(R.font.montserrat_bold, FontWeight.Bold)
)
val Typography = Typography(
displayLarge = TextStyle(
fontFamily = AbrilFatface,
fontWeight = FontWeight.Normal,
fontSize = 36.sp
),
displayMedium = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.Bold,
fontSize = 20.sp
),
labelSmall = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.Bold,
fontSize = 14.sp
),
bodyLarge = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.Normal,
fontSize = 14.sp
)
)
4. File Color.kt
Kumpulan warna tema terang dan gelap (light/dark) + variasi kontras (medium/high) untuk berbagai elemen UI seperti latar, teks, tombol, dll.
Berikut penjelasan singkat masing-masing file dalam res
🎨 color.xml
File ini menyimpan warna-warna utama aplikasi, seperti:
-
Ungu (
purple_200,purple_500,purple_700) -
Warna sekunder (
teal_200,teal_700) -
Hitam & Putih
Digunakan untuk konsistensi warna UI.
📏 dimens.xml
Berisi nilai ukuran seperti:
-
padding_smalldanpadding_medium: jarak antar elemen. -
image_size: ukuran gambar anjing.
Membantu menjaga layout yang rapi dan responsif.
🐶 strings.xml
Menyimpan semua teks yang tampil di UI, seperti:
-
Nama & deskripsi anjing
-
Nama aplikasi (
Woof) -
Teks tombol dan info tambahan
Memudahkan lokalisasi dan pengelolaan teks.
🎨 themes.xml
Menentukan tema dasar aplikasi, dalam hal ini:
<style name="Theme.Woof" parent="android:Theme.Material.Light.NoActionBar" />
Artinya pakai Material Design tanpa ActionBar.
🐶 Dog.kt – Data Class & Dummy Data
Kode:
package com.example.woof.data
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.example.woof.R
/**
* A data class to represent the information presented in the dog card
*/
data class Dog(
@DrawableRes val imageResourceId: Int,
@StringRes val name: Int,
val age: Int,
@StringRes val hobbies: Int
)
val dogs = listOf(
Dog(R.drawable.koda, R.string.dog_name_1, 2, R.string.dog_description_1),
Dog(R.drawable.lola, R.string.dog_name_2, 16, R.string.dog_description_2),
Dog(R.drawable.frankie, R.string.dog_name_3, 2, R.string.dog_description_3),
Dog(R.drawable.nox, R.string.dog_name_4, 8, R.string.dog_description_4),
Dog(R.drawable.faye, R.string.dog_name_5, 8, R.string.dog_description_5),
Dog(R.drawable.bella, R.string.dog_name_6, 14, R.string.dog_description_6),
Dog(R.drawable.moana, R.string.dog_name_7, 2, R.string.dog_description_7),
Dog(R.drawable.tzeitel, R.string.dog_name_8, 7, R.string.dog_description_8),
Dog(R.drawable.leroy, R.string.dog_name_9, 4, R.string.dog_description_9)
)
File ini berisi:
-
data class Dog: merepresentasikan data tiap anjing, seperti:-
Gambar (
imageResourceId) -
Nama (
name) -
Umur (
age) -
Hobi (
hobbies)
-
-
val dogs: daftar anjing (List) berisi data statis yang digunakan untuk ditampilkan di aplikasi.
📌 Tujuan: memisahkan data dari tampilan (UI) agar kode lebih terstruktur dan mudah digunakan.
📱 MainActivity.kt – Tampilan Utama Aplikasi
package com.example.woof
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.example.woof.data.Dog
import com.example.woof.data.dogs
import com.example.woof.ui.theme.WoofTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
WoofTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize()
) {
WoofApp()
}
}
}
}
}
/**
* Composable that displays an app bar and a list of dogs.
*/
@Composable
fun WoofApp() {
Scaffold(
topBar = {
WoofTopAppBar()
}
){ it->
LazyColumn (contentPadding = it){
items(dogs) {
DogItem(
dog = it,
modifier = Modifier.padding(dimensionResource(R.dimen.padding_small)))
}
}
}
}
/**
* Composable that displays a list item containing a dog icon and their information.
*
* @param dog contains the data that populates the list item
* @param modifier modifiers to set to this composable
*/
@Composable
fun DogItem(
dog: Dog,
modifier: Modifier = Modifier
) {
Card(modifier = modifier) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(dimensionResource(R.dimen.padding_small))
) {
DogIcon(dog.imageResourceId)
DogInformation(dog.name, dog.age)
}
}
}
/**
* Composable that displays a photo of a dog.
*
* @param dogIcon is the resource ID for the image of the dog
* @param modifier modifiers to set to this composable
*/
@Composable
fun DogIcon(
@DrawableRes dogIcon: Int,
modifier: Modifier = Modifier
) {
Image(
modifier = modifier
.size(dimensionResource(R.dimen.image_size))
.padding(dimensionResource(R.dimen.padding_small))
.clip(MaterialTheme.shapes.small),
contentScale = ContentScale.Crop,
painter = painterResource(dogIcon),
// Content Description is not needed here - image is decorative, and setting a null content
// description allows accessibility services to skip this element during navigation.
contentDescription = null
)
}
/**
* Composable that displays a dog's name and age.
*
* @param dogName is the resource ID for the string of the dog's name
* @param dogAge is the Int that represents the dog's age
* @param modifier modifiers to set to this composable
*/
@Composable
fun DogInformation(
@StringRes dogName: Int,
dogAge: Int,
modifier: Modifier = Modifier
) {
Column(modifier = modifier) {
Text(
text = stringResource(dogName),
style = MaterialTheme.typography.displayMedium,
modifier = Modifier.padding(top = dimensionResource(R.dimen.padding_small))
)
Text(
text = stringResource(R.string.years_old, dogAge),
style = MaterialTheme.typography.bodyLarge
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {
CenterAlignedTopAppBar(
title = {
Row(
verticalAlignment = Alignment.CenterVertically
){
Image(
modifier = Modifier
.size(dimensionResource(id = R.dimen.image_size))
.padding(dimensionResource(id = R.dimen.padding_small)),
painter = painterResource(R.drawable.ic_woof_logo),
contentDescription = null
)
Text(
text = stringResource(R.string.app_name),
style = MaterialTheme.typography.displayLarge
)
}
},
modifier = modifier
)
}
/**
* Composable that displays what the UI of the app looks like in light theme in the design tab.
*/
@Preview
@Composable
fun WoofPreview() {
WoofTheme(darkTheme = false) {
WoofApp()
}
}
@Preview
@Composable
fun WoofDarkThemePreview() {
WoofTheme(darkTheme = true) {
WoofApp()
}
}
File utama yang membentuk UI aplikasi Woof, menggunakan Jetpack Compose. Berikut bagian-bagian pentingnya:
✅ WoofApp()
-
Menampilkan daftar anjing dengan
LazyColumn. -
Memanggil
DogItem()untuk tiap item.
✅ DogItem()
-
Menampilkan satu kartu anjing berisi gambar dan informasi.
-
Menggunakan
Row()untuk tata letak horizontal.
✅ DogIcon() dan DogInformation()
-
DogIcon: menampilkan gambar anjing. -
DogInformation: menampilkan nama dan umur anjing dengan style Material.
✅ WoofTopAppBar()
-
Menampilkan app bar di atas dengan logo dan nama aplikasi.
-
Menggunakan
CenterAlignedTopAppBar.
✅ Preview
-
WoofPreview()danWoofDarkThemePreview()digunakan untuk melihat UI dalam mode terang dan gelap.
📌 Kesimpulan:
Proyek ini adalah contoh implementasi Jetpack Compose yang menampilkan daftar data dalam UI modern dan responsif, cocok untuk pemula memahami struktur data dan UI di Android.
Hasil
