개요
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가 된다.
Uploaded by Notion2Tistory v1.1.0