Flowter 0.4.1

Flowter 0.4.1

Paulo Saito 维护。



Flowter 0.4.1

  • Paulo Cesar Saito

Build Status codecov Pod Platform Pod License Pod Version Carthage compatible

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)
}

务必在必要时削弱自身的存在。

有很多闭包被存储,并且在流程关闭时避免内存泄漏是至关重要的。