From_Base

[Jetpack Compose] Chapter1. 기초 본문

Android/Jetpack Compose

[Jetpack Compose] Chapter1. 기초

base_coding 2025. 1. 2. 22:24

개요:

Jetpack Compose는 Google에서 출시한 최신 네이티브 Android UI 툴킷입니다. Kotlin 언어 기반의 선언형 UI 프레임워크로, 기존의 명령형 XML 레이아웃 방식에서 벗어나 Kotlin 코드로 UI를 정의함으로써 더욱 직관적이고 효율적인 UI 개발 방식을 제시하며 Android 개발의 새로운 표준으로 자리 잡고 있습니다. 이 글에서는 Jetpack Compose의 핵심 개념, XML과의 차이점, 주요 장점, 그리고 간단한 예제를 통해 Jetpack Compose를 소개하겠습니다.

 


XML vs Jetpack Compose: 

 

안드로이드 UI 개발은 오랫동안 XML을 기반으로 이루어져 왔습니다. XML은 UI 레이아웃을 명확하게 정의할 수 있다는 장점이 있지만, 코드가 길어지고 복잡해지는 경향이 있었습니다. UI를 업데이트할 때마다 개발자가 변경부분을 직접 수정해야 하므로 번거롭고 오류가 발생하기 쉬워 유지보수가 어려우며,  XML은 각 레이아웃마다 별도의 XML 파일을 사용해야했습니다.

 

반면, 최근에는 선언형 UI 모델이 업계 전반의 트렌드로 자리 잡으면서 Jetpack Compose가 등장했습니다. Compose는 UI를 Kotlin 코드로 직접 inline으로 작성하는 선언형 UI 방식을 통해 UI 개발을 혁신적으로 간소화해주고, 개발자는 UI의 현재 상태를 선언하기만 하면 Compose가 자동으로 UI를 업데이트해줍니다. 덕분에 코드가 간결해지고 유지보수가 쉬워졌으며, UI 업데이트 로직을 직접 작성할 필요가 없어 오류 발생 가능성도 줄어들었습니다.

 

Compose는 다음과 같은 장점들을 제공합니다.

  • 간결하고 직관적인 코드: xml없이 간단한 Kotlin 코드만으로 UI를 작성하여 가독성을 높이고 코드량을 줄입니다.
  • 쉬운 유지보수: 선언형 UI 방식을 통해 UI 변경 및 관리가 용이합니다.
  • 향상된 성능: 최적화된 렌더링 엔진을 사용하여 XML보다 빠른 성능을 제공합니다.
  • 강력한 기능: 애니메이션, Material Design 지원 등 다양한 기능을 제공합니다.

즉, Jetpack Compose는 선언형 UI 방식을 통해 안드로이드 UI 개발을 더욱 간결하고 효율적으로 만들어주는 새로운 프레임워크이며, 기존 주류로 사용되어왔던 XML에 비해 코드 작성, 유지보수, 성능 측면에서 많은 이점을 제공해줍니다. 

 

 

 

<기존 명령형 프로그래밍 방식: XML >

 val textView: TextView = findViewById(R.id.textView)
        val button: Button = findViewById(R.id.button)

        button.setOnClickListener {
            textView.text = "텍스트가 변경되었습니다!"
        }

 

<신규 선언형 프로그래밍 방식: Jetpack Compose> ( UI 구성 & 인터렉션을 한번에!)

var text by remember { mutableStateOf("안녕하세요") }

Text(text = text)
Button(onClick = { text = "텍스트가 변경되었습니다!" }) {
Text("텍스트 변경")

 

 

위의 간단한 코드블럭 예제를 보더라도, Jetpack Compose로 넘어오면서 기본적인 코드량이 확실하게 감소되었음을 파악해볼 수 있습니다.  

 

 


 

 

키워드로 알아보는 이번 Chapter 중요 개념들: 

 

선언형 UI (Declarative UI):

UI의 현재 상태를 선언적으로 기술하기만 하면 UI가 구성되는 방식.
Compose는 이러한 선언을 기반으로 UI를 자동으로 그려줌.

  • "화면에 텍스트를 표시하고 싶다" ➡️ Text(text = "안녕하세요")
  • "버튼을 클릭하면 텍스트가 바뀌었으면 좋겠다" ➡️ Button(onClick = { /* 텍스트 변경 */ }) { Text(text = text) }

 

 

Composable  함수 (구성 가능한 함수 ):

📌앱의 UI를 구성하는 구성 요소이자 함수
(앱 화면이 하나의 요리라고 한다면, Composable 함수는 각각의 재료).


Jetpack Compose는 Kotlin 컴파일러를 사용하여 Composable 함수를 ➡️ 앱의 UI요소로 변환. 
이는 마치 React Native 에서의 함수형 컴포넌트와 유사( 상태 관리 & 변경된 부분만을 다시 렌더링하여 UI 업데이트 )

✅ 함수를 구성 가능한 함수로 만드려면 @Composable 어노테이션을 함수의 맨 위에 추가해줘야함
✅ Composable 함수는 Composable함수에서만 호출가능

이 컴포저블 함수 선언으로 앱의 UI의 일부분인 UI 컴포넌트들을 쉽게 구성가능!

  • ex) Compose UI 라이브러리에 정의된 텍스트를 화면에 표시해주는  Composable 함수 Text() 

 

 

@Preview ( 미리보기 ):

@preview 어노테이션을 사용하면, @preview가 달린 Composable 함수에서 생성한 UI요소를 앱 빌드전에 미리 확인해볼 수 있음
Android 스튜디오 내의 분할(디자인/코드) 보기에서의 미리보기 창

 

이렇듯, @Preview 어노테이션이 붙은 Composable UI 구성요소들을 번거로운 에뮬레이터 및 빌드과정 없이 미리 확인 가능.
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    JetpackTheme {
        Greeting("안드로이드")

    }
}

 

 

 

Scaffold() :

앱 화면의 기본적인 틀을 잡아주는 역할을 하는 기본 Composable 함수.
앱의 상단 바, 플로팅 버튼, 하단 바, 콘텐츠 영역 등, 앱 화면을 구성하는 주요 UI 요소들을 쉽게 배치하고 관리해줌.


<Scaffold가 제공하는 주요 구성 요소들>

  • topBar: 앱의 상단에 위치하는 앱 바. 앱의 제목, 메뉴 등
  • bottomBar: 앱의 하단에 위치하는 앱 바. 탐색 버튼, 액션 버튼 등
  • floatingActionButton: 화면 위에 떠 있는 액션 버튼. 주요 액션을 수행하는 데 사용
  • content: 위 주요 요소들을 제외한, 개발자가 자유롭게 배치할 수 있는 앱의 주요 콘텐츠가 표시되는 영역.

위의 구성 요소들은 Scaffold의 매개변수로 설정 가능. (마지막 매개변수는 content 영역이며, 람다 type 입니다)

Scaffold 컴포저블의 마지막 매개변수는 content: @Composable (PaddingValues) -> Unit 으로, 람다 type 이기때문에 타 매개변수들과 구분하여 밖에 따로 작성해주는 것이 좋습니다. ( 코틀린 trailing lambda 문법 )

Text() 같은 화면에 문자열 표시와같은 단순한 컴퍼저블의 content 영역은 text라는 단일 문자열 매개변수 하나로만 구성되지만, Scaffold의 content 영역에는 여러 UI 구성요소 컴퍼저블들이 포함되기때문에 Scaffold는 content 영역을 람다식으로 받음

이전 버전에서는 Scaffold의 content 영역에 padding 값을 명시적으로 지정하지 않아도 되었지만, compose 가 많은 변화를 거치면서 Scaffold의 content 영역에 padding values를 써주도록 변경되었습니다.
이는 Scaffold의 content 영역에 배치되는 컴포저블들이 Scaffold 내부의 padding 값을 고려하여 배치되어야 하기 때문입니다. 
예를 들어, topBar나 bottomBar가 화면의 일부 영역을 차지하기 때문에, content 영역에 padding을 적용시켜주지 않는다면 content 영역의 컴포저블들이 이들과 겹쳐 화면에 보이지 않게됩니다.


그럼에도 불구하고 Scaffold 를 사용하면서 padding을 적용시키고 싶지않은 경우에는 Scaffold 상단에
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")

위와 같은 어노테이션을 작성해주면 됩니다.

하지만 이 방법은 권장하지 않습니다. padding 값을 무시하면 content 영역의 컴포저블들이 TopAppBar나 BottomAppBar와 겹쳐 보일 수 있기 때문입니다.

따라서 Scaffold를 사용할 때는 content 영역에 innerPadding 매개변수를 명시적으로 전달하고, Modifier.padding(innerPadding)을 사용하여 컴포저블에 padding을 적용하는 것이 좋습니다. 이렇게 하면 컴포저블들이 화면에 정상적으로 표시됩니다.





<간단한 Scaffold 사용 예시>

Scaffold(
//플로팅 버튼
    floatingActionButtonPosition = FabPosition.End,
    floatingActionButton = {
    FloatingActionButton(onClick = { } , shape = CircleShape, containerColor = Color.Yellow) {

        Text("클릭")
}},
//상단 바
    topBar = {
        TopAppBar(
            title = { Text("WJ's Android App") },
            colors = TopAppBarDefaults.topAppBarColors(
                containerColor = Color(0xFFF25287),
            )
        )
    },
//하단 바
    bottomBar = {
        BottomAppBar(
            contentColor = Color.Red,
            containerColor = Color(0xFF00FF00),

        ) {
            Text("BottomAppBar")
            IconButton(onClick = {}) {
                Icon(Icons.Default.Favorite, contentDescription = "Favorite")
            }
        }
    },


) 
// content 영역
{
  // Scaffold의 content 영역에 innerPadding 적용
        // Compose 업데이트 이후, Scaffold의 content 영역에 padding values를 써주도록 변경되었음.
        // Scaffold의 content 영역에 배치되는 컴포저블들은 Scaffold 내부의 padding 값을 고려하여 배치되어야 함.
        // Scaffold의 content 람다식의 유일한 하나의 매개변수인 innerPadding은, 탑 바, 하단 바 등을 고려하여 자동으로 계산된 패딩 값임.
        // 즉 Scaffold는 content 람다식에 PaddingValues 타입의 매개변수를 전달하여, 앱 바, 하단 탐색 바 등의 크기를 고려한 패딩 값을 제공해주는 것인데,
        // 왜 자동으로 제공하느냐? -> 상단 바, 하단 바 등 앱 기본 UI요소들 때문에 content에 정의한 컴포저블 UI요소들이 하단 바 등등에 가려지기 때문에
        // 가려지지않고 올바르게 배치될 수 있도록 compose 프레임워크에서 적절히 padding 값을 자동으로 계산하여 넘겨주는 것.
        // 즉, PaddingValues 타입 매개변수인 innerPadding을 적용해야 하단바, 상단바 등등의 요소들과 겹치지 않게돠어 화면에 보임.
            innerPadding -> MyComposableView(innerPadding) // innerPadding을 MyComposableView에 전달
}

 

 

 

표준 레이아웃 구성요소(Column, Row, Box) :

 Composable 함수는 여러 UI 요소를 내보낼 수 있습니다. 하지만, 그 UI 요소들을 어떻게 배치해야 하는지에 대한 가이드를 제공하지 않으면 UI 요소들이 뒤죽박죽 겹쳐서 그려지는 등 원치않는 구성으로 배치되어질 것 입니다.
이를 위해, Compose는 UI 요소를 배치하는 데 도움을 주는 표준 레이아웃 컬렉션을 제공해줍니다.

출처: https://developer.android.com/develop/ui/compose/layouts/basics?hl=ko



  • Modifier : Modifier는 레이아웃을 비롯한 UI요소들의 크기, 위치, 정렬, 패딩,효과 등을 조정하는 데 사용하는 조정자.

    ✅ Jetpack Compose의 모든 컴포저블은 modifier 매개변수를 가지고 있으며, modifier는 컴포저블의 크기, 위치, 정렬, 배경, 패딩, 클릭 이벤트 처리 등 다양한 속성을 변경하는 데 사용됨.
    modifier 매개변수는 항상 컴포저블 함수의 첫 번째 선택적 매개변수인 것이 특징 
    Modifier는 .(점)연산자를 사용하여 체이닝(chaining)을 통해 여러 수정자를 연결하여 사용할 수 있음


    < Modifier 일부 속성들 및 간단한 사용예시>
  • clickable: 컴포저블이 사용자 입력에 반응하도록 설정
  • padding: 요소 내부에 여백공간 설정
  • fillMaxWidth: 컴포저블이 상위 요소로부터 부여받은 최대 너비를 채우도록 설정
  • background(): 요소의  배경 색상 설정
Text(
    text = "Hello",
    modifier = Modifier
        .padding(16.dp)
        .background(Color.Blue)
)



<간단한 레이아웃 사용 예시>

@Composable
fun LayoutSample() {
    Column(){
        Text(
           //...
        )
    }

    Row{
        Text(
            //...
        )
    }

    Box(
        modifier = Modifier
            .clickable(onClick = { /* 클릭 이벤트 처리 */ })
            .padding(16.dp)
            .fillMaxWidth()
    ) {
        Image(
           //...
        )
        Text(
            //...
        )
    }
}

 

 

 

 


 

 

참고 자료 및 같이 참고하면 좋은 자료들:

 

https://developer.android.com/develop/ui/compose/tutorial?hl=ko

 

Android Compose 튜토리얼  |  Jetpack Compose  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Jetpack Compose는 네이티브 Android UI를 빌드하기 위한 최신

developer.android.com

 

https://youtu.be/BX0rQvYgf1I?si=hFUGvW9DRHZ3G21c

https://youtu.be/1apENzDbtCQ?si=QkTOpsGhfx-gs3E9