测试已测试 | ✗ |
语言语言 | SwiftSwift |
许可证 | MIT |
发布最后发布 | 2017年12月 |
SwiftSwift 版本 | 4.0.2 |
SPM支持 SPM | ✗ |
由 Thibault Wittemberg 维护。
依赖项 | |
RxSwift | >= 4.0.0 |
RxCocoa | >= 4.0.0 |
Travis CI | |
框架 | |
平台 | |
许可证 |
Weavy 是一个基于交织模式的 iOS 应用导航框架
这份 README 是我通往这个框架整个构思过程的一个简要概述。
查看这个维基页面了解 Weavy 的更多信息:[Weavy 详细介绍](https://github.com/twittemb/Weavy/wiki/Weavy-in-details)
关于 iOS 应用内的导航,有两个选择可行
这两种解决方案的缺点
在您的 Cartfile 中
github "twittemb/Weavy"
在您的 Podfile 中
pod 'Weavy'
在现实世界中:交织涉及使用一个 织机 来交错两组以相互垂直的线:纵向的 经线 和与之相交的 纬线
这就是我设想简单应用中的交织模式的方式
如何理解这个?
这些纬线中的每一个都将因用户操作或后端状态变化而触发。
代表一个经线和一条纬线交叉的彩色芯片将是一个特定的导航操作(例如 UIViewController 出现)。
如我们所见,某些纬线被用于多个经线,它们的触发将导致显示相同的屏幕,但具有不同的展示选项。有时这些屏幕会弹出,有时它们将推入导航堆栈。
这个草图说明了我们可以如何分解UIViewControllers和Storyboards。
经线和纬线的组合描述了应用程序内部的所有可能的导航模式。
每个经线定义了一个清晰的导航区域(这使得您的应用程序分为界定良好的部分),其中每个纬线代表一个特定的导航动作(在堆栈上推入VC、弹出VC等)。
最后,针织功能必须返回一个针脚数组。针脚有助于织布机了解在下一导航步骤中将要处理什么。
为什么是针脚数组?例如,UITabbarController是一种模式,其中同时进行多个导航,我们需要告诉织布机那是在发生的。
针脚告诉织布机:您接下来要处理的是这个特定的可展示和这个特定的可织。在某些情况下,针织功能可以返回空数组,因为我们知道在当前导航之后不会有任何进一步的导航。
演示应用程序展示了几乎所有可能的情况。
导航的基本原理非常简单:它由对应用状态变化的连续视图转换组成。这些变化通常是由于用户交互引起的,但也可以来自您应用程序的低级层。我们可以想象,网络会话丢失可能导致登录屏幕出现。
我们需要一种方式来表达这些变化。正如我们所见,一个经线和纬线的组合代表一个导航动作。正如经线可以定义应用程序区域一样,纬线可以定义这些区域内的导航状态变化。
考虑到这一点,一个可织基本上是应用程序中能够表达一个新的纬线的东西,从而实现一个导航状态变化,导致导航动作。
纬线甚至可以嵌入内部值(如Ids、URLs等),这些值将在编织过程中传递到屏幕上。
织布机只是开发者的一种工具。一旦他已经定义了代表导航可能性的合适的经线和纬线的组合,织布机的工作就是要根据由纬线触发的导航状态变化编织这些组合。
由开发人员负责
下面的经线用作导航堆栈。
class WatchedWarp: Warp {
var head: UIViewController {
return self.rootViewController
}
let rootViewController = UINavigationController()
func knit(withWeft weft: Weft) -> [Stitch] {
guard let weft = weft as? AppWeft else { return Stitch.emptyStitches }
switch weft {
case .movieList:
return navigateToMovieListScreen()
case .moviePicked(let movieId):
return navigateToMovieDetailScreen(with: movieId)
case .castPicked(let castId):
return navigateToCastDetailScreen(with: castId)
default:
return Stitch.emptyStitches
}
}
private func navigateToMovieListScreen () -> [Stitch] {
let viewController = WatchedViewController.instantiate()
viewController.title = "Watched"
self.rootViewController.pushViewController(viewController, animated: true)
return [Stitch(nextPresentable: viewController, nextWeftable: viewController)]
}
private func navigateToMovieDetailScreen (with movieId: Int) -> [Stitch] {
let viewController = MovieDetailViewController.instantiate()
self.rootViewController.pushViewController(viewController, animated: true)
return [Stitch(nextPresentable: viewController, nextWeftable: viewController)]
}
private func navigateToCastDetailScreen (with castId: Int) -> [Stitch] {
let viewController = CastDetailViewController.instantiate()
self.rootViewController.pushViewController(viewController, animated: true)
return [Stitch(nextPresentable: viewController, nextWeftable: viewController)]
}
}
由于纬线被视为横跨整个应用程序的某些状态,因此使用枚举声明它们似乎很合理。
enum AppWeft: Weft {
case apiKey
case movieList
case moviePicked (withId: Int)
case castPicked (withId: Int)
case settings
}
从理论上讲,可织作为一个协议,可以是任何东西(一个UIViewController实例),但建议将这种行为孤立在ViewModel等中。
对于简单情况(例如,我们只需要使用第一个纬线引导经线,而不想为它编写基本可织代码的情况),Weavy提供了一个SingleWeftable类。
class WishlistViewModel: Weftable {
init() {
self.weftSubject.onNext(AppWeft.movieList)
}
@objc func settings () {
self.weftSubject.onNext(AppWeft.settings)
}
}
编织过程将在AppDelegate中启动。
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var loom = Loom()
let mainWarp = MainWarp()
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
guard let window = self.window else { return false }
Warps.whenReady(warp: mainWarp, block: { [unowned window] (head) in
window.rootViewController = head
})
loom.weave(fromWarp: mainWarp, andWeftable: SingleWeftable(withInitialWeft: DemoWeft.apiKey))
return true
}
}
作为奖励,织布机提供了一个Rx扩展,允许您追踪编织步骤(Loom.rx.willKnit和Loom.rx.didKnit)。
提供一个演示应用程序来展示核心机制。几乎涵盖了所有类型的导航。应用程序包括
Weavy依赖于