뷰를 수동으로 조작하면 오류가 발생할 가능성이 커집니다. 그리고 데이터를 여러 위치에서 렌더링한다면 실수해서 빼먹는 가능성이 있으며 유지관리 복잡성이 증가합니다.
그래서, 선언형 UI 모델로 전환하기 시작했으며,이에 따라 ㅂ질드 및 엔지니어링이 크게 감소해씁니다. 처음부터 화면 전체를 개념적으로 재생성한 후 필요한 변경사항만 적용하는 방식입니다.
@Composable
그림<1> 데이터를 사용하여 다른 컴포저블을 호출하는 그림
그림<2> 사용자가 UI 요소와 상호작용하여 이에 따라 이벤트 트리거되며 앱 로직이 이벤트에 응답합니다.
Compose에서는 새 데이터를 사용하여 구성 가능한 함수를 다시 호출합니다. 이에 따라 함수가 재구성되며 , 필요한 경우 새 데이터로 다시 그려집니다.
@Composable
fun ClickCounter(clicks: Int, onClick: () -> Unit) {
Button(onClick = onClick) {
Text("I've been clicked $clicks times")
}
}
@Composable
fun SharedPrefsToggle(
text: String,
value: Boolean,
onValueChanged: (Boolean) -> Unit
) {
Row {
Text(text)
Checkbox(checked = value, onCheckedChange = onValueChanged)
}
}
@Composable
fun ButtonRow() {
MyFancyNavigation {
StartScreen()
MiddleScreen()
EndScreen()
}
}
@Composable
fun ListComposable(myList: List<String>) {
Row(horizontalArrangement = Arrangement.SpaceBetween) {
Column {
for (item in myList) {
Text("Item: $item")
}
}
Text("Count: ${myList.size}")
}
}
@Composable
@Deprecated("Example with bug")
fun ListWithBug(myList: List<String>) {
var items = 0
Row(horizontalArrangement = Arrangement.SpaceBetween) {
Column {
for (item in myList) {
Text("Item: $item")
items++ // Avoid! Side-effect of the column recomposing.
}
}
Text("Count: $items")
}
}
@Composable
fun NamePicker(
header: String,
names: List<String>,
onNameClicked: (String) -> Unit
) {
Column {
// [names]가 변경할 때가 아닌 [header]가 변경할때 재구성 한다.
Text(header, style = MaterialTheme.typography.h5)
Divider() // 구분선 html<hr> 비슷함
// LazyColumn은 RecyclerView의 Compose버전이다.
// items()는 RecyclerView.ViewHolder의 역할과 비슷하다.
LazyColumn {
items(names) { name ->
// 아이템의 [name] 이 업데이트 될때 어댑터의 아이템이 재구성된다.
// [header] 변경될때는 재구성하지 않는다.
NamePickerItem(name, onNameClicked)
}
}
}
}
/**
* Display a single name the user can click.
*/
@Composable
private fun NamePickerItem(name: String, onClicked: (String) -> Unit) {
Text(name, Modifier.clickable(onClick = { onClicked(name) }))
}