Kotlin Multiplatform Compose UI 개선 작업

gay0ung·2025년 7월 24일
0

Android

목록 보기
10/14
post-thumbnail

최근에 KMP 프로젝트에서 UI/UX 개선 작업을 진행했는데, 생각보다 까다로운 부분들이 많았다. 특히 iOS와 안드로이드의 차이점을 처리하는 게 제일 골치 아팠음. 그래도 하나씩 해결하면서 많이 배웠으니 정리해보려고 함.

1. iOS 홈 인디케이터와 바텀바 색상 통일

문제 상황

iOS에서 홈 인디케이터(━)와 앱 바텀바가 다른 색상으로 나와서 UI가 분리되어 보였다. 게다가 바텀바 높이도 너무 커서 공간 낭비가 심했음.

해결 과정

먼저 iOS Safe Area 처리부터 손봤다.

// MainViewController.kt - iOS Safe Area 처리
fun MainViewController() = ComposeUIViewController {
    App(modifier = Modifier
        .fillMaxSize()
        .imePadding() // 키보드 패딩 처리
    )
}

그다음 바텀바 설정을 개선했다.

// App.kt - 바텀바 설정
NavigationBar(
    containerColor = MaterialTheme.colorScheme.surface, // 상단바와 동일한 색상
    modifier = Modifier.height(56.dp) // 높이 축소
) {
    // NavigationBarItems...
}

핵심 포인트

  • .imePadding(): 키보드가 올라올 때 UI가 가려지지 않도록 자동으로 패딩을 조정해줌
  • 색상 통일: 상단바와 바텀바 모두 MaterialTheme.colorScheme.surface 사용
  • 높이 최적화: 56dp로 컴팩트하게 조정해서 공간 효율성 높임

2. 알림 다이얼로그 UX 개선

문제 상황

통화 선택할 때 FilterChip들이 가로로 쭉 나열되어서 공간을 너무 많이 차지했다. 통화 옵션이 많을 때는 UI가 복잡해져서 사용성이 떨어졌음.

기존 방식

// 기존: FilterChip 방식
Row {
    currencies.forEach { currency ->
        FilterChip(
            selected = selectedCurrency == currency,
            onClick = { selectedCurrency = currency },
            label = { Text(currency) }
        )
    }
}

개선된 방식

// 개선: 드롭다운 방식
ExposedDropdownMenuBox(
    expanded = expandedCurrency,
    onExpandedChange = { expandedCurrency = !expandedCurrency }
) {
    OutlinedTextField(
        value = selectedCurrency,
        readOnly = true,
        trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expandedCurrency) },
        modifier = Modifier.menuAnchor().fillMaxWidth()
    )
    ExposedDropdownMenu(
        expanded = expandedCurrency,
        onDismissRequest = { expandedCurrency = false }
    ) {
        currencies.forEach { currency ->
            DropdownMenuItem(
                text = { Text(currency) },
                onClick = {
                    selectedCurrency = currency
                    expandedCurrency = false
                }
            )
        }
    }
}

개선 효과

  • 노션 스타일 토글: 클릭하면 옵션이 드롭다운으로 펼쳐짐
  • 공간 효율성: 한 줄로 압축된 UI로 깔끔해짐
  • 선택적 적용: 통화 선택만 드롭다운으로, 알림 조건은 FilterChip 유지

3. 안드로이드 Edge-to-Edge 대응

문제 상황

안드로이드에서 enableEdgeToEdge()를 사용하면서 콘텐츠가 시스템 바 영역까지 확장되어 바텀바가 콘텐츠를 가리는 현상이 발생했다. 특히 API 35+ 에서는 edge-to-edge가 강제 정책이라 더 신경써야 했음.

// MainActivity.kt
enableEdgeToEdge() // 콘텐츠가 시스템 바 영역까지 확장

해결 방법

Scaffold(
    modifier = modifier
        .fillMaxSize()
        .systemBarsPadding(), // 시스템 바 영역 자동 패딩
    topBar = { /* ... */ },
    bottomBar = { /* ... */ }
) { paddingValues ->
    // 콘텐츠 영역
}

동작 원리

  • systemBarsPadding(): 상태바와 네비게이션바 높이를 자동으로 감지해서 패딩 적용
  • 크로스 플랫폼: 안드로이드에서는 시스템 인셋 처리, iOS에서는 Safe Area 처리
  • 미래 대응: Android API 35+ edge-to-edge 정책과도 완벽하게 호환됨

주요 학습 포인트

KMP UI 패딩 전략

// iOS - MainViewController
.imePadding() // 키보드 대응

// 공통 - Scaffold  
.systemBarsPadding() // 시스템 바 대응

Material Design 3 컴포넌트 활용

  • ExposedDropdownMenuBox: 드롭다운 UI 구현할 때 최고
  • FilterChip: 토글 방식 선택 UI에 적합
  • 적절한 선택: 용도에 맞는 컴포넌트 조합이 중요함

Edge-to-Edge 대응 패턴

// MainActivity
enableEdgeToEdge()

// Compose
Scaffold(modifier = Modifier.systemBarsPadding())

마무리

이번 개선 작업을 통해 iOS와 안드로이드 모두에서 일관되고 현대적인 UI/UX를 제공할 수 있게 되었다. 특히 시스템 바 처리와 컴포넌트 선택에 있어서 많이 배웠음. KMP에서 UI 작업할 때는 플랫폼별 특성을 잘 이해하고 적절한 Modifier를 사용하는 게 핵심인 것 같다.

앞으로도 이런 세부적인 UX 개선에 더 신경써야겠음!

0개의 댓글