Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
SwiftUI/SwiftUI(Basic)

26. [SwiftUI] 모달 .sheet() & fullscreenCover(), @Environment

by Toughie 2023. 4. 24.

sheet

SwiftUI에서 sheet은 UIKit에서 modal과 유사하게 모달뷰를 표시하는데 사용한다.

유저가 모달뷰를 닫기 전까지 기존 뷰를 덮고, 새로운 뷰를 표시한다.

바인딩 변수를 전달해야 하고, content 클로저에서 조건문을 사용하면 안 되는 점을 주의하자.

 

why? 

*시트를 통한 뷰는 부모뷰가 생성될 때 같이 생성된다.

먼저 코드의 가독성과 유지보수성 측면에서 단점이 있다.

sheet content 클로저 내부에서 조건문을 사용해 다양한 뷰를 표시하려면 코드가 복잡해지고,

중복되는 코드가 발생할 가능성이 있으며 이는 가독성과 유지보수를 어렵게 만든다.

-> 각 뷰를 별도의 변수로 추출해서 뷰의 계층 구조를 간결하게 유지하는 방향이 좋다.

다양한 뷰를 띄우는 방식은 다음에 더 자세히 알아보도록 하자.

 

또한 sheet는 뷰당 한 번만 사용 가능하다. 

.sheet(...)

.sheet(...)과 같은 형태는 불가능하다는 의미. (.fullScreenCover도 마찬가지)

 

또한 모달뷰는 드래그 제스쳐를 통해(아래로 내리는 동작) 사라지게(dismiss)할 수 있는데 (fullScreenCover는 불가능)

이를 위해서는 프로퍼티 래퍼중 하나인 @Environment를 알아야 한다.

 

@Environment

Swift에서 property wrapper는 특별한 기능을 제공하도록 구현된 구조체나 클래스이다.

다른 속성을 래핑하고, 그 속성에 '추가적인 기능을 부여'한다. 

@Environment는 뷰 계층 구조 (View Hierarchy)에서 환경 값을 캡슐화하는 데 사용된다.

이는 뷰 계층 구조에서 공유되는 값을 저장하고 전달하는데 유용하며, 이를 통해서
뷰 계층 구조에서 일관성 있는 동작을 보장하고 뷰 간의 결합도를 낮출 수도 있다.

 

예시를 통해 sheet, fullscreencover, @Environment에 대해 알아보자.

//  Created by Toughie on 2023/04/24.
//

import SwiftUI

struct Sheets: View {
    //sheet의 바인딩 파라미터에 전달할 @State 변수
    @State var showSheet: Bool = false
    
    var body: some View {
        ZStack {
            Color.blue.opacity(0.5)
                .ignoresSafeArea()
            
            Button {
            //버튼을 통해 토글
                showSheet.toggle()
            } label: {
                Text("Button")
                    .foregroundColor(.blue)
                    .font(.headline)
                    .padding(20)
                    .background(Color.white.cornerRadius(10))
            }
            //뷰당 한 번만 사용 가능 (.sheet()여러번 불가능!)
            //클로저 안에서 조건문 사용 금지(지양)
            //분기 처리를 통해 여러 뷰를 띄우려고 하면 안 됨.(다른 방법이 있음)
            //시트는 속해있는 뷰가 생성될 때 같이 생성되기 때문에
            .sheet(isPresented: $showSheet) {
                SecondView()
            }
            //fullScreenCover도 sheet와 거의 동일. 다만 제스쳐를 통한 dismiss 불가
//            .fullScreenCover(isPresented: $showSheet) {
//                SecondView()
//            }
        }
    }
}

struct SecondView: View {
    //to dismiss sheet
    /*
    시트를 사라지게 하기 위해 필요
    자동완성이 안 되기 때문에 암기하는 것이 좋음.
    변수명은 다르게 지을 수도 있음.
    */
    @Environment(\.presentationMode) var presentationMode
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            Color.green.opacity(0.5)
                .ignoresSafeArea()
            
            Button {
            //뷰 계층 구조에서 정의된 환경 변수에 접근하기 .dissmiss() 호출
                presentationMode.wrappedValue.dismiss()
            } label: {
                Image(systemName: "xmark")
                    .foregroundColor(.green)
                    .font(.headline)
                    .padding(10)
                    .background(Color.white.cornerRadius(10))
                    .padding(20)
            }
        }
    }
}

 

fullScreenCover는 위에서 언급했듯이 sheet와 거의 유사하지만 

화면을 꽉 채우고, 제스처를 통한 dismiss가 불가능하다는 차이가 있다.

(새로운 뷰를 띄운다는 점은 동일하다.)

 

+ 모달뷰에 관해서

-모달뷰는 언제 사용하면 좋은가?

시트(모달)는 아래와 같은 상황에서 사용될 수 있다.

 

1. 추가적인 정보를 요구하는 경우

- 유저에게 선택 사항이나 추가 정보를 제공할 때 (어떤 작업 수행 중에 추가 정보가 필요한 경우 모달 뷰를 통해 추가 정보 제공 가능)

 

2. 액션 수행 전 경고 표시용

- 중요한 작업 시작 전에 경고가 필요한 경우

 

3. 피드백 제공

- 작업이 완료되었다는 피드백, 실패했을 경우 실패한 이유를 알릴 때(알럿도 자주 쓰임)

 

4. 작업 용도(완료용)

- 새로운 항목을 추가하거나 설정을 변경하거나 다른 사용자와 공유하기 위한 콘텐츠 생성 등의 작업 수행 시 사용 가능

 

5.광고 표시용

 

모달뷰는 일시적인 뷰이고, 사용자는 모달뷰를 닫을 수 있기 때문에(제스처를 통해) 해당 특징을 잘 파악해서 사용하는 것이 중요하겠다.