Jay's Developer Note

[Android] Jetpack Compose에 쓰인 Kotlin 특징 - 2 본문

Android

[Android] Jetpack Compose에 쓰인 Kotlin 특징 - 2

Jay(J) 2023. 12. 1. 21:17
728x90

Jetpack Compose에 쓰인 Kotlin 특징 part. 2

지난번에 이어 Kotlin의 특징을 마저 서술하겠다. 이 특징들은 아주 신박하다. 특히 Destructuring은 진짜 예술이다. 처음 이 친구를 봤을 때 필자는 머리를 한 대 맞은 듯 얼얼했다. 그럼 얼른 써내려가보겠다.

 

범위(Scopes)

이게 무슨 말인가 싶을 텐데, 쉽게 얘기하자면 어떠한 함수나 속성값은 특정 범위에서만 사용이 가능하다는 것이다.

백문이 불여일견! 코드로 확인해 보자.

Row {
  Text(
    text = "Hello There",
    // modifier = Modifier.align(Alignment.CenterHorizontally) // Error
    modifier = Modifier.align(Alignment.CenterVertically)
  )
}

Column {
  Text(
    text = "Hello There",
    // modifier = Modifier.align(Alignment.CenterVertically) // Error
    modifier = Modifier.align(Alignment.CenterHorizontally)
  )
}

차이점이 눈에 들어오는가?

Row와 Column 안에 들어가는 modifier의 정렬 값이 다른 것을 볼 수 있다.

RowScope에는 Center정렬할 때 CenterVertically만, ColumnScope에는 CenterHorizontally만 사용이 가능하다.

그 이유는 조금만 생각해 보면 이해할 수 있다.

Row, Column을 모르는 사람은 없겠지..?

 

Jetpack Compose에서 Row는 가로Column은 세로로 Contents가 배치된다.

그렇다면 Row에 CenterVertically, Column에 CenterHorizontally를 적용하면 아래와 같이 Center정렬이 된다.

 

 

 

Center정렬을 하려 할 때 에러가 없다 가정하고 만약에 Row에 Horizontally, Column에 Vertically를 주면 어떻게 될까?

가로로 배치됐던 항목들이 가로의 중앙에 겹쳐서 정렬될 것이다. 세로로 배치됐던 항목들은 세로의 중앙에 겹쳐서 정렬될 것이다.

실제로는 불가능함 !

예시는 버튼 모양의 한 종류의 위젯으로만 그렸지만 실제로는 텍스트며 버튼이며 모든 하위 content들이 뭉쳐질 것이다.

 

위임된 속성(Delegated Properties)

이 속성은 단순 변수처럼 호출해서 사용하지만 그 값은 표현식을 통해 동적으로 정해진다.

by를 사용해서 인식할 수 있다.

class DelegatedPropTest {
  var uid: String by ManageUid()
}

fun test() {
  val dpt = DelegatedPropTest()

  Log.d("TAG", "This user's uid is ${dpt.uid}")
  dpt.uid = "UID123456789"
}

이런 식으로 사용할 수 있다.

ManageUid Class에는 getValue와 setValue Operator가 정의되어 있어야 한다.

class ManageUid {
  operator fun getValue(
    delegatedPropTest: DelegatedPropTest,
    property: KProperty<*>
  ): String {
    return "UID987654321"
  }

  operator fun setValue(
    delegatedPropTest: DelegatedPropTest,
    property: KProperty<*>,
    s: String
  ) {
    println(s)
  }
}

test 함수에 있는 getter, setter가 실행되면 아래와 같이 나올 것이다.

This user's uid is UID987654321
UID123456789

이 녀석은 Compose에서 상태 속성에 아주 굉장히 유용하게 쓰인다.

remember APImutableStateOf( )를 이용한다.

remember는 메모리에 객체를 저장하는 역할을 하고, mutableStateOf는 런타임 시 Compose에 통합되는 Observable MutableState를 생성하여 데이터를 관찰한다.

// by 로 사용하려면 아래 2개의 라이브러리가 필수 import 되어야 한다.
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

var isChecked by remember { mutableStateOf(false) }
    
Checkbox(
  checked = isChecked,
  onCheckedChange = {
    isChecked = it
  }
)

remember와 mutableStateOf를 활용해서 간단한 Checkbox interaction을 만들어봤다.

(Compose의 Checkbox는 onCheckedChange가 없으면 체크표시조차 되지 않는다! xml은 됐었나...?)

by 대신 = 대입으로 사용할 수도 있다. 그렇게 되면 사용할 때 isChecked.value로 사용해야 한다.

 

데이터 클래스 구조분해(Destructuring Data Classes)

진짜 볼수록 멋있고 아름답다. 이건 구조화된 클래스를 풀어서 바로 사용할 수 있게 해주는 그런 기능이다. 역시 말이 필요 없이 예제를 같이 보도록 하자.

data class Student(val name: String, val score: Int)

간단하게 학생 이름과 점수를 갖고 있는 데이터 클래스를 만들고 Destructuring 해서 써보겠다.

val jay = Student("JayChoi", 100)

// Destructuring
val (name, score) = jay

// Same result
val name = jay.name
val score = jay.score

( ) 괄호 안에 들어가는 변수이름은 아무렇게나 지어도 상관없다. 꼭 데이터 클래스에서 선언했던 변수를 따라갈 필요는 없다.

단, 데이터 클래스에서 선언했던 순서대로 Destructuring이 되기 때문에 3개가 있을 때 2개만 하면 2개만 구조분해되는 점을 유의하자.

 

728x90

 

data class Student(val name: String, val score: Int, val gender: String)

기존 데이터 클래스에 gender를 추가했다.

val jay = Student("JayChoi", 100, "M")

// Destructuring
val (n, g) = jay

println("Name : $n Gender : $g")

이렇게 쓰게 되면 g 라는 변수에는 100이라는 값이 들어가게 되니 유의하자.

Name : JayChoi Gender : 100

 

 

마치며

이번 게시글까지 해서 분량 안 넘치고 알차게 특징들을 알아보았다.

다음 게시글부터는 본격적으로 Jetpack Compose에 대해 탐구해 보겠다.

728x90