Flowter
一个轻量级、Swift 字符和可自定义的 UIViewController 流程协调器 DSL。
它支持静态或动态构建流程,具有良好的一般语法。
安装
Carthage
只需将其添加到 Cartfile 中。
github "Zazcar/Flowter"
别忘了运行您喜欢的 carthage 命令。
CocoaPods
只需将 Flowter 添加到 Podfile 中。
pod 'Flowter'
别忘了运行您喜欢的 cocoapods 命令。
基本用法
创建流程并将其设置为 UIViewController 和一个容器。
Flowter 可以在任何地方创建,前提是你有一个将要展示流程的参考,只需在使用 startFlow 闭包时使用它。
Flowter(with: UINavigationController())
.addStep { $0.make(with: StepViewController(withLabel: "1st Step"))}
.addStep { $0.make(with: StepViewController(withLabel: "2nd Step"))}
.addStep { $0.make(with: StepViewController(withLabel: "3rd Step"))}
.addEndFlowStep { (container) in
container.dismiss(animated: true)
}
.startFlow { (container) in
myNavigationController.present(container, animated: true)
}
你必须使你的控制器符合 Flowtable
协议。
这仅指定说你的控制器有一个名为 flow 的类型为 FlowStepInfo?
的变量。
var flow: FlowStepInfo?
当控制器准备好进行流程时,你将调用它。
private func nextStep() {
flow?.next()
}
逐步进行
让我们从 Flowter
开始,它只是你正在构建的流程的临时表示。你用一个容器初始化它,这个容器应该是 UIViewController 或 UINavigationController 的实例,之后只需向其中添加步骤。
let flowContainer = UINavigationController()
let flowter = Flowter(with: flowContainer)
flowter.addStep(with: { (stepFactory) -> FlowStep<FlowtableViewController, UINavigationController> in
return stepFactory.make(with: FlowtableViewController())
})
你的 FlowtableViewController 步骤将被添加到流程中,它需要符合 Flowtable 协议。
视图控制器将在展示之前被实例化,并且根据容器类型,存在默认的展示流程。所以你将在基于导航的流程中收到推送和弹出,在 UIViewController 流程中获得基本的展示。你可以为整个流程或每个步骤自定义展示,详见以下内容...
在你结束添加步骤之后,你需要使用其 dismiss 代码结束你的流程,然后你最终可以开始你的流程。
let finishedFlowter = flowter.addEndFlowStep { (container) in
container.dismiss(animated: true)
}
finishedFlowter?.startFlow { (container) in
someViewController.present(container, animated: true)
}
当然,这可以以一种更简洁的方式完成。
Flowter(with: UINavigationController())
.addStep { $0.make(with: FlowtableViewController()) }
.addEndFlowStep { $0.dismiss(animated: true) }
.startFlow { someViewController.present($0, animated: true) }
感谢尾随闭包和使用简写参数名称糖,享受这种简短的版本...
依赖注入
你可以完全自定义每个步骤 UIViewController 子类的工厂闭包,在这个时候,你可以给它提供所需的内容。
let newUser = User()
Flowter(with: UINavigationController())
.addStep { $0.make(with: FirstStepViewController(withUser: newUser))}
.addStep {
$0.make { () -> SecondStepViewController in
let viewModel = SecondStepViewModel(with: newUser)
return SecondStepViewController(with: viewModel)
}
}
.addStep(with: { (stepFactory) -> FlowStep<ThirdStepViewController, UINavigationController> in
let step = stepFactory.make(with: ThirdStepViewController())
step.setPresentAction({ (thirdStepVC, container) in
thirdStepVC.setUser(newUser)
thirdStepVC.setCustomParameter(foo: false)
container.pushViewController(thirdStepVC, animated: false)
})
return step
})
.addEndFlowStep { (container) in
container.dismiss(animated: true)
}
.startFlow { [weak self] (container) in
self?.present(container, animated: true)
}
你可以在视图控制器内部做任何你想做的事情,以一个易于可视化和灵活的语法。
将上下文对象传递到下一步
你可以选择在调用 flow?.next(context: Any?)
时传递一个任意的对象到下一步。
let info: String = "context string"
flow?.next(context: info)
在下一个步骤 viewController 的 func updateFlowtableViewController(with context: Any?)
中,上下文将在展示前传递,这使得上下文在展示前传递。
func updateFlowtableViewController(with context: Any?) {
guard let contextString = context as? String else {
//do something or just return
return
}
doSomething(with: contextString)
}
自定义呈现和消失代码
默认值
在创建流程时,可以为自定义宽度的自定义呈现或消失代码提供,如果在步骤上未定义自定义流程,则这些实现将生效。
let flowContainer = CustomNavigationController()
Flowter(with: flowContainer,
defaultPresentAction: { (vc, container) in
container.customPushViewController(vc)
},
defaultDismissAction: { (vc, container) in
container.customPopViewController()
})
您期望使用与创建流程时相同的容器类型,由于泛型,不需要类型转换。
呈现
为了控制一个控制器的呈现
.addStep(with: { (stepFactory) -> FlowStep<StepViewController, UINavigationController> in
let step = stepFactory.make(with: StepViewController(withLabel: "Flow Start"))
step.setPresentAction({ (welcomeVC, container) in
welcomeVC.setAsWelcomeStep()
container.pushViewController(welcomeVC, animated: false)
//I don't known why I would do this...
})
return step
})
消失
当您查看控制器不依赖于自动的 UINavigationController 返回按钮时,消失也是可用的。
您必须调用 FlowStepInfo 方法的回调来导航回退,您的步骤 dismissAction 闭包将被调用,您将负责消失的 viewController。
.addStep(with: { (stepFactory) -> FlowStep<StepViewController, UINavigationController> in
let step = stepFactory.make(with: StepViewController(withLabel: "Flow Start"))
step.setPresentAction({ (welcomeVC, container) in
container.pushViewController(welcomeVC, animated: false)
})
step.setDismissAction({ (welcomeVC, container) in
container.dismiss(animated: false, completion: {
//some completion code
})
})
return step
})
在您的 FlowTable 定义 UIViewController 子类中
private func backStep() {
flow?.back()
}
private func nextStep() {
flow?.next()
}
动态构建的流程
也可以使用可变的步骤数量和类型来构建流程。为此,将流程存储在 let 中,并使用此引用添加新步骤。
private func openFlow(includeSecondStep: Bool) {
let flowter = Flowter(with: UINavigationController())
.addStep { $0.make(with: StepViewController(withLabel: "1st Step"))}
if includeSecondStep {
flowter.addStep { $0.make(with: StepViewController(withLabel: "2nd Step"))}
}
flowter
.addStep { $0.make(with: StepViewController(withLabel: "3rd Step"))}
.addEndFlowStep { (container) in
container.dismiss(animated: true)
}
.startFlow { (container) in
myNavigationController.present(container, animated: true)
}
}
始终向同一 Flowter 对象添加步骤。如果您想串联步骤,保持对返回的 FilledFlowters 的引用,并使用它来添加更多步骤或完成流程。
代码复用
您可以使用并在其他地方已经使用过的相同的控制器,在流程外使用!
只需保证或检查 flow
的存在,或者使用可选链来调用它,如 flow?.next()
。
private func close() {
if let flow = self?.flow {
//inside a Flowter, proceed the flow
flow.next()
return
}
//on stand alone usage just pop the view controller
self.navigationController?.popViewController(animated: true)
}