Tech/앱동-kotlin 부트캠프

[2주차].단어 리스트 UI 그리기

JSJH._. 2026. 4. 6. 16:39

[2주차] 단어 리스트 UI 그리기

  • 이번 주는 앱 화면에 단어장의 껍데기를 만들어 화면에 띄우는 주차입니다.
  • 아직 눌러도 아무 반응 없으며, 철저히 보이는 것만 만드는 주차입니다.

오늘의 목표

  • 스마트폰에 단어 카드가 하나 뜹니다.
  • 오른쪽에 아이콘이 보이지만, 아직 눌러도 기능은 없습니다.

1. 패키지(폴더) 나누기

  • 코드를 깔끔하게 정리하기 위해 서랍장(폴더)을 두 개 만듭니다.
  1. 왼쪽 폴더 트리에서 app > kotlin+java > com.example...(자신의 패키지명) 폴더 우클릭.
  2. New -> Package 클릭.
  3. 깜빡이는 이름 맨 뒤에 data 라고만 이어서 치고 엔터 (데이터 보관용 폴더).
  4. 똑같이 상위 패키지를 한 번 더 우클릭해서 ui 라고 치고 패키지 1개 더 생성 (화면용 폴더).
    ui는 이미 자동생성 되어있을수도..

2. 2주차 뼈대 파일 생성

  1. 방금 만든 data 폴더 우클릭 ➜ New -> Kotlin Class/File 클릭.
    데이터 클래스로 만들어도 되긴하지만 일단은 기본클래스로 만들기
  2. 빈칸에 Word 입력 후 엔터 ➜ 2주차 준비 코드 - Word.kt 전체 복붙.
  3. ui 폴더 우클릭 ➜ 똑같은 방법으로 이름은 HomeScreen 입력 후 엔터 ➜ 2주차 준비 코드 - HomeScreen.kt 전체 복붙.
  4. 마지막으로 화면을 띄워줄 MainActivity.kt 열어서 안의 WordCardScreen() 글자를 HomeScreen() 으로 수정.
    시작부분의 함수를 바꾸기.
    밑의 함수는 쓸모 없어짐.
    그러면 오류와 함께 자동으로 {kotlin}import com.example.bootcamp_wordlist.ui.HomeScreen 삽입 가능하게함

3. 빈 화면에 데이터 심기

  1. 방금 만든 HomeScreen.kt 파일 열기.
  2. HomeScreen 함수 안쪽의 주석 // TODO: 여기에 더미 데이터 넣기 찾기.
  3. 아래 코드를 복사해서 주석 밑에 붙여넣고 임시 단어 생성하기.
// 더미 데이터(사과) 만들기 (Long 타입 id는 L 붙이기)
val dummyWord = Word(
    id = 1L,
    spelling = "apple",
    meaning = "사과",
    isHidden = false
)

// UI 그리는 함수에 이 단어 넘겨주기
WordItem(word = dummyWord)
  • 예시 출력을 위한 더미데이터입니다.

4. 2주차 UI 코드 이식

  1. 스크롤을 맨 밑으로 내려서 2주차 완성 코드 안의 WordItem 함수 몸통 전체 복사.
  2. HomeScreen.kt 맨 밑에 비어있는 fun WordItem(word: Word) 함수 덮어쓰기.
  3. 상단 초록색 (Run) 클릭.

5. 기본적인 android 문법 (2주차)

1. Card { }

둥근 박스나 그림자를 가진 카드 모양 UI.

// Card = 둥근 네모 박스 (전체 껍데기)
Card(
    modifier = Modifier.fillMaxWidth(),
    shape = RoundedCornerShape(16.dp),
    // elevation = 기본 그림자 없애기
    elevation = CardDefaults.cardElevation(0.dp)
) { ... }
  • RoundedCornerShape() = 모서리 얼마나 둥글게 깎을지 결정.

2. Row { }

안에 있는 요소들을 왼쪽에서 오른쪽으로 가로 배치하는 레이아웃.

  • 지난주에 배운 Column은 세로(위아래) 정렬.
  • 이번 주에 쓰는 Row는 가로(양옆) 정렬.

3. weight(1f)

가로 배치(Row) 안에서 남는 공간을 똑같은 비율로 꽉 채우게 하는는 옵션.

Text(
    text = word.spelling,
    modifier = Modifier.weight(1f) // 여백 1배수 할당
)
  • Text에 weight(1f), 뜻 Text에 weight(1f)를 주었으므로 화면을 1:1 비율로 양분함.

4. IconButton { } & Icon()

화면에 쓸모 있는 클릭 버튼과 아이콘 이미지 띄우기.

IconButton(onClick = { /* 나중에 기능 붙일 곳 */ }) {
    Icon(
        imageVector = Icons.Default.Delete,
        contentDescription = "삭제"
    )
}
  • IconButton = 클릭 가능한 원형 투명 구역 만들기.
  • Icon = 안드로이드 내장 아이콘 그리기.

5. Modifier (생김새 조작 리모컨)

UI 블록의 크기(fillMaxWidth()), 여백(padding()), 정렬을 조작하는 설정값입니다.

  • 안드로이드 Compose의 모든 화면 요소는 괄호 안에 modifier = 를 넣어 비율과 간격을 세팅.

6. dp와 sp (반응형 단위)

다양한 스마트폰 크기에도 안 깨지게 화면을 그리는 안드로이드 전용 크기 단위.

  • dp (Density-independent Pixels): 여백, 상자 크기 같은 물리적 박스 사이즈.
  • sp (Scale-independent Pixels): 글씨 전용 크기.
    저번 주차 설명 내용

6. 에러 대응

발생할 수 있는 문제

  • 아이콘 코드에 빨간줄 뜸
    Alt + Enter 눌러서 import 선택
    Alt+Enter가 굉장히 유용합니다.
  • 글씨만 있고 카드가 안 생김
    Card 괄호 { } 안에 다른 코드가 제대로 들어갔는지 확인
  • 아무것도 안 뜸
    실습 1에서 WordItem(word = dummyWord) 코드를 안 적었음

2주차 준비 코드

  • Word.kt 파일
package com.example.bootcamp_wordlist.data // data 폴더에 넣었으므로 .data로 끝납니다. (맨 윗줄은 지우지 마세요)

// Word = 단어 하나가 가지는 정보 꾸러미
data class Word(
    val id: Long = System.currentTimeMillis(), // 추가 시각(밀리초)을 고유 id로 자동 사용
    val spelling: String,
    val meaning: String,
    val isHidden: Boolean = false
)
  • HomeScreen.kt 파일
package com.example.bootcamp_wordlist.ui // ui 폴더에 넣었으므로 .ui로 끝납니다. (맨 윗줄은 지우지 마세요)

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.bootcamp_wordlist.data.Word

@Composable
fun HomeScreen() {
    Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        // TODO: 여기에 더미 데이터 넣기
    }
}

// 2주차 동안 밑에서 코드를 채워넣을 빈 껍데기 함수
@Composable
fun WordItem(word: Word) {
}

2주차 완성 코드

  • HomeScreen.kt 파일 하단의 WordItem 함수 (이걸 덮어쓰기 하세요)
@Composable
fun WordItem(word: Word) {
    // Card = 둥근 네모 박스 (전체 껍데기)
    Card(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(16.dp),
        colors = CardDefaults.cardColors(containerColor = Color.White),
        // elevation = 기본 그림자 없애기
        elevation = CardDefaults.cardElevation(0.dp)
    ) {
        // Row = 가로 배치 레이아웃
        Row(
            modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 14.dp),
            // verticalAlignment = 세로 중앙 정렬
            verticalAlignment = Alignment.CenterVertically
        ) {
            // Text 1: 단어 
            Text(
                text = word.spelling,
                fontSize = 18.sp,
                fontWeight = FontWeight.SemiBold,
                modifier = Modifier.weight(1f)
            )
            // Text 2: 뜻 
            Text(
                text = word.meaning,
                fontSize = 14.sp,
                color = Color(0xFF888888),
                modifier = Modifier.weight(1f)
            )
            
            // IconButton 1: 투명 원형 버튼 (눈 모양)
            IconButton(onClick = { /* 나중에 기능 추가 */ }) {
                Icon(
                    imageVector = Icons.Outlined.Visibility,
                    contentDescription = "숨기기",
                    // tint = 기본 검정색 대신 회색 덧칠
                    tint = Color(0xFFAAAAAA)
                )
            }

            // IconButton 2: 투명 원형 버튼 (삭제)
            IconButton(onClick = { /* 나중에 기능 추가 */ }) {
                Icon(
                    imageVector = Icons.Default.Delete,
                    contentDescription = "삭제",
                    tint = Color(0xFFAAAAAA)
                )
            }
        }
    }
}