SwiftUI

SwiftUI — Combine 实践 双向绑定和时间机器

2020-03-08  本文已影响0人  丿唯一的唯一丿

学习完苹果的教程
我们知道了通过@State 就可以实现 数据和UI的绑定
修改APP就可以直接修改数据的State 例如

@State private var showDetail = true
Button(action: {
 self.showDetail.toggle()
}
 if showDetail {
  HikeDetail(hike: hike).transition(.moveAndFade)
 }

当点击Button的时候会修改数据,同时SwiftUI会reload页面
做过大型一点的APP的同学都会知道 当你们公司出现数据部门的时候
APP端就会要求打点 对用户当前所做的操作做记录 那么用户的所有操作都会定义一个State 我们就可以创建一个protocol 来完成这件事

//
public protocol StateMachine {

    // 定义你APP内可能发生的事情例如:添加一个item 修改item Title
    associatedtype Event

    //储存事件信息
    mutating func update(with event: Event)
}

     //事件类型
    enum Event {
            //开始创建item 点击 +
             case startCreatingItem
            //取消创建item 点击 后面蒙版
             case cancelCreatingItem
            //修改 添加 title
             case changePartialItemName(String)
            //点击add
             case addItem
            //点击Toggle 开关
             case setItemDone(identifier: UUID, isDone: Bool)
    }

用户操作后你就要记录下来 那么通过上面你就可以知道我们可以创建一个记录操作的类 在用户操作的时候自动记录
数据部门还会有需求,把用户的操作链式表现,那么就可以用数组装下他
创建一个全局的Store,并增加一个方法记录TodoState

@EnvironmentObject var store: Store
 // 添加事件
     private var subsequentStates: [TodoState] = []

        func dispatch(event: TodoState.Event) {
           var newState = state
           newState.update(with: event)
           subsequentStates.append(newState)
       }

说到这里呢,最后把数据上报,就已经完成了数据部门的要求。
我们已经完成了View对State的绑定,学过前端的同学就知道,前端一般都会实现双向绑定,单向绑定非常简单,就是 用户修改View,也更新了State的数据。有单向绑定,就有双向绑定。如果用户更新了State时,View就会自动更新,这种情况就是双向绑定。

把UI根据当前的State绑定

var body: some View {
        ZStack{
            NavigationView{
                List(store.state.todoItems){item in
                    TodoListItem(item: item)
                }.navigationBarTitle(Text("TimeTrave"))
                    .navigationBarItems(trailing: Button(action: {
                        self.store.dispatch(event: .startCreatingItem)
                    }, label: {
                        Image(systemName: "plus.circle")
                    }))
            }
            if store.state.isCreatingItem {
                ModalDimmingView()
                    VStack{
                    Spacer()
                    AddItemView()
                    .background(Color.white)
                    .cornerRadius(12.0)
                    .shadow(radius: 16.0)
                    .padding()
                    Spacer()
                    }
                .transition(.move(edge: .bottom))
            }
        }
双向绑定

那么UI绑定已经绑定State,那怎么实现State发生变化View就能变化了,那我们就可以让Store成为一个ObservableObject,绑定方法也修改,当前State需要改变时,发布change,当currentState发生变化的时候就可以让View发生变化了

//观察对象
public final class Store: ObservableObject {
    //初始State
    private let initialState: TodoState
    //储存TodoState
    private var subsequentStates: [TodoState] = []
    //Publisher 发布者 发布状态改变
    public let objectWillChange = PassthroughSubject<Void, Never>()

  //当前state需要改变时 发布change
    var currentStateIndex: Int = 0 {
        didSet {
            withAnimation {
                objectWillChange.send(())
            }
        }
    }

       func dispatch(event: TodoState.Event) {
           var newState = state
           newState.update(with: event)
           subsequentStates.append(newState)
           currentStateIndex = stateCount - 1
       }

最后既然我们都实现了双向绑定那么就可以手动修改currentState看一下,用一个Slider绑定currentStateIndex

 let indexBinding = Binding(
        get: {
           return Double(self.store.currentStateIndex)
        }, set: {
            self.store.currentStateIndex = Int($0)
    })
 Slider(value: indexBinding, in: 0...Double(store.stateCount - 1)

当你拖动Slider的时候,是不是就有种时间机器的感觉,可以回到任意的State,看一下效果

TimeTrave.gif
最后放上代码地址
上一篇下一篇

猜你喜欢

热点阅读