Compose 기본2026년 01월 18일· 12 min read

Button 종류와 스타일링

Jetpack Compose Button 종류와 스타일링 - 기초 단계. Compose 기본 카테고리의 실전 가이드.

Button 종류와 스타일링

한 줄 요약

Jetpack Compose에서 다양한 버튼을 만들고 스타일링하는 방법을 배워보자!

들어가며

안드로이드 앱을 사용하다 보면, 클릭 가능한 버튼을 수도 없이 만나게 되지. 카카오톡의 '전송' 버튼, 인스타그램의 '좋아요' 버튼 등등. 버튼은 사용자와 앱이 상호작용하는 가장 기본적인 요소 중 하나야. 그래서 앱 개발에서 버튼을 어떻게 만들고 스타일링하느냐에 따라 사용자 경험이 달라질 수 있어. 오늘은 Jetpack Compose에서 버튼을 어떻게 다양하게 만들고 스타일링할 수 있는지 알아보자.

버튼 이미지

목차

  • Button이란?

  • Button 종류

  • 파라미터 설명

  • 내부 동작 원리

  • 실제 사용 예제

  • 자주 하는 실수

  • 실전 응용

  • 심화: 직접 구현해보기

Button이란?

버튼은 사용자가 클릭할 수 있는 UI 요소야. 예를 들어, 우리가 스마트폰에서 '확인'이나 '취소' 같은 버튼을 눌러서 어떤 작업을 수행하지. 이 버튼은 Jetpack Compose에서 Button 컴포저블로 표현돼. 이걸 사용하면 클릭 가능한 버튼을 쉽게 만들 수 있어.

Button 종류

Compose에서는 다양한 스타일의 버튼을 제공해. 각각의 특징을 살펴보자.

FilledButton

가장 일반적인 버튼으로 배경이 채워져 있어. 기본적으로 사용하기 좋아.



@Composable
fun showFilledButton() {  // 배경이 채워진 기본 버튼
    Button(onClick = { /* 클릭 이벤트 처리 */ }) {
        Text("Filled Button")  // 버튼에 표시될 텍스트
    }
}

OutlinedButton

테두리만 있고 배경이 투명해. 깔끔한 느낌을 줄 때 사용해.



@Composable
fun showOutlinedButton() {  // 테두리만 있는 버튼
    OutlinedButton(onClick = { /* 클릭 이벤트 처리 */ }) {
        Text("Outlined Button")  // 버튼에 표시될 텍스트
    }
}

TextButton

텍스트만 있는 버튼으로, 배경이나 테두리가 없어. 단순한 텍스트 링크 같은 느낌을 줄 때 유용해.



@Composable
fun showTextButton() {  // 텍스트만 있는 버튼
    TextButton(onClick = { /* 클릭 이벤트 처리 */ }) {
        Text("Text Button")  // 버튼에 표시될 텍스트
    }
}

IconButton

아이콘만 있는 원형 버튼이야. 앱바나 툴바에 주로 쓰여.



@Composable
fun showIconButton() {  // 아이콘만 있는 버튼
    IconButton(onClick = { /* 클릭 이벤트 처리 */ }) {
        androidx.compose.material.Icon(Icons.Filled.Favorite, contentDescription = "Favorite")  // 아이콘 표시
    }
}

FilledTonalButton

톤이 적용된 채워진 버튼으로, 색상의 변화를 준다.



@Composable
fun showFilledTonalButton() {  // 톤이 적용된 채워진 버튼
    FilledTonalButton(onClick = { /* 클릭 이벤트 처리 */ }) {
        Text("Tonal Button")  // 버튼에 표시될 텍스트
    }
}

ElevatedButton

그림자 효과가 있는 버튼으로, 강조하고 싶을 때 사용해.



@Composable
fun showElevatedButton() {  // 그림자 효과가 있는 버튼
    ElevatedButton(onClick = { /* 클릭 이벤트 처리 */ }) {
        Text("Elevated Button")  // 버튼에 표시될 텍스트
    }
}

파라미터 설명

각 버튼 컴포저블에는 여러 파라미터가 있어. 버튼을 어떻게 스타일링하고 동작하게 할지를 설정할 수 있지. 예를 들어 onClick은 버튼이 클릭되었을 때 실행할 동작을 정의해.

파라미터타입설명기본값
onClick() -> Unit버튼 클릭 시 실행할 동작필수
enabledBoolean버튼 활성화 여부true
elevationButtonElevation버튼의 그림자 효과기본값

각 파라미터 상세 분석

1. 파라미터 선언부 코드



@Composable
fun Button(
    onClick: () -> Unit,  // 클릭 시 실행할 동작
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    elevation: ButtonElevation? = ButtonDefaults.elevation(),
    ...
)

2. 내부 처리 로직 코드

// 버튼 내부에서 파라미터가 어떻게 처리되는지
@Composable
fun Button(
    onClick: () -> Unit,
    enabled: Boolean,
    elevation: ButtonElevation?,
    ...
) {
    // Step 1: 클릭 가능 여부 설정
    val isClickable = enabled && onClick != null

    // Step 2: 버튼 스타일 지정
    val buttonElevation = elevation ?: ButtonDefaults.elevation()

    // Step 3: 컴포저블 생성
    Surface(
        onClick = if (isClickable) onClick else null,
        elevation = buttonElevation,
        ...
    ) {
        // 버튼 내용을 그리는 부분
    }
}

3. 왜 이 파라미터가 필요한가?

  • onClick: 사용자가 버튼을 눌렀을 때 실행할 동작을 지정해줘야 앱이 반응해.
  • enabled: 버튼을 일시적으로 비활성화하고 싶을 때 사용해. 예를 들어, 로딩 중인 상태에서는 클릭을 막을 수 있어.
  • elevation: 버튼에 그림자 효과를 줘서 강조하거나 깊이감을 줄 수 있어.

4. 언제 이 파라미터를 바꿔야 하는가?

  • onClick: 버튼의 기능이 변경될 때, 예를 들어 로그인 버튼을 클릭했을 때 로그인 처리를 할 때.
  • enabled: 특정 조건에서 버튼을 비활성화해야 할 때, 예를 들어 입력 폼이 모두 채워지지 않았을 때.
  • elevation: 버튼을 더 강조하고 싶을 때, 예를 들어 메인 액션 버튼으로 사용하고 싶을 때.

내부 동작 원리

버튼 컴포저블이 어떻게 동작하는지 알아보자.

전체 흐름 개요

  1. Composition 단계: 버튼이 컴포지션 트리에 추가되고, 상태가 관리돼.
  2. Layout 단계: 버튼의 크기가 측정되고, 위치가 결정돼.
  3. Drawing 단계: 버튼의 배경, 테두리, 텍스트가 실제로 그려져.

상세 코드 레벨 분석

1. 함수 호출 시점부터 시작

@Composable
fun MyScreen() {
    Button(onClick = { /* 클릭 이벤트 처리 */ }) {
        Text("안녕하세요")  // 버튼에 표시될 텍스트
    }
}

2. Compose 내부 처리 과정



@Composable
fun Button(
    onClick: () -> Unit,
    enabled: Boolean = true,
    elevation: ButtonElevation? = null,
    ...
) {
    // Step 1: 클릭 가능 여부 설정
    val isClickable = enabled && onClick != null

    // Step 2: 스타일 및 레이아웃 설정
    val buttonStyle = ButtonDefaults.buttonColors()

    // Step 3: 컴포저블 생성
    Surface(
        onClick = if (isClickable) onClick else null,
        color = buttonStyle.backgroundColor(enabled).value,
        elevation = elevation ?: ButtonDefaults.elevation(),
        ...
    ) {
        // 버튼의 내용 렌더링
    }
}

실제 사용 예제

버튼을 실제로 어떻게 사용할 수 있는지 예제를 통해 살펴보자. 예를 들어 로그인 화면에서 버튼을 사용해보자.



@Composable
fun LoginScreen() {
    Button(onClick = { /* 로그인 처리 */ }) {
        Text("로그인")  // 버튼에 표시될 텍스트
    }
}

자주 하는 실수 TOP 3

실수 1: onClick을 설정하지 않음

  • 😵 문제: 버튼을 눌러도 아무 반응이 없어.
  • 🤔 원인: onClick 파라미터를 설정하지 않아서 클릭 이벤트가 발생하지 않아.
  • ✅ 해결: onClick 파라미터에 클릭 이벤트를 처리할 동작을 지정해줘.

실수 2: enabled 상태를 잘못 설정

  • 😵 문제: 버튼이 클릭되지 않거나, 비활성화 상태에서 클릭이 되어버려.
  • 🤔 원인: enabled 파라미터를 적절히 설정하지 않아.
  • ✅ 해결: 버튼의 상태에 따라 enabled 파라미터를 정확히 설정해줘.

실수 3: elevation을 잘못 설정

  • 😵 문제: 버튼의 그림자 효과가 너무 강하거나 약해.
  • 🤔 원인: elevation 파라미터를 잘못 설정해서 그림자 효과가 의도와 다르게 보여.
  • ✅ 해결: elevation 파라미터를 적절히 설정해줘.

버튼 이미지

실전 응용 예제

버튼을 어떻게 실전에서 활용할 수 있는지 알아보자.

  • 예제 1: 쇼핑 앱에서 '결제하기' 버튼을 만들어보자. 이 버튼은 결제 화면으로 이동하게 돼.


@Composable
fun CheckoutButton() {
    Button(onClick = { /* 결제 화면으로 이동 */ }) {
        Text("결제하기")  // 버튼에 표시될 텍스트
    }
}
  • 예제 2: SNS 앱에서 '팔로우' 버튼을 만들어보자. 이 버튼은 팔로우 상태에 따라 텍스트가 바뀌어.


@Composable
fun FollowButton() {
    val isFollowing = remember { mutableStateOf(false) }
    Button(onClick = { isFollowing.value = !isFollowing.value }) {
        Text(if (isFollowing.value) "언팔로우" else "팔로우")
    }
}

심화: Button을 활용한 실전 프로젝트 구현

1단계: 리플 효과가 들어간 버튼 만들기

Material Design의 리플 효과를 구현해보자.



@Composable
fun RippleButton() {
    Surface(
        modifier = Modifier.clickable { /* 클릭 처리 */ },
        color = MaterialTheme.colorScheme.primary,
        onClick = {}
    ) {
        Text("Ripple Button")
    }
}

2단계: 로딩 상태가 있는 버튼 만들기

버튼 클릭 시 로딩 인디케이터가 표시되도록 만들어보자.



@Composable
fun LoadingButton() {
    val isLoading = remember { mutableStateOf(false) }
    Box {
        Button(
            onClick = { isLoading.value = !isLoading.value }
        ) {
            if (isLoading.value) {
                CircularProgressIndicator(modifier = Modifier.fillMaxSize())
            } else {
                Text("버튼 클릭")
            }
        }
    }
}

3단계: 애니메이션이 적용된 버튼 만들기

버튼 클릭 시 애니메이션 효과를 적용해보자.



@Composable
fun AnimatedButton() {
    val scale = remember { mutableStateOf(1f) }
    val animatedScale = animateFloatAsState(targetValue = scale.value)

    Button(
        onClick = { scale.value = if (scale.value == 1f) 1.1f else 1f },
        modifier = Modifier.size((50 * animatedScale.value).dp)
    ) {
        Text("애니메이션 버튼")
    }
}

다음 시간 예고

다음 시간에는 Icon과 Image를 다루어볼 거야. 오늘 배운 버튼과 함께 사용하면 더욱 멋진 UI를 만들 수 있어!


Photo by Denny Müller on Unsplash```

관련 글