본문 바로가기
Android

[Android] Compose Dialog 사용

by 중곰 2024. 11. 18.

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와 함께 사용하여 가시성, 데이터 변경 등을 효율적으로 처리

기본구조

@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 등을 설정해 자연스러운 애니메이션과 입력처리 지원 가능
반응형