Pertemuan 2 - Jetpack Compose

Naufal Khairul Rizky - 5025221127


1. Getting started with Compose

Jetpack Compose menyederhanakan pengembangan UI dengan menggunakan fungsi @Composable sebagai pengganti XML. Fungsi Greeting menunjukkan bagaimana elemen UI seperti teks dapat dibuat secara dinamis.



2. Tweaking the UI

Jetpack Compose memungkinkan penyesuaian elemen UI dengan mudah menggunakan Surface dan MaterialTheme. Dengan membungkus komponen Text dalam Surface dan mengatur warnanya ke MaterialTheme.colorScheme.primary, warna latar belakang akan diperbarui secara otomatis. 

Selain itu, Modifier dapat digunakan untuk mengontrol tata letak. Menerapkan Modifier.padding(24.dp) akan menambahkan jarak di sekitar teks. Perubahan dapat langsung dipratinjau di Android Studio menggunakan anotasi @Preview.



3. Reusing Composables

Bagian ini berfokus pada penggunaan kembali fungsi composable untuk meningkatkan keterbacaan dan pemeliharaan kode. Dengan membagi UI menjadi komponen kecil yang dapat digunakan kembali, setiap bagian layar dapat lebih mudah diperbarui dan dipelihara.


4. Creating Columns and Rows

Untuk mengubah fungsi Greeting agar menampilkan teks dalam format kolom, tambahkan dua elemen teks di dalamnya. Pastikan untuk menyesuaikan posisi padding agar tata letaknya tetap terlihat rapi.


Fungsi Composable dapat digunakan seperti fungsi lainnya di Kotlin, memberikan fleksibilitas dalam membangun UI. Dengan Compose, elemen UI dapat dibuat secara dinamis menggunakan struktur pemrograman seperti for loop.

Selanjutnya, elemen interaktif akan ditambahkan untuk memperluas tampilan Greeting. Untuk itu, sebuah tombol perlu dibuat terlebih dahulu agar pengguna dapat berinteraksi dengan UI. Button adalah salah satu composable dari paket Material3 yang menerima composable lain sebagai argumen terakhir. Dengan fitur trailing lambda, konten dalam tombol dapat didefinisikan dengan lebih rapi di luar tanda kurung.




5. State in Compose

Di bagian ini, UI yang sebelumnya statis akan dibuat lebih interaktif dengan merespons perubahan dari pengguna. Sebelum tombol dapat mengubah ukuran elemen, diperlukan cara menyimpan status tiap item, apakah dalam kondisi diperluas atau tidak. Penyimpanan status ini dilakukan langsung di dalam composable tersebut  menggunakan mutableStateOf, yang memungkinkan Compose mendeteksi perubahan dan memperbarui UI. 




6. State Hoisting

State hoisting dalam Compose berarti memindahkan state ke komponen yang lebih tinggi agar bisa digunakan oleh beberapa composable. Ini menghindari duplikasi state, meningkatkan reusability, dan mempermudah pengujian. 






7. Creating a Performant Lazy List

Jika ingin menampilkan daftar dalam jumlah besar tanpa mengorbankan performa, gunakan LazyColumn sebagai pengganti Column. LazyColumn hanya merender item yang sedang terlihat di layar, sehingga lebih efisien dibandingkan langsung menampilkan seluruh daftar sekaligus.



8. Styling and Theming




Source code:

package com.example.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.myapplication.ui.theme.MyApplicationTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.ElevatedButton
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.material3.Button
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.spring
import androidx.compose.material3.Switch
import androidx.compose.runtime.saveable.rememberSaveable


class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
MyApplicationTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}

@Composable
fun MyApp(modifier: Modifier = Modifier) {
var isDarkTheme by rememberSaveable { mutableStateOf(false) }
var shouldShowOnboarding by rememberSaveable { mutableStateOf(true) }

MyApplicationTheme(darkTheme = isDarkTheme) {
Surface(modifier) {
Column {
Switch(
checked = isDarkTheme,
onCheckedChange = { isDarkTheme = it }
)

if (shouldShowOnboarding) {
OnboardingScreen(onContinueClicked = { shouldShowOnboarding = false })
} else {
Greetings(onBackClicked = { shouldShowOnboarding = true })
}
}
}
}
}



@Composable
fun OnboardingScreen(
onContinueClicked: () -> Unit,
modifier: Modifier = Modifier
) {


Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Welcome to the Basics Codelab!")
Button(
modifier = Modifier.padding(vertical = 24.dp),
onClick = onContinueClicked
) {
Text("Continue")
}
}

}

@Composable
private fun Greetings(
onBackClicked: () -> Unit,
modifier: Modifier = Modifier,
names: List<String> = List(1000) { "$it" }
) {
Column {
Button(
onClick = onBackClicked,
modifier = Modifier.padding(8.dp)
) {
Text("Back")
}

LazyColumn(modifier = modifier.padding(vertical = 4.dp)) {
items(items = names) { name ->
Greeting(name = name)
}
}
}
}


//@Preview(showBackground = true, widthDp = 320, heightDp = 320)
//@Composable
//fun OnboardingPreview() {
// MyApplicationTheme {
// OnboardingScreen(onContinueClicked = {})
// }
//}

@Composable
private fun Greeting(name: String, modifier: Modifier = Modifier) {

var expanded by rememberSaveable { mutableStateOf(false) }

val extraPadding by animateDpAsState(
if (expanded) 48.dp else 0.dp,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
)
)
Surface(
color = MaterialTheme.colorScheme.primary,
modifier = modifier.padding(vertical = 4.dp, horizontal = 8.dp)
) {
Row(modifier = Modifier.padding(24.dp)) {
Column(modifier = Modifier
.weight(1f)
.padding(bottom = extraPadding.coerceAtLeast(0.dp))
) {
Text(text = "Hello, ")
Text(text = name)
}
ElevatedButton(
onClick = { expanded = !expanded }
) {
Text(if (expanded) "Show less" else "Show more")
}
}
}
}

//@Preview(showBackground = true)
//@Composable
//fun GreetingPreview_5025221127() {
// MyApplicationTheme {
// MyApp()
// }
//}

//@Preview(showBackground = true, widthDp = 320, heightDp = 320)
//@Composable
//fun OnboardingPreview() {
// MyApplicationTheme {
// OnboardingScreen()
// }
//}

//@Preview(showBackground = true, widthDp = 320)
//@Composable
//fun GreetingPreview_5025221127() {
// MyApplicationTheme {
// Greetings()
// }
//}

@Preview
@Composable
fun MyAppPreview_5025221127() {
MyApplicationTheme {
MyApp(Modifier.fillMaxSize())
}
}

Komentar