我有这个测试代码,我认为我编写的一切都正确,但由于某些原因它不起作用,我的意思是它没有应用修改。我不明白为什么会出现这个问题?
我的目标是停止重复输入修饰符的值并使用父视图值
import SwiftUI
struct ContentView: View {
var body: some View {
MyView(value: "Hello, world!", color: .red, border: true)
.bordered()
}
}
struct MyView: View {
let value: String
let color: Color
let border: Bool
var body: some View {
Text(value)
.foregroundStyle(color)
.environment(\.borderColor, color)
.environment(\.isBorderEnabled, border)
}
}
struct BorderedModifier: ViewModifier {
@Environment(\.borderColor) private var color
@Environment(\.isBorderEnabled) private var border
func body(content: Content) -> some View {
Group {
if (border) {
content
.padding(5.0)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(color, lineWidth: 2)
)
} else {
content
}
}
}
}
extension View {
func bordered() -> some View {
self.modifier(BorderedModifier())
}
}
private struct BorderColorKey: EnvironmentKey {
static let defaultValue: Color = .black
}
private struct BorderEnabledKey: EnvironmentKey {
static let defaultValue: Bool = false
}
extension EnvironmentValues {
var borderColor: Color {
get { self[BorderColorKey.self] }
set { self[BorderColorKey.self] = newValue }
}
var isBorderEnabled: Bool {
get { self[BorderEnabledKey.self] }
set { self[BorderEnabledKey.self] = newValue }
}
}
这是修饰符排序的问题。视图修饰符只会拾取在应用视图修饰符后设置的环境值。但是按照您的方式,环境值是在应用视图修饰符之前设置的。
您可以通过将
.bordered()
修饰符移入进行修复MyView
:使其工作的另一种方法是稍微改变一下逻辑。
事实上,您已经让父视图确定边框是否启用,因为您将布尔标志作为参数传递给子视图。
这里有更新的例子来展示它如何以这种方式工作。
.isBorderEnabled
通过View
扩展设置环境变量bordered
。false
作为参数提供给.bordered
,或者根本不要调用它。BorderedModifier
来调用视图修饰符。View
borderColor
.borderColor
不再需要环境键。我找到了一种方法来停止重复输入父视图中已经存在的值。我使用的是 PreferenceKey。我看到的限制是我必须将此修饰符应用于我想要修改的视图。理想情况下,我希望将其应用于 VStack 一次,以便所有四个 MyView 实例都得到修改。目前,如果您将修饰符应用于 VStack,它会将 VStack 视为内容并仅应用一次修改。在最佳情况下,我希望修饰符通过 VStack 并影响所有 MyView 实例。