OverView
Compose Dialog 를 통해 커스텀 및 Control에 있어 내용을 정리 해봅니다.
Dialog
- 주요 목적 : 사용자가 현재 화면과 상호작용을 차단하고 특정 작업이나 정보를 표시
- 특장점
- Compose의 선언형 UI와 완벽히 통합
- Compose 기반의 선언형 스타일을 사용해 Dialog 콘텐츠를 정의할 수 있습니다.
- XML 없이 코드만으로 UI를 빠르고 효율적으로 구성 가능.
- 높은 유연성과 커스터마이징
- Dialog의 크기, 색상, 스타일 등 모든 부분을 쉽게 커스터마이즈 가능.
- 기본 제공 스타일 외에도 Modifier를 활용해 완전히 맞춤형 Dialog 구현 가능.
- 시스템 UI와 자연스럽게 통합
- Android의 시스템 Window에 의해 관리되어, Dialog가 항상 최상위에 그려짐.
- DialogProperties를 통해 백 버튼, 외부 클릭, 키보드와 같은 시스템 동작을 세부적으로 제어 가능.
- 전환과 애니메이션 제어
- 애니메이션 API와 결합하여 등장/퇴장 시 애니메이션을 쉽게 추가 가능.
- 투명도, 크기, 위치 등을 사용자 정의할 수 있어 다채로운 UI를 구현 가능.
- Compose 생명주기 관리
- Compose 상태 관리와 직접 통합되어, Dialog 상태를 쉽게 관리 가능.
- remember, state와 함께 사용하여 가시성, 데이터 변경 등을 효율적으로 처리
- Compose의 선언형 UI와 완벽히 통합
기본구조
@Composable
fun Dialog(
onDismissRequest: () -> Unit,
properties: DialogProperties,
content: @Composable () -> Unit
) { ... }
// DialogProperties 정리
DialogProperties(
dismissOnBackPress = false, // 뒤로가기 버튼으로 닫을 수 없음
dismissOnClickOutside = false, // 외부 클릭으로 닫을 수 없음
usePlatformDefaultWidth = false, // 너비가 콘텐츠에 맞게 설정됨
decorFitsSystemWindows = false, // 시스템 윈도우와 독립적으로 배치
securePolicy = SecureFlagPolicy.SecureOn, // 스크린샷 방지 활성화
enableImeInsets = true // 키보드가 나타날 때 Dialog 위치 조정
)
- onDismissRequest : 닫기 콜백
- properties : 사용자 인터렉션 제어(뒤로가기, 외부클릭), 화면크기 설정, 시스템 제어(스크린샷 방지, 키보드 insets 처리)등의 기능 제공
고려 사항
- 여러 Dialog 중첩 시 상태관리와 중첩 우선순위 명확 필요
- 내장 애니메이션 부족
- 애니메이션이 필요하다면 직접 구현 필요
애니메이션 구현
- 등장/퇴장 시 Compose Animation API를 사용한다. 또한 DialogWindowProvider를 활용하여
Dialog의 Window를 통해 추가적인 설정 (예: 배경 흐림, 시스템 창 속성)을 조정 - Compose Animation 사용
- 상태 기반
- animationFloatAsState 또는 animationDpAsState
- Modifier의 alpha, scale, offset 등을 조정
-
// 예 val alpha by animateFloatAsState( targetValue = if (isVisible) 1f else 0f, // 투명도 상태 animationSpec = tween(durationMillis = 300) // 애니메이션 지속 시간 ) Dialog( ) { Box( modifer = Modifier.alpha(alpha) ) { } }
- Transition API
- Transition을 사용해 복합 애니메이션 관리
-
// 예 val transition = updateTransition(targetState = isVisible, label = "DialogTransition") val alpha by transition.animateFloat( label = "AlphaAnimation" ) { visible -> if (visible) 1f else 0f } val scale by transition.animateFloat( label = "ScaleAnimation" ) { visible -> if (visible) 1f else 0.8f } // 크기가 80%에서 시작 if (isVisible || alpha > 0f) { Dialog(onDismissRequest = onDismissRequest) { Surface( modifier = Modifier .alpha(alpha) // 투명도 .scale(scale), // 크기 ) { Box( modifier = Modifier .padding(24.dp) .size(200.dp), contentAlignment = Alignment.Center ) { Text("Dialog") } } } }
- 상태 기반
- DialogWindowProvider 사용
- Dialog는 내부적으로 Android Window를 사용
- DialogWindowProvider를 활용하면 Dialog 의 Window 객체에 접근하여 다양한 설정 직접 조정 가능
- setDimAmount(float): Dialog 배경 흐림 정도 설정.
- addFlags(int): WindowManager 플래그 추가 (예: 스크린샷 방지).
- setBackgroundDrawable(Drawable): 배경을 변경.
- setSoftInputMode(int): 키보드 동작 방식 제어.
- attributes: WindowManager.LayoutParams를 통해 크기, 위치, 애니메이션 등 세부 설정.
- setWindowAnimation: Dialog의 등장 및 퇴장 시 실행되는 Window 애니메이션을 설정. res/anim 또는 res/animator 디렉토리에 XML 파일로 정의된 리소스ID를 가지고 사용. 0일 경우 애니메이션 제거
-
// 예 val dialogWindow = LocalView.current.parent as? DialogWindowProvider val window = dialogWindow?.window // Dialog의 생명주기 의존적인 작업을 설정하고 정리하기 위해 사용 DisposableEffect(Unit) { val previousDimAmount = window?.attributes?.dimAmount window?.setDimAmount(0.5f) // 배경 흐림 설정 onDispose { window?.setDimAmount(previousDimAmount ?: 1f) // 초기 상태 복원 } } // 또는 window?.apply { setDimAmount(0.7f) // 배경 흐림 정도 조정 setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) setWindowAnimations(R.style.DialogAnimation) // 애니메이션 스타일 설정 } // SOFT_INPUT_ADJUST_RESIZE 등을 설정해 자연스러운 애니메이션과 입력처리 지원 가능
반응형