Sheet는 기본 콘텐츠 위에 화면 하단에 나타나 추가 작업이나 정보를 제공하는 UI 구성 요소입니다. Bottom Sheet는 가장 일반적인 유형으로, Material Design 3 (Google, 2024)의 가이드라인에 정의되어 있습니다. 대화상자와 달리 Sheet는 배경과의 상호 작용을 완전히 차단하지 않으며 collapsed 및 expanded 상태를 지원합니다. 모바일 애플리케이션에서 편리한 내비게이션을 구축하려면 Sheet의 유형과 동작을 이해하는 것이 필요합니다.
핵심 포인트
Sheet는 화면 하단에서 슬라이드 업되어 현재 화면에서 사용자를 이동시키지 않고 추가 콘텐츠나 작업을 표시하는 표면 수준의 UI 구성 요소입니다. 전체 화면 전환과 달리 Sheet는 컨텍스트를 유지합니다. 사용자는 배경 화면을 볼 수 있으며 Sheet가 어디서 나타났는지 이해할 수 있습니다.
Sheet의 아키텍처는 높이 조절 가능한 컨테이너를 기반으로 합니다. 최소 상태(collapsed)에서는 콘텐츠의 일부만 표시되며, 일반적으로 제목이나 작은 패널만 보입니다. 사용자는 Sheet를 위로 드래그하여 확장(expanded)하거나 아래로 스와이프하여 닫을 수 있습니다. 이 동작은 물리적인 종이 시트를 더미 아래에서 빼내는 것과 유사하여 이름이 붙여졌습니다.
Google은 Material Design 3 가이드라인(2024)에서 Sheet 사용의 두 가지 주요 시나리오를 강조합니다. 기본 도구 모음에 맞지 않는 추가 작업 표시, 그리고 별도 화면으로 이동하지 않고 양식이나 상세 정보 표시입니다. iOS에서는 Apple이 iOS 15부터 UISheetPresentationController를 통해 시스템 수준의 Sheet 지원을 추가하여 패턴의 보편성을 입증했습니다.
Material Design은 각각 고유한 동작과 적용 영역을 가진 세 가지 유형의 Bottom Sheet를 정의합니다. 올바른 유형을 선택하는 것은 사용자 경험과 플랫폼 가이드라인 준수에 직접적인 영향을 미칩니다.
표준 Bottom Sheet는 비모달 구성 요소입니다. 사용자는 Sheet를 닫지 않고 배경 화면과 상호 작용할 수 있습니다. 예를 들어, 백그라운드에서 제품 목록을 탐색하는 동안 사용자는 Bottom Sheet에 필터를 보고 패널을 닫지 않고 변경할 수 있습니다. Sheet는 콘텐츠에 따라 높이를 조정합니다(화면의 30% ~ 90%).
표준 Bottom Sheet는 배경을 차단하지 않으며 기본 콘텐츠와의 상호 작용을 허용합니다. 이것이 모달 Sheet와의 주요 차이점이며, 모달 Sheet는 계속하기 위해 필수 작업이 필요합니다. 추가 정보가 주요 시나리오에 중요하지 않은 경우 표준 Sheet를 사용하세요.
모달 Bottom Sheet는 사용자가 Sheet 내에서 작업을 수행할 때까지 배경 화면과의 상호 작용을 차단합니다. 이러한 Sheet는 항상 확장된 상태로 표시되며 명시적으로 닫아야 합니다(버튼, 작업 또는 아래로 스와이프). Material Design은 로그인 양식, 확인 대화상자 및 중요한 설정에 모달 Sheet를 권장합니다.
Android에서 모달 Bottom Sheet는 BottomSheetDialogFragment를 통해 구현되며 자동으로 배경을 차단합니다. iOS에서는 .mediumDetent 매개변수가 있는 UISheetPresentationController의 모달 변형이 유사한 동작을 제공합니다. 모달 Sheet는 컨텍스트가 사용자의 주의를 필요로 하는 경우에만 사용해야 합니다.
확장형 Bottom Sheet는 표준과 모달의 특성을 결합합니다. collapsed 상태에서는 비모달로 시작하지만 위로 드래그하면 모달이 됩니다. 실제로 사용자는 먼저 콘텐츠를 간략히 살펴본 다음 Sheet를 확장하여 자세히 살펴보거나 닫을지 결정할 수 있습니다.
이 패턴은 특히 지도 및 내비게이션 앱에서 인기가 있습니다. 하단 패널에 경로 지점에 대한 간략한 정보가 표시되고 위로 스와이프하면 세부 정보와 함께 확장됩니다. Google Maps는 장소 및 경로에 대한 정보를 표시하기 위해 정확히 이 확장형 Sheet를 사용합니다.
| Sheet 유형 | 배경 차단 | 초기 상태 | 예시 |
|---|---|---|---|
| 표준 | 아니요 | Collapsed | 카탈로그 필터 |
| 모달 | 예 | Expanded | 로그인 양식 |
| 확장형 | 부분적 | Collapsed | 장소 카드 |
Android SDK는 클래식 View 기반 접근 방식부터 최신 Jetpack Compose까지 Bottom Sheet를 구현하기 위한 여러 API를 제공합니다. Android용 Material Components 라이브러리에는 BottomSheetDialogFragment 및 BottomSheetBehavior의 기성 구현이 포함되어 있습니다.
BottomSheetBehavior는 모든 View에 연결되어 화면에서 위치를 제어하는 Material Components의 클래스입니다. 개발자는 STATE_COLLAPSED, STATE_EXPANDED 및 STATE_HIDDEN의 세 가지 상태를 설정합니다. Behavior는 드래그 제스처와 애니메이션을 자동으로 처리합니다.
val sheet = findViewById<View>(R.id.bottom_sheet)
val behavior = BottomSheetBehavior.from(sheet)
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
behavior.peekHeight = 200
Jetpack Compose는 Material 3의 ModalBottomSheet 구성 요소를 통해 더 선언적인 API를 제공합니다. View 기반 접근 방식과 달리 Compose에서 Bottom Sheet는 상태와 콘텐츠를 받는 컴포저블 함수입니다. Sheet는 드래그 시 나타나기, 숨기기 및 높이 변경을 자동으로 애니메이션화합니다.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FilterSheet(onDismiss: () -> Unit) {
ModalBottomSheet(onDismissRequest = onDismiss) {
Text("필터")
Button(onClick = onDismiss) { Text("적용") }
}
}
BottomSheetDialogFragment는 Bottom Sheet로 표시되는 특수 DialogFragment입니다. 모달성, 수명 주기 및 구성 변경을 자동으로 처리합니다. 개발자는 onCreateView를 재정의하고 Sheet 레이아웃을 반환하기만 하면 됩니다. Google 문서(Android Developers, 2024)에 따르면 BottomSheetDialogFragment는 클래식 Android에서 모달 Bottom Sheet에 권장되는 방법입니다.
Apple은 iOS 15부터 UISheetPresentationController를 통해 시스템 수준의 Sheet 지원을 도입했습니다. 이전에는 개발자가 사용자 지정 전환 또는 타사 라이브러리를 통해 수동으로 Bottom Sheet를 구현했습니다. Apple의 네이티브 Sheet는 사전 정의된 확장 수준인 detents를 지원합니다.
UISheetPresentationController는 View Controller를 Sheet로 표시하는 내장 프레젠테이션 컨트롤러입니다. 개발자는 Sheet가 멈출 수 있는 높이 값인 detents 배열을 지정합니다. iOS 16은 사용자 지정 높이의 커스텀 detents를 추가했습니다. Apple은 기본 detents로 medium(.medium)과 large(.large)를 사용할 것을 권장합니다.
let viewController = MySheetViewController()
if let sheet = viewController.sheetPresentationController {
sheet.detents = [.medium, .large]
sheet.prefersGrabberVisible = true
sheet.preferredCornerRadius = 16
}
present(viewController, animated: true)
SwiftUI는 Sheet 표시를 상태에 바인딩하는 .sheet 수정자를 제공합니다. published 변수가 true가 되면 SwiftUI가 자동으로 Sheet를 표시합니다. SwiftUI는 iOS 16에 추가된 .presentationDetents 수정자를 통해 detents도 지원합니다.
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Button("시트 표시") { showSheet = true }
.sheet(isPresented: $showSheet) {
FilterView()
.presentationDetents([.medium, .large])
}
}
}
크로스 플랫폼 프레임워크도 Bottom Sheet를 지원하며 대상 플랫폼에 따라 동작을 조정합니다. Flutter와 React Native는 다양한 유연성 수준의 내장 및 사용자 지정 구현을 제공합니다.
Flutter SDK에는 Bottom Sheet를 표시하는 두 가지 메서드가 있습니다. showBottomSheet(표준)와 showModalBottomSheet(모달)입니다. Flutter의 Material Design은 Android와 동일한 원칙을 따릅니다. Sheet는 하단에서 나타나고 드래그를 지원하며 높이를 조절할 수 있습니다. detents를 사용한 확장 동작에는 DraggableScrollableSheet가 사용됩니다.
Scaffold.of(context).showBottomSheet((context) {
return Container(
padding: EdgeInsets.all(16),
child: Column(
children: [
Text("시트 콘텐츠"),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("닫기")
)
]
)
);
})
React Native의 코어에는 내장 Bottom Sheet 구성 요소가 없으므로 개발자는 타사 라이브러리를 사용합니다. 가장 인기 있는 것은 @gorhom/bottom-sheet입니다(GitHub에서 7,000개 이상의 스타, 2024). 스냅 포인트, 애니메이션 및 고정 헤더를 지원하는 제스처 기반 Bottom Sheet를 제공합니다. 이 라이브러리는 60FPS 성능을 위해 Reanimated 2 및 Gesture Handler 위에 구축되었습니다.
Bottom Sheet의 올바른 사용은 플랫폼 가이드라인을 준수하고 Sheet가 적합한 시나리오를 이해해야 합니다. Sheet를 설계할 때 주요 권장 사항과 일반적인 실수를 살펴보겠습니다.
Bottom Sheet는 화면의 기본 콘텐츠에 대한 보충 작업에 최적입니다. 필터, 정렬, 옵션 선택, 항목에 대한 간략한 정보 등이 일반적인 시나리오입니다. Material Design은 전체 화면을 차지하지 않아야 하지만 Action Sheet나 팝업 메뉴보다 더 많은 공간이 필요한 도구에 Bottom Sheet 사용을 권장합니다.
중요한 경고나 오류에 Bottom Sheet를 사용하지 마세요. 대화상자가 더 적합합니다. 스크롤이 필요한 많은 입력 필드가 있는 Sheet는 피하세요. 사용자가 키보드에 도달하는 데 어려움을 겪고 컨텍스트를 잃습니다. Sheet에 7개 이상의 작업 항목이 포함된 경우 Sheet 대신 별도 화면을 고려하세요.
일반적인 실수는 peekHeight(접힌 상태의 높이)를 화면의 40% 이상으로 설정하는 것입니다. 사용자는 Sheet를 완전히 보고 있는지 아니면 확장할 수 있는지 알 수 없습니다. Material Design은 콘텐츠의 눈에 띄는 부분을 숨겨 드래그를 유도하기 위해 peekHeight를 화면 높이의 15-30% 이내로 권장합니다.
iOS에서 사용자는 모든 위치에서 아래로 스와이프하여 Sheet를 닫을 수 있을 것으로 기대합니다. 이 제스처를 비활성화하면(UISheetPresentationController.prefersEdgeAttachedInCompactHeight를 통해) 사용자는 익숙한 방식으로 Sheet를 닫으려고 시도할 때 좌절감을 느낍니다. Apple Human Interface Guidelines(2024)은 스와이프하여 닫기가 iOS 사용자의 기본 기대치임을 강조합니다.
자주 묻는 질문
Bottom Sheet는 배경을 완전히 차단하지 않고 드래그를 지원하는 반면, 대화상자는 모달이며 필수 작업이 필요합니다. Bottom Sheet는 보충 옵션에 더 적합하고 대화상자는 중요한 확인에 적합합니다.
네, 하지만 Android 매니페스트에서 adjustResize 또는 adjustPan 설정이 필요합니다. iOS에서는 키보드가 자동으로 Sheet를 들어 올립니다. Flutter와 React Native는 올바른 위치 지정을 위해 MediaQuery를 통한 수동 처리가 필요합니다.
권장되는 표준 Sheet의 항목 수는 5-7개를 초과하지 않는 것입니다. 더 많은 콘텐츠가 있는 경우 스크롤 또는 카테고리 분할을 사용하세요. Material Design은 확장 상태에서 화면 높이의 90%를 초과하지 않도록 조언합니다.
모달 Sheet의 경우, Android에서는 setCancelable(true)를, iOS에서는 isModalInPresentation = false를 설정합니다. Jetpack Compose에서는 onDismissRequest가 배경 탭을 자동으로 처리합니다. SwiftUI에서는 아래로 스와이프가 기본 동작입니다.
네, 모든 네이티브 구현이 VoiceOver와 TalkBack을 지원합니다. FocusManager가 Sheet를 열 때 포커스를 Sheet로 올바르게 이동하고 닫을 때 복원하는지 확인하세요. 사용자 지정 구현은 수동 접근성 구성이 필요합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.