SwiftUI/SwiftUI(Basic)

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

Toughie 2023. 4. 24. 20:17

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.광고 표시용

 

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