Language \ Framework/Kotlin(Android)

[Android] Jetpack Compose 기본 컴포넌트

구로모논 2025. 11. 23. 17:16

1. Scaffold

Scaffold는 화면의 기본 레이아웃을 담당한다.
아래와 같이 사용 가능하다.

내용에 보면 innerPadding 이라는 Scaffold에서 자체적으로 넘겨주는 파라미터가 있다.
PaddingValues 타입의 값을 넘겨주는데, 기기 상단(푸시아이콘, 시간 등)과 하단의 공간 Padding 값이다.
이 값을 사용하지 않으면, 상단과 하단의 공간까지 전체를 차지하여 표시한다.

@Composable
fun ScaffoldTemplate() {
  Scaffold(
    contentWindowInsets = WindowInsets.safeDrawing,
    topBar = {
        TopAppBar(
            title = { Text("타이틀") },
        )
    },
    bottomBar = {
        title = { Text("하단 바") },
    }
  ) { innerPadding -> 
    MainContent()
  }
}

 

2. Column, Row

jetpack compose의 기본 컴포넌트들이 대체적으로 플러터와 비슷하다.
Column은 수직으로 나열해주는 컴포넌트이고, Row는 수평으로 나열해주는 컴포넌트이다.

사용법은 아래와 같다.
나는 기본적으로 Scaffold안에 Column을 가장 먼저 사용한다.

@Composable
fun ColRow(innerPadding: PaddingValues) {
  Column(
      // 순서가 영향이 있을 수 있음
      modifier = Modifier // 스타일
          .fillMaxSize() // 이렇게 해주면 화면 전체를 차지한다
          .background(color = MaterialTheme.colorScheme.background)
          .padding(innerPadding),
      horizontalAlignment = Alignment.CenterHorizontally,
      verticalArrangement = Arrangement.SpaceBetween
  ) {
    Row(
        modifier = Modifier
            .fillMaxSize()
            .padding(innerPadding)
    ) {
        Text("Hello")
        Spacer(Modifier.width(16.dp)) // 공간만 차지하는 컴포넌트
        Text("World")
    }
  }
  
}

 

3. Box

Box는 하위 요소들을 모두 겹친 상태로 보여준다.
가장 앞에 있는 요소가 가장 밑으로 가고, 가장 뒤에 있는 요소가 가장 위로 올라온다.

@Composable
fun ImageTextBox() {
  Box(modifier = Modifier.size(120.dp)) {
      Image(painter = painterResource(R.drawable.bg), contentDescription = null)
      Text("Hello", modifier = Modifier.align(Alignment.Center))
  }
}

 

4. Lazy Column

LazyColumn은 반복되는 목록 형태를 보여줄 때 사용된다.
api 연동하여 무한스크롤을 구현하는 방법은 별도로 포스팅 예정

@Composable
fun OrgList(vm: OrgListViewModel = viewModel()) {
  val orgUi by vm.state.collectAsState()

  LazyColumn(
    modifier = Modifier.fillMaxSize()
  ) {
      items(orgUi.orgs, key = { it.orgId }) { org ->
          OrgRow(
              org = org,
          )
          HorizontalDivider(Modifier, DividerDefaults.Thickness, DividerDefaults.color)
      }
  }
}

 

 

5. Card

Card는 기본적으로 둥근 모서리를 가진 형태로 그려진다.
그룹화된 ui를 표현하기에 좋을 수 있다.

ex) 리스트 ui 구현 시, 목록의 객체 정보를 별도의 영역으로 구분하여 표시
ex) 화면 내부 특정 섹션에 그룹화 된 내용 표시

하지만 꼭 위의 상황이 아니더라도, 둥근 모서리를 가진 영역을 ui로 그려내고 싶을 때 사용하면 된다.

@Composable
fun LogoSection() {
  Card(
      modifier = Modifier
          .width(200.dp)
          .height(200.dp),
      shape = RoundedCornerShape(200.dp),
      elevation = CardDefaults.cardElevation(defaultElevation = 8.dp)
  ) {
      Image(
          painter = painterResource(id = R.drawable.bami),
          contentDescription = "로고",
          contentScale = ContentScale.Crop
      )
  }
}

 

6. TextField, Button

TextField, Button은 특별히 사용법에 대해 설명할 것은 없지만,
각 항목마다 Outlined 같은 조금 꾸며진 항목들이 존재한다.
그래서 각각 상황이나 전체적인 ui디자인에 맞게 기본 컴포넌트를 써도 되고, 꾸며진 컴포넌트를 쓰면 된다.

@Composable
fun InputComponents() {
  Column(
      modifier = Modifier.fillMaxSize(),
      verticalArrangement = Arrangement.Center,
      horizontalAlignment = Alignment.CenterHorizontally
  ) {
      TextField(
          value = text,
          onValueChange = {
              setValue(it)
          },
      )
      Button(
          onClick = {
              keyboardController?.hide()
              scope.launch {
                  snackbarHostState.showSnackbar("Hello $text")
              }
          }
      ) {
          Text("클릭")
      }
  }
}

 

마무리

일단은 위의 컴포넌트들만으로도 기본적인 화면은 구성할 수 있다.
전체적인 사용감이 플러터와 비슷하다고 느껴진다.
XML보다는 확실히 편하게 화면 구성이 가능하다는 점에서
앞으로 Jetpack compose의 점유율이 높아질 것 같다는 생각이 든다.

이 외에 Navigation, State에 대해서도 포스팅할 예정이다.