Skip to content

Instantly share code, notes, and snippets.

@WinterArch
Last active November 20, 2023 06:04
Show Gist options
  • Select an option

  • Save WinterArch/8087f3487b69080f1bc35eff4c94c7a7 to your computer and use it in GitHub Desktop.

Select an option

Save WinterArch/8087f3487b69080f1bc35eff4c94c7a7 to your computer and use it in GitHub Desktop.
Model-View Design Patterns Plus
import SwiftUI
/// ContentView: Model
struct ContentView {
/// viewmodel first, one View one View Model, intuitively. if need.
@StateObject private var viewmodel = ViewModel()
/// properties here
let recordTime: Date
/// states here
@State private var counter: Int = 0
}
/// ContentView: View
extension ContentView: Equatable, View {
static func == (lhs: ContentView, rhs: ContentView) -> Bool {
lhs.counter == rhs.counter
}
var body: some View {
VStack {
Text("counter\(counter)")
Text("drag this: \(viewmodel.lastestAt.x), \(viewmodel.lastestAt.y)")
.padding(30)
.gesture(
DragGesture()
.onChanged { value in
viewmodel.lastestAt = value.location
}
)
.background {
// FREQUENT updates
Color.init(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1)
)
}
}
}
}
/// ContentView: ViewModel
extension ContentView {
class ViewModel: ObservableObject {
@Published var lastestAt = CGPoint()
}
}
#Preview {
ContentView(recordTime: Date())
.equatable()
}
import SwiftUI
struct StateView { // 祖先视图
@State private var box = Box()
struct Box {
var times: Int = 0
var record: Date = .now
let pub = PublishBox()
}
}
extension StateView.Box {
class PublishBox: ObservableObject {
@Published var color: Color = .clear
}
}
fileprivate extension StateView {
struct EnvironmentBox: EnvironmentKey {
static var defaultValue: Box = .init()
}
}
fileprivate extension EnvironmentValues {
var environmentBox: StateView.Box {
get { self[StateView.EnvironmentBox.self] }
set { self[StateView.EnvironmentBox.self] = newValue }
}
}
extension StateView: View {
var body: some View {
VStack {
Text("click:\(box.times)")
.onTapGesture {
box.times += 1
box.pub.color = .random
}
Text("record:\(box.record)")
.onTapGesture {
box.record = .now
box.pub.color = .white
}
SubView(box: box)
.equatable()
SubView2(box: $box)
}
.environment(\.environmentBox, box)
}
struct SubView: View, Equatable {
static func == (lhs: StateView.SubView, rhs: StateView.SubView) -> Bool {
lhs.box.times == rhs.box.times
}
let box: StateView.Box
var body: some View {
VStack {
Text("click:\(box.times)")
.onTapGesture {
// box.times += 1
// print("\(box.record)")
}
.background {
Color.random
}
Text("SubViewrecord:\(box.record)")
.background {
Color.random
}
StateView.SubView3()
}
}
}
struct SubView2: View {
@Binding var box: StateView.Box
var body: some View {
VStack {
Text("click:\(box.times)")
.onTapGesture {
box.times += 1
// print("\(box.record)")
}
.background {
Color.random
}
StateView.SubView(box: box)
.equatable()
.background {
Color.random
}
}
}
}
struct SubView3: View {
/// 环境注入-数据跨级传递
@Environment(\.environmentBox) var box: StateView.Box
/// 状态 - 接收器变量
@State private var receivedColor: Color = .clear
var body: some View {
VStack {
Text("hello,\(box.times)")
Text("world!\(receivedColor.description)")
.onReceive(box.pub.$color) {
receivedColor = $0
}
.background {
receivedColor
}
}
}
}
}
fileprivate extension Color {
static var random: Color {
.init(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1)
)
}
}
#Preview {
StateView()
}
struct VMStyleView {
@StateObject private var vm = ViewModel()
class ViewModel: ObservableObject {
@Published var times: Int = 0
@Published var record: Date = .now
}
}
extension VMStyleView: View {
var body: some View {
VStack {
Text("click:\(vm.times)")
.onTapGesture {
vm.times += 1
// print("\(box.record)")
}
Text("record:\(vm.record)")
.onTapGesture {
vm.record = .now
}
SubView(vm: vm)
.equatable()
SubView2(vm: vm)
}
}
struct SubView: View, Equatable {
static func == (lhs: VMStyleView.SubView, rhs: VMStyleView.SubView) -> Bool {
lhs.vm.times == rhs.vm.times
}
@ObservedObject var vm: VMStyleView.ViewModel
var body: some View {
VStack {
Text("click:\(vm.times)")
.onTapGesture {
vm.times += 1
// print("\(box.record)")
}
.background {
Color.random
}
Text("record:\(vm.record)")
.onTapGesture {
vm.record = .now
}
.background {
Color.random
}
}
}
}
struct SubView2: View {
@ObservedObject var vm: VMStyleView.ViewModel
var body: some View {
VStack {
Text("click:\(vm.times)")
.onTapGesture {
vm.times += 1
// print("\(box.record)")
}
VMStyleView.SubView(vm: vm)
.equatable()
}
.background {
Color.random
}
}
}
}
#Preview {
VMStyleView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment