SwiftUI

SwiftUI Binding, Environment

Daesiker 2021. 3. 31. 18:03
반응형

개요

swiftUI에서 자신의 뷰에서의 상태값을 저장할 때는 @State 키워드를 사용한다. 하지만 이 상태값을 자신의 하위 뷰에도 적용시킬 때가 분명히 필요하다 이럴 때 사용하는 것이 바로 @Binding 키워드이다.

그리고 모든 View에는 환경 기본값이 존재한다. 사용하기 전에 따로 설정을 하지 않아도 기본적으로 설정되어있는데 이 값을 바꾸고 싶을 때는 @Environment 키워드를 사용하여 변경이 가능하다.

 


시작하기

@Binding 키워드를 통해서 다크모드를 사용할 수 있는 Boolean 변수를 다른 View와 공유를 하고 @Environment 키워드를 통해서 현재 View의 presentationMode의 값을 변경해서 현재 열려있는 View를 종료할 수 있게 도와주는 변수를 만들 예정이다.

 

Code

ContentView

우선 버튼과 이미지가 Stack으로 쌓여있는 ContentView를 먼저 만들것이다.

TimeOfDayImage

struct TimeOfDayImage: View {
    var imageTitle: String
    
    var body: some View {
        Image(systemName: imageTitle)
            .resizable()
            .renderingMode(.original)
            .aspectRatio(contentMode: .fit)
            .frame(width: 180, height: 180)
    }
}

imageTitle 파라미터에 String 값을 받아서 해당 String값과 같은 systemImage를 Image 컴포넌트로 만들어 주는 View이다. aspectRatio 속성을 사용하여 해당 프레임에 맞게 이미지의 크기를 조절해준다.

 

ButtonLabel

struct ButtonLabel: View {
    var title: String
    var imageName: String
    var color: Color
    
    var body: some View {
        Label(title, systemImage: imageName)
            .frame(width: 280, height: 50)
            .background(color)
            .foregroundColor(.white)
            .cornerRadius(12)
            .padding()
    }
}

파라미터로 버튼의 색상(Color)과 제목, 이미지를 받는 Button 컴포넌트이다. cornerRadius 속성을 사용하여 모서리를 둥글게 만들었다.

 

ContentView

struct View1: View {
    
    @State private var isNight = true
    @State private var isShowingSheet = false
    
    var body: some View {
        ZStack {
            Color(isNight ? .black : .systemBlue).ignoresSafeArea()
            
            VStack {
                TimeOfDayImage(imageTitle: isNight ? "moon.stars.fill": "cloud.sun.fill")
                
                Button {
                    isShowingSheet = true
                } label: {
                    ButtonLabel(title: "Change Time Of Day", imageName: "clock.fill", color: .green)
                }
                .padding(.top, 100)
            }
        }
        .sheet(isPresented: $isShowingSheet, content: {
            ChangeTimeOfDayView(isNight: $isNight)
        })
    }
}

우선 다크모드인지 라이트모드인지를 판별하는 isNight 변수와 다른 뷰를 호출할것인지 여부를 결정하는 isShowingSheet를 @State로 선언하였다.

그 다음 배경색과 TimeOfDayImage의 이미지를 isNight에 값에 따라 변경할 수 있게 설정하였다. 버튼을 클릭하면 isShowingSheet 값이 true값으로 바뀌고 .sheet 속성을 통해 isNight 파라미터를 받는 새로운 View가 호출된다.

 

ChangeTimeOfDayView

다크모드와 라이트모드를 정할 수 있는 버튼 2개가 있는 View이다.

 

struct ChangeTimeOfDayView: View {
    
    @Binding var isNight:Bool
    @Environment(\.presentationMode) var presentationMode
    
    var body: some View {
        VStack {
            Button {
                isNight = true
                presentationMode.wrappedValue.dismiss()
            } label: {
                ButtonLabel(title: "Make Night", imageName: "moon.stars.fill", color: .black)
            }
            
            Button {
                isNight = false
                presentationMode.wrappedValue.dismiss()
            } label: {
                ButtonLabel(title: "Make Day", imageName: "cloud.sun.fill", color: .blue)
            }
        }
    }
}

@Binding을 통해 isNight 값을 부모 View로 부터 가져오고 환경 값인 presentationMode에 접근 할 수 있고 @Environment 키워드를 통해 새로운 변수인 presentationMode를 선언하여 해당 변수로 접근 가능할 수 있게 선언하였다.

주의해야 할 점은 @State로 선언한 변수는 파라미터가 없지만 @Binding으로 선언하면 반드시 해당 컴포넌트에 파라미터로 값을 받아야한다.

@isNight를 공유하고 있으므로 버튼을 클릭하면 부모 View의 isNight 값도 변하게 된다. 그 다음에 presentationMode의 현재 View인 wrappedValue를 가져온 뒤 dismiss 함수를 통해 해당 View를 닫아준다.

ActionSheet는 해당 View가 보여지면 isPresented가 true여야하고 안보이면 false여야한다. 그래서dismiss()를 통해 해당 뷰의 호출을 종료하면 자동으로 isShowingSheet의 값도 false가 된다.

반응형

'SwiftUI' 카테고리의 다른 글

SwiftUI Link  (0) 2021.04.03
SwiftUI Segmented Control  (0) 2021.04.01
SwiftUI Profile View  (0) 2021.03.30
SwiftUI 사진 가져오기(3)  (0) 2021.03.20
SwiftUI 사진 가져오기(2)  (0) 2021.03.19