Tugas 9 - Pemrograman Perangkat Bergerak
Hesekiel Nainggolan
5025201054
PPB I
Material Design - Aplikasi Woof
Pada pertemuan kita kali ini akan membuat Woof, yaitu aplikasi yang menampilkan daftar anjing dan menggunakan Desain Material untuk membuat pengalaman aplikasi yang menarik. Sama seperti pertemuan sebelumnya, pada kesempatan ini kita akan membuat aplikasi woof dalam bentuk image scroling. Adapun aplikasi woofnya dapat kita dowload melalui Github ini.
1. Membuat New Project
Sama seperti pertemuan-pertemuan sebelumnya, tahapan awal dalam membuat aplikasi yaitu membuat sebuah project baru. untuk kesempatan ini kita akan membuat aplikasi woof, kita bebas untuk membuat penamaan aplikasinya
2. Menambahan Skema Warna
Skema warna adalah kombinasi warna yang digunakan aplikasi Anda. Kombinasi warna yang berbeda membangkitkan suasana hati yang berbeda, yang memengaruhi perasaan orang saat menggunakan aplikasi Anda.
Warna, dalam sistem Android, diwakili oleh nilai warna heksadesimal (hex). Kode warna heksadesimal dimulai dengan tanda pagar (#), dan diikuti dengan enam huruf dan/atau angka yang mewakili komponen merah, hijau, dan biru (RGB) dari warna tersebut. Dua huruf/angka pertama merujuk ke warna merah, dua huruf berikutnya berwarna hijau, dan dua huruf terakhir mengacu pada warna biru
Di halaman Material Theme Builder, ada opsi untuk mengklik tombol Export guna mendownload file Color.kt dan file Theme.kt dengan tema kustom yang Anda buat di Theme Builder.
Tombol ini akan bekerja untuk menambahkan tema kustom yang telah kita buat ke aplikasi. Namun, karena file Theme.kt yang dihasilkan tidak menyertakan kode untuk warna dinamis yang akan kita bahas nanti di codelab, salin file tersebut.
Dikode kita, WoofTheme(), colorScheme val menggunakan pernyataan when
- Jika dynamicColor bernilai benar dan versi build adalah S atau yang lebih tinggi, perangkat akan diperiksa apakah menggunakan darkTheme atau tidak.
- Jika temanya gelap, colorScheme akan disetel ke dynamicDarkColorScheme.
- Jika tidak dalam tema gelap, warna akan disetel ke dynamicLightColorScheme.
- Jika aplikasi tidak menggunakan dynamicColorScheme, aplikasi akan diperiksa apakah menggunakan darkTheme. Jika demikian, colorScheme akan ditetapkan ke DarkColors.
- Jika tidak ada yang benar, colorScheme akan ditetapkan ke LightColors.
Color.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.woof.ui.theme | |
import androidx.compose.ui.graphics.Color | |
val md_theme_light_primary = Color(0xFF006C4C) | |
val md_theme_light_onPrimary = Color(0xFFFFFFFF) | |
val md_theme_light_primaryContainer = Color(0xFF89F8C7) | |
val md_theme_light_onPrimaryContainer = Color(0xFF002114) | |
val md_theme_light_secondary = Color(0xFF4D6357) | |
val md_theme_light_onSecondary = Color(0xFFFFFFFF) | |
val md_theme_light_secondaryContainer = Color(0xFFCFE9D9) | |
val md_theme_light_onSecondaryContainer = Color(0xFF092016) | |
val md_theme_light_tertiary = Color(0xFF3D6373) | |
val md_theme_light_onTertiary = Color(0xFFFFFFFF) | |
val md_theme_light_tertiaryContainer = Color(0xFFC1E8FB) | |
val md_theme_light_onTertiaryContainer = Color(0xFF001F29) | |
val md_theme_light_error = Color(0xFFBA1A1A) | |
val md_theme_light_errorContainer = Color(0xFFFFDAD6) | |
val md_theme_light_onError = Color(0xFFFFFFFF) | |
val md_theme_light_onErrorContainer = Color(0xFF410002) | |
val md_theme_light_background = Color(0xFFFBFDF9) | |
val md_theme_light_onBackground = Color(0xFF191C1A) | |
val md_theme_light_surface = Color(0xFFFBFDF9) | |
val md_theme_light_onSurface = Color(0xFF191C1A) | |
val md_theme_light_surfaceVariant = Color(0xFFDBE5DD) | |
val md_theme_light_onSurfaceVariant = Color(0xFF404943) | |
val md_theme_light_outline = Color(0xFF707973) | |
val md_theme_light_inverseOnSurface = Color(0xFFEFF1ED) | |
val md_theme_light_inverseSurface = Color(0xFF2E312F) | |
val md_theme_light_inversePrimary = Color(0xFF6CDBAC) | |
val md_theme_light_shadow = Color(0xFF000000) | |
val md_theme_light_surfaceTint = Color(0xFF006C4C) | |
val md_theme_light_outlineVariant = Color(0xFFBFC9C2) | |
val md_theme_light_scrim = Color(0xFF000000) | |
val md_theme_dark_primary = Color(0xFF6CDBAC) | |
val md_theme_dark_onPrimary = Color(0xFF003826) | |
val md_theme_dark_primaryContainer = Color(0xFF005138) | |
val md_theme_dark_onPrimaryContainer = Color(0xFF89F8C7) | |
val md_theme_dark_secondary = Color(0xFFB3CCBE) | |
val md_theme_dark_onSecondary = Color(0xFF1F352A) | |
val md_theme_dark_secondaryContainer = Color(0xFF354B40) | |
val md_theme_dark_onSecondaryContainer = Color(0xFFCFE9D9) | |
val md_theme_dark_tertiary = Color(0xFFA5CCDF) | |
val md_theme_dark_onTertiary = Color(0xFF073543) | |
val md_theme_dark_tertiaryContainer = Color(0xFF244C5B) | |
val md_theme_dark_onTertiaryContainer = Color(0xFFC1E8FB) | |
val md_theme_dark_error = Color(0xFFFFB4AB) | |
val md_theme_dark_errorContainer = Color(0xFF93000A) | |
val md_theme_dark_onError = Color(0xFF690005) | |
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6) | |
val md_theme_dark_background = Color(0xFF191C1A) | |
val md_theme_dark_onBackground = Color(0xFFE1E3DF) | |
val md_theme_dark_surface = Color(0xFF191C1A) | |
val md_theme_dark_onSurface = Color(0xFFE1E3DF) | |
val md_theme_dark_surfaceVariant = Color(0xFF404943) | |
val md_theme_dark_onSurfaceVariant = Color(0xFFBFC9C2) | |
val md_theme_dark_outline = Color(0xFF8A938C) | |
val md_theme_dark_inverseOnSurface = Color(0xFF191C1A) | |
val md_theme_dark_inverseSurface = Color(0xFFE1E3DF) | |
val md_theme_dark_inversePrimary = Color(0xFF006C4C) | |
val md_theme_dark_shadow = Color(0xFF000000) | |
val md_theme_dark_surfaceTint = Color(0xFF6CDBAC) | |
val md_theme_dark_outlineVariant = Color(0xFF404943) | |
val md_theme_dark_scrim = Color(0xFF000000) |
Theme.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.woof.ui.theme | |
import android.app.Activity | |
import android.os.Build | |
import android.view.View | |
import androidx.compose.foundation.isSystemInDarkTheme | |
import androidx.compose.material3.MaterialTheme | |
import androidx.compose.material3.darkColorScheme | |
import androidx.compose.material3.dynamicDarkColorScheme | |
import androidx.compose.material3.dynamicLightColorScheme | |
import androidx.compose.material3.lightColorScheme | |
import androidx.compose.runtime.Composable | |
import androidx.compose.runtime.SideEffect | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.graphics.toArgb | |
import androidx.compose.ui.platform.LocalContext | |
import androidx.compose.ui.platform.LocalView | |
import androidx.core.view.WindowCompat | |
private val LightColors = lightColorScheme( | |
primary = md_theme_light_primary, | |
onPrimary = md_theme_light_onPrimary, | |
primaryContainer = md_theme_light_primaryContainer, | |
onPrimaryContainer = md_theme_light_onPrimaryContainer, | |
secondary = md_theme_light_secondary, | |
onSecondary = md_theme_light_onSecondary, | |
secondaryContainer = md_theme_light_secondaryContainer, | |
onSecondaryContainer = md_theme_light_onSecondaryContainer, | |
tertiary = md_theme_light_tertiary, | |
onTertiary = md_theme_light_onTertiary, | |
tertiaryContainer = md_theme_light_tertiaryContainer, | |
onTertiaryContainer = md_theme_light_onTertiaryContainer, | |
error = md_theme_light_error, | |
errorContainer = md_theme_light_errorContainer, | |
onError = md_theme_light_onError, | |
onErrorContainer = md_theme_light_onErrorContainer, | |
background = md_theme_light_background, | |
onBackground = md_theme_light_onBackground, | |
surface = md_theme_light_surface, | |
onSurface = md_theme_light_onSurface, | |
surfaceVariant = md_theme_light_surfaceVariant, | |
onSurfaceVariant = md_theme_light_onSurfaceVariant, | |
outline = md_theme_light_outline, | |
inverseOnSurface = md_theme_light_inverseOnSurface, | |
inverseSurface = md_theme_light_inverseSurface, | |
inversePrimary = md_theme_light_inversePrimary, | |
surfaceTint = md_theme_light_surfaceTint, | |
outlineVariant = md_theme_light_outlineVariant, | |
scrim = md_theme_light_scrim, | |
) | |
private val DarkColors = darkColorScheme( | |
primary = md_theme_dark_primary, | |
onPrimary = md_theme_dark_onPrimary, | |
primaryContainer = md_theme_dark_primaryContainer, | |
onPrimaryContainer = md_theme_dark_onPrimaryContainer, | |
secondary = md_theme_dark_secondary, | |
onSecondary = md_theme_dark_onSecondary, | |
secondaryContainer = md_theme_dark_secondaryContainer, | |
onSecondaryContainer = md_theme_dark_onSecondaryContainer, | |
tertiary = md_theme_dark_tertiary, | |
onTertiary = md_theme_dark_onTertiary, | |
tertiaryContainer = md_theme_dark_tertiaryContainer, | |
onTertiaryContainer = md_theme_dark_onTertiaryContainer, | |
error = md_theme_dark_error, | |
errorContainer = md_theme_dark_errorContainer, | |
onError = md_theme_dark_onError, | |
onErrorContainer = md_theme_dark_onErrorContainer, | |
background = md_theme_dark_background, | |
onBackground = md_theme_dark_onBackground, | |
surface = md_theme_dark_surface, | |
onSurface = md_theme_dark_onSurface, | |
surfaceVariant = md_theme_dark_surfaceVariant, | |
onSurfaceVariant = md_theme_dark_onSurfaceVariant, | |
outline = md_theme_dark_outline, | |
inverseOnSurface = md_theme_dark_inverseOnSurface, | |
inverseSurface = md_theme_dark_inverseSurface, | |
inversePrimary = md_theme_dark_inversePrimary, | |
surfaceTint = md_theme_dark_surfaceTint, | |
outlineVariant = md_theme_dark_outlineVariant, | |
scrim = md_theme_dark_scrim, | |
) | |
@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 -> DarkColors | |
else -> LightColors | |
} | |
val view = LocalView.current | |
if (!view.isInEditMode) { | |
SideEffect { | |
setUpEdgeToEdge(view, darkTheme) | |
} | |
} | |
MaterialTheme( | |
colorScheme = colorScheme, | |
shapes = Shapes, | |
typography = Typography, | |
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 | |
} |
3. Menambahkan Bentuk
Menerapkan bentuk akan sangat memengaruhi tampilan dan nuansa composable. Bentuk mampu menarik perhatian, mengidentifikasi komponen, mengomunikasikan status, dan mengekspresikan merek.
Banyak bentuk ditentukan menggunakan RoundedCornerShape, yang menggambarkan persegi panjang dengan sudut membulat. Angka yang diteruskan menentukan kebulatan sudut. Jika RoundedCornerShape(0.dp) digunakan, persegi panjang tidak memiliki sudut membulat; jika RoundedCornerShape(50.dp) digunakan, sudut akan membulat sepenuhnya.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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 | |
) | |
} |
4. Menambahkan Tipografi
Jenis huruf adalah pilihan gaya font yang dapat digunakan di seluruh aplikasi dan memastikan gaya yang fleksibel namun konsisten. Jenis huruf Desain Material mencakup lima belas gaya font yang didukung oleh sistem jenis. Penamaan dan pengelompokannya telah disederhanakan untuk: tampilan, judul utama, judul, isi, dan label, dengan ukuran besar, sedang, dan kecil untuk masing-masing. Anda hanya perlu menggunakan pilihan ini jika ingin menyesuaikan aplikasi. Jika Anda tidak tahu apa yang harus ditetapkan untuk setiap kategori jenis huruf, ada skala tipografi default yang dapat Anda gunakan. Kemudian kita akan melakukan inisialisasi font:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.compose.ui.text.TextStyle | |
import androidx.compose.ui.unit.sp | |
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 | |
) | |
) |
Kemudian kita akan menambahkan jenis judul utama ke setiap instance teks di aplikasi. Kita menambahkan displayMedium sebagai gaya untuk dogName karena merupakan informasi singkat yang penting. Tambahkan bodyLarge sebagai gaya untuk dogAge karena berfungsi cukup baik dengan ukuran teks yang lebih kecil:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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(id = R.dimen.padding_small)) | |
) | |
Text( | |
text = stringResource(R.string.years_old, dogAge), | |
style = MaterialTheme.typography.bodyLarge | |
) | |
} | |
} |
5. Menambahkan Panel Atas
Scaffold adalah tata letak yang menyediakan slot untuk berbagai komponen dan elemen layar, seperti Image, Row, atau Column. Scaffold juga menyediakan slot untuk TopAppBar, yang akan Anda gunakan di bagian ini.
TopAppBar dapat digunakan untuk berbagai tujuan, tetapi dalam hal ini, Anda akan menggunakannya untuk branding dan memberikan karakteristik pada aplikasi. Ada empat jenis TopAppBar: tengah, kecil, sedang, dan besar. Dalam code ini kita akan menerapkan panel aplikasi atas di tengah. Kita akan membuat composable yang terlihat seperti screenshot di bawah, dan memasukkannya ke bagian topBar dari Scaffold.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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 | |
) | |
} |
Komentar
Posting Komentar