Skip to content

[Android] 젯팩 컴포즈: 선언적 UI 패러다임 연구

Notifications You must be signed in to change notification settings

chihyeonwon/Kotlin_Compose

Repository files navigation

안드로이드 컴포즈 공식 개발 문서
컴포즈 성능 최적화
image

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Welcome()
        }
    }
}

@Composable
@Preview
fun Welcome() {
    Text(
        text = stringResource(id = R.string.welcome,),
        style = MaterialTheme.typography.titleSmall
    )
}
Flutter와 마찬가지로 선언적 UI를 사용함에 따라 @Preview 어노테이션을 사용하여서 바로 변경사항을 미리 볼 수 있다. (flutter의 hot-reloading과 동일)

image

@Composable
@Preview
fun Greeting(name: String = "원치현") {
    Text(
        text = stringResource(id = R.string.hello, name),
        textAlign = TextAlign.Center,
        style = MaterialTheme.typography.titleMedium
    )
}

string.xml

<string name="hello">Hello, %1$s \nNice to meet you.</string>
strings에 문자열을 html로 넣어서 읽을 수 있다. @Preview 미리보기를 사용하기 위해 함수의 매개변수에 기본 값으로 이름을 넣어주었다.

컴포즈의 미리보기 기능

image

SetContent 에서 Hello 함수와 Greeting 함수 중 Hello만 넣고 기기를 실행하면 실제 에뮬레이터에는 Hello 함수만 실행되어 보이지만
미리보기 화면에서는 Hello와 Greeting이 모두 보이는 것을 알 수 있다.

Row, TextField

@Composable
fun TextAndButton(name: MutableState<String>, nameEntered: MutableState<Boolean>) {
    Row(modifier = Modifier.padding(top = 8.dp)) {
        TextField(
            value = name.value,
            onValueChange = {
                name.value = it
            },
            placeholder = {
                Text(text = stringResource(id = R.string.hint))
            },
            modifier = Modifier
                .alignByBaseline()
                .weight(1.0F),
            singleLine = true,
            keyboardOptions = KeyboardOptions(
                autoCorrect = false,
                capitalization = KeyboardCapitalization.Words,
            ),
            keyboardActions = KeyboardActions(onAny = {
                nameEntered.value = true
            })
        )
    }
}
Flutte와 유사하게 Row, Column으로 레이아웃의 배치를 한다.
Row는 modifier 매개변수를 받고 외형과 행위에 영향을 준다.

Row안에 여러 컴포저블 함수를 배치한다.
  Button(modifier = Modifier
            .alignByBaseline()
            .padding(8.dp),
            onClick = {
                nameEntered.value = true
            }) {
            Text(text = stringResource(id = R.string.done))
Row 안에 Button 컴포저블 함수를 추가했다. 버튼을 클릭하면 nameEntered의 값의 상태를 true로 변경한다.

2024-06-22 11;26;12

@Composable
fun Hello() {
    val name = remember { mutableStateOf("") } // 상태 생성: mutableStateOf 상태 기억: remember
    val nameEntered = remember { mutableStateOf(false) }
    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        contentAlignment = Alignment.Center
    ) {
        if (nameEntered.value) {
            Greeting(name.value)
        } else {
            Column(horizontalAlignment = Alignment.CenterHorizontally) {
                Welcome()
                TextAndButton(name, nameEntered)
            }
        }
    }
}
mutableStateOf 는 상태를 생성하고 remember는 상태를 기억한다.
Column은 Row(가로)와 마찬가지로 컴포저블 요소의 위치 상태를 세로로 결정한다.
위 코드를 실행하면 nameEntered.value가 true라면 Greeting의 매개변수로 전달한다. (TextButton 클릭 시 true로 변경됨)
버튼 클릭 하기 전에는 Welcome와 TextAndButton을 실행한다.

미리 보기 설정

image

@Preview(showBackground = true, backgroundColor = 0xffff0000)
Preview 어노테이션에 showBackground 속성과 backgroundColor 속성을 이용하여 미리보기의 배경색을 설정할 수 있다.

image

@Preview(widthDp = 100, heightDp = 100)
widthDp와 heightDp 속성값을 이용하여 미리 보기의 면적을 지정할 수 있다. (.dp는 생략, 밀도 독립 픽셀)

미리 보기 그룹화

image

@Preview(group = "my-group-1")
미리 보기를 그룹화(컴포저블 함수에 네이밍)하여 미리보기에서 보이게 할지 안 보이게 할지 설정할 수 있다.

컴포넌트와 컴포저블 함수

일반적으로 컴포넌트는 UI 요소와 관련되어 있다. 컴포넌트는 메시지를 주고 받는 방식을 사용해 시스템의 다른 부분과 통신한다.
컴포넌트의 모습과 행위는 일련의 속성이나 프로퍼티로 제어한다.

XML 속성에서 태그마다 고유한 속성이 있는 것을 알 수 있다. android:layout_width, android_layout_height는 요소의 크기를 정의한다.
크기와 위치는 컴포넌트와 관련이 있다.

이런 속성을 기반으로 각각의 컴포넌트는 전문화 단계를 갖는다.

객체지향 프로그래밍 언어에서는 상속을 통해 전문화의 정도를 손쉽게 모델링한다. 더욱 전문화된 UI 요소(클래스)는 일반적인 요소를 확장한다.

컴포넌트 계층 구조의 한계

모든 컴포넌트는 계층 구조를 갖는다. 가령 EditText의 직계 부모는 TextView이고 부모 클래스는 View를 확장한다.

자바는 단일 상속 기반이기에 클래스는 정확히 한 개의 클래스만 확장한다. Button이 TextView와 ImageView의 기능을 모두 사용하고자 한다면
두 클래스 모두를 확장해야하지만 그럴 수 없다는 의미이다.

컴포넌트 구조의 근본적인 문제는 더욱 전문화된 UI요소를 만들고자 하나 이상의 개별 기능을 조합하는 것이 불가능하다라는 것이다.

개별 기능은 분리할 수 없다. -> 재활용이 컴포넌트 단계에서 발생하기 때문이다.

UI 요소의 외형 또는 행위는 부모를 수정하기보다 Container, Padding, Align와 같이 간단한 구성 요소간의 조합으로 정의 -> 플러터(상속 보다는 구성 원칙)

젯팩 컴포즈 역시 간단한 구성 요소끼리를 조합하는 방식을 사용 ( 클래스 대신 컴포저블 함수를 사용한다 )

정리하자면 클래스 기반의 ui 컴포넌트 프레임워크는 상속을 통해 전문화를 모델링 -> 하지만 쓸데없는 상위 부모의 기능까지 상속받음
-> 내가 필요하고자 하는 기능을 조합해서 사용할 순 없을까? -> 단순화된 구성 요소 간의 조합을 사용한다 -> 젯팩 컴포즈의 컴포저블 함수로 구현

About

[Android] 젯팩 컴포즈: 선언적 UI 패러다임 연구

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages