개발/Swift

SwiftUI 커스텀 팝업 노출 방법 fullScreenCover

덤벨로퍼 2025. 3. 25. 17:15
반응형

 

https://inf.run/iDaq4

 

SwiftUI + TCA: 실전 프로젝트로 완성하는 차세대 iOS 아키텍처 강의 | 덤벨로퍼 - 인프런

덤벨로퍼 | 복잡한 SwiftUI 상태 관리, TCA (The Composable Architecture)로 깔끔하고 견고한 앱을 만드세요. 실전 프로젝트 예제로 핵심만 빠르게 배웁니다. , SwiftUI + TCA: 실전 프로젝트로 완성하는 차세대

www.inflearn.com

 

SwiftUI에서 부모 뷰 위에 반투명한 커스텀 팝업 UI를 띄우는 방법은 다음과 같습니다.

커스텀 팝업 view 구조

ZStack {
	Color.black.opacity(0.5)
	팝업 뷰
}
팝업 뷰 구조: 팝업은 부모 뷰를 덮는 형태이지만 반투명한 UI여야 합니다. 이를 위해 ZStack 내부에 Color.black.opacity(0.5)와 같은 반투명 색상 레이어를 먼저 배치하고 그 위에 실제 팝업 뷰 내용을 추가하는 방식으로 구성할 수 있습니다.
 


팝업을 띄우는 방법 (부모 뷰 에서)

팝업 띄우는 방법: fullScreenCover를 사용하며, 백그라운드를 투명하게 만들기 위해 UIViewRepresentable을 함께 활용합니다.

 

 

fullScreenCover + UIViewRepresent

struct ClearBackgroundRepresentable: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        return InnerView()
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
    }
    
    private class InnerView: UIView {
        override func didMoveToWindow() {
            super.didMoveToWindow()
            
            superview?.superview?.backgroundColor = .clear
        }
        
    }
}

    ◦ ClearBackgroundRepresentable과 같은 UIViewRepresentable을 만들고, makeUIView 메서드에서 InnerView를 반환합니다.

    ◦ InnerView didMoveToWindow() 메서드 내에서 superview?.superview?.backgroundColor = .clear 코드를 통해 UIKit을 사용하여 백그라운드를 투명하게 변경합니다.

 

백그라운드를 UIKit에서 Clear하게 바꿔서사용 → 성공

 

.fullScreenCover(isPresented: $store.showRestrictPopup.sending(\\.commentInput.showRestrictPopup)) {
                CommunityRestrictedUserPopup(dismiss: { store.send(.commentInput(.showRestrictPopup(false))) },
                                             onTapGuide: { store.send(.commentInput(.tapCommnunityGuide)) },
                                             restrictPeriod: store.profile.restrictPeriod)
            }

부모 뷰에서는 fullScreenCover를 일반적인 방식으로 호출합니다.

 

 

ZStack {
 Color(.Transparency_TD054)
  .ignoresSafeArea(.all)
                    
  팝업 내용...
                    
}
 .background(ClearBackgroundView())

(자식) 뷰의 ZStack .background(Color(.Transparency_TD054)) (혹은 다른 투명 색상)를 ignoresSafeArea(.all)와 함께 적용하고, 추가적으로 **.background(ClearBackgroundView())**를 사용하여 백그라운드를 투명하게 만듭니다. 

.background(.clear)해도 안되었던 문제가 해결됨

 

 

애니메이션 비활성화

fullScreenCover 특성상 아래에서 위로 올라오는 애니메이션이 적용이됨

애니메이션 끄려면 이런 방식들이 있음 얘네들을 부모뷰에 적용시켜두면 애니메이션이 안먹음

.onAppear {
	UIView.setAnimationsEnabled(false)
}

.transaction { $0.disablesAnimations = true }
주의사항: 이러한 방식들은 해당 뷰뿐만 아니라 다른 페이지 진입 시의 애니메이션까지도 함께 비활성화할 수 있습니다. 따라서 이 애니메이션 비활성화 코드는 특정 조건에서만 적용되도록 구현하는 것이 중요합니다.
 
 

실패했던 기록들

background

  .background(content: {
      if store.showRestrictPopup {
          CommunityRestrictedUserPopup(dismiss: { store.send(.commentInput(.showRestrictPopup(false))) },
                                       onTapGuide: { store.send(.commentInput(.tapCommnunityGuide)) },
                                       restrictPeriod: store.profile.restrictPeriod)
      }
  })

이상하게 뜸 뭔가 부모뷰에 팝업이 합쳐진것처럼 노출됨-> 실패

fullScreenCover

  .fullScreenCover(isPresented: $store.showRestrictPopup.sending(\\.commentInput.showRestrictPopup)) {
      CommunityRestrictedUserPopup(dismiss: { store.send(.commentInput(.showRestrictPopup(false))) },
                                   onTapGuide: { store.send(.commentInput(.tapCommnunityGuide)) },
                                   restrictPeriod: store.profile.restrictPeriod)
  }

팝업 배경이 전체 영역을 모두 다 덮어서 부모뷰를 모두 가려버림, 해당 팝업 배경을 Clear 배경을 줘도 같았음

overlay

.overlay(content: {
      if store.showRestrictPopup {
          CommunityRestrictedUserPopup(dismiss: { store.send(.commentInput(.showRestrictPopup(false))) },
                                       onTapGuide: { store.send(.commentInput(.tapCommnunityGuide)) },
                                       restrictPeriod: store.profile.restrictPeriod)
      }
  })

그나마 노출 되고 웹뷰도 잘 뜨지만 문제는 네비게이션 영역을 차지하지 못해

팝업 배경은 어두운색이지만 네비게이션 영역만 흰색 임

부모 뷰에서 네비게이션 영역은 toolbar 사용중임

  .navigationBarBackButtonHidden(true)
  .toolbar { navigationBarToolbar }

  1. 팝업에서 .ignoresSafeArea(.all) 사용해도 해결 안됨
    • ZStack, ZStack 내부 둘다 안됨
  2. overlay 자체를 부모뷰 toolbar 덮어씌는 위치에서 사용
ZStack {
	부모뷰
	.toolbar {}
}
.overlay {}

→ 실패

  1. .frame(maxWidth: .infinity, maxHeight: .infinity)

→ 실패

  1. .navigationBarTitleDisplayMode(.inline) → 실패
  2. Zstack 내부에 사용
ZStack {
	부모뷰
	.toolbar {}
	팝업
}

→ 실패

→ 포기

4.popover

 .popover(isPresented: $store.showRestrictPopup.sending(\\.commentInput.showRestrictPopup) {
                        CommunityRestrictedUserPopup(dismiss: { store.send(.commentInput(.showRestrictPopup(false))) },
                                                     onTapGuide: { store.send(.commentInput(.tapCommnunityGuide)) },
                                                     restrictPeriod: store.profile.restrictPeriod)

→ fullScreen과 같이 부모뷰를 덮음 → 실패

 

 

 

반응형