完全声明式:SwiftUI 规则。
SwiftUI 规则在 AlwaysRightInstitute 的配套博客文章中进行了介绍:动态环境 ¶ SwiftUI 规则。
SwiftUI 规则需要能够运行 SwiftUI 的环境。即:macOS Catalina、iOS 13 或 watchOS 6。需要配合 Xcode 11 使用。
请注意,您可以在 Mojave 模拟器上运行 iOS 13/watchOS 6 应用程序,所以这也没问题。
您可以直接将 SwiftUIRules Xcode 项目拖到您自己的项目中,也可以使用 Swift Package Manager。
软件包 URL 是:https://github.com/DirectToSwiftUI/SwiftUIRules.git 。
SwiftUI 规则在 AlwaysRightInstitute 的配套博客文章中进行了介绍:动态环境 ¶ SwiftUI 规则。
假设我们想要添加一个名为 fancyColor
的自定义环境键。
首先我们需要一个 DynamicEnvironmentKey
声明
struct FancyColorEnvironmentKey: DynamicEnvironmentKey {
public static let defaultValue = Color.black
}
最重要的是,它指定了环境键的静态 Swift 类型(Color
),并提供了一个默认值。当查询环境键时,但用户没有显式设置值时,将使用该默认值。
其次,我们需要在 DynamicEnvironmentPathes 结构体上声明一个属性
extension DynamicEnvironmentPathes {
var fancyColor : Color {
set { self[dynamic: FancyColorEnvironmentKey.self] = newValue }
get { self[dynamic: FancyColorEnvironmentKey.self] }
}
}
就这样。我们可以开始使用我们的新键了。
某个 View 使用 @Environment 属性包装器访问我们出色的新 fancyColor
struct FancyText: View {
@Environment(\.fancyColor) private var color
var label : String
var body: some View {
Text(label)
.foregroundColor(color) // boooring
}
}
和一个 View 提供它
struct MyPage: View {
var body: some View {
VStack {
Text("Hello")
FancyText("World")
}
.environment(\.fancyColor, .red)
}
}
我们建议创建一个 RuleModel.swift
Swift 文件。将所有规则放在该中心位置。
// RuleModel.swift
import SwiftUIRules
let ruleModel : RuleModel = [
\.priority == .low => \.fancyColor <= .gray,
\.priority == .high => \.fancyColor <= .red,
\.priority == .normal => \.fancyColor <= .black
]
您可以在 SwiftUI View 层次结构的任何位置挂钩规则系统,但我们再次建议在最顶层执行此操作。例如,在 Xcode 中生成的新应用程序中,您可以像这样修改生成的 ContentView
struct ContentView: View {
private let ruleContext = RuleContext(ruleModel: ruleModel)
var body: some View {
Group {
// your views
}
.environment(\.ruleContext, ruleContext)
}
}
通常需要注入一些“根”属性
struct TodoList: View {
let todos: [ Todo ]
var body: someView {
VStack {
Text("Todos:")
ForEach(todos) { todo in
TodoView()
// make todo available to the rule system
.environment(\.todo, todo)
}
}
}
}
TodoView
及其子视图现在可以使用规则系统派生 todo
键的环境值。
哈!无穷无尽 🤓 “以规则思考”™(即声明式)是截然不同的,但它们允许您以高度解耦且真正“声明式”的方式组合您的应用程序。
它可以用于低级别,有点像 CSS。将动态环境键视为有点像 CSS 类。例如,您可以根据平台切换设置
[
\.platform == "watch" => \.details <= "minimal",
\.platform == "phone" => \.details <= "regular",
\.platform == "mac" || \.platform == "pad"
=> \.details <= "high"
]
但它也可以用于非常高的级别,例如在工作流程系统中
[
\.task.status == "done" => \.view <= TaskFinishedView(),
\.task.status == "done" => \.actions <= [],
\.task.status == "created" => \.view <= NewTaskView(),
\.task.status == "created" => \.actions = [ .accept, .reject ]
]
struct TaskView: View {
@Environment(\.view) var body // body derived from rules
}
由于 SwiftUI View 也只是轻量级结构体,因此您可以构建携带它们的动态属性!
无论如何:我们对如何使用它的任何想法都感兴趣!
当前,规则只能评估 DynamicEnvironmentKey
s,它不考虑常规环境键。也就是说,您不能使用规则系统驱动例如内置的 SwiftUI lineLimit
。
[
\.user.status == "VIP" => \.lineLimit <= 10,
\.lineLimit <= 2
]
不起作用。这目前通过要求与系统一起使用的键具有 DynamicEnvironmentKey
类型来显式化。因此,您不会意外地遇到这种情况。
我们可能会将其开放给任何 EnvironmentKey
,待定。
有时可能想要这样
\.todos.count > 10 => \.person.status <= "VIP"
即,将值分配给多组件 keypath (\.person.status
)。这不起作用。
有时 SwiftUI 在导航期间或在 List 中会“丢失”其环境。 watchOS 和 macOS 似乎特别有问题,iOS 较少。如果发生这种情况,可以手动传递 ruleContext
struct MyNavLink<Destination, Content>: View {
@Environment(\.ruleContext) var ruleContext
...
var body: someView {
NavLink(destination: destination
// Explicitly pass along:
.environment(\.ruleContext, ruleContext))
...
}
由 The Always Right Institute 和 ZeeZide 为您带来。我们喜欢 反馈、GitHub 星星、酷炫的 合同工作,大概是您可以想到的任何形式的赞美。