protocol EnvironmentalModifier : ViewModifier where Self.Body == Never {
associatedtype ResolvedModifier : ViewModifier
func resolve(in environment: EnvironmentValues) -> Self.ResolvedModifier
}
실행 직전에 environment 값으로부터 구체적 modifier를 결정하는 modifier.
EnvironmentalModifier
는 실행시의 View environment 값에 따라 각기 다른 수정자(modifier)를 실행할 수 있다. body
는 ViewModifier
의 기본구현만을 사용하는 것이 강제되므로, 사용자는 body
대신 resolve
함수에서 ViewModifier
를 반환하는 구문을 구현해야 한다. SwiftUI는 수정자가 호출될 때마다 EnvironmentValues
인자 전달과 함께 resolve
함수를 실행한다.
사용자 정의 수정자를 사용할 경우 다음과 같은 상황이 발생할 수 있다.
struct Vivid: ViewModifier {
let isDarkmode: Bool
func body(content: Content) -> some View {
content
.foregroundColor(isDarkmode ? .white : .black)
.padding()
}
}
struct ContentView: View {
@Environment(\.colorScheme) private var colorScheme
var body: some View {
Text("Hello World")
.modifier(Vivid(isDarkmode: colorScheme == .dark))
// modifier의 가독성이 떨어진다.
}
}
EnvironmentalModifier를 사용하면 위 코드를 개선할 수 있다.
// environment 값 처리 및 인자 전달이 처리된 modifier를 반환한다.
struct VividEnvironment: EnvironmentalModifier {
struct Vivid: ViewModifier { /*위와 동일...*/ }
func resolve(in environment: EnvironmentValues) -> Vivid {
let isDarkmode = environment.colorScheme == .dark
return Vivid(isDarkmode: isDarkmode)
}
}
// 이제 environment 프로퍼티도, 인자 전달 구문도 필요하지 않다.
struct ContentView: View {
var body: some View {
Text("Hello World")
.modifier(VividEnvironment())
// resolve 함수를 호출하고 반환된 modifier를 실행한다.
}
}
다른 사용자 정의 수정자와 마찬가지로, View 익스텐션 코드 블록 내부에 modifier(_:)
수정자를 감싼 새 수정자를 정의하여 수정자 호출문을 단순하게 만들 수 있다.
extension View {
func vivid() -> some View {
modifier(VividEnvironment())
}
}
...
struct ContentView: View {
var body: some View {
Text("Hello World").vivid()
}
}