导航器 0.3.10

导航器 0.3.10

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最后发布2015年7月

Ty Cobb 维护。



导航器 0.3.10

  • 作者:
  • Ty Cobb

Navigator 是一个用于跟踪应用程序状态并在视图之间切换的 URL 路由器。与使用 key/:id -> view 映射提供孤立转换的现有解决方案不同, Navigator 将 URL 区分为一系列更新,可以执行任何数量的堆栈更改和执行任意动画。这提高了视图控制器和动画模块化,并减轻了实现深链接或基于状态的分析等功能的工作量。

安装

您可以使用 CocoaPods 安装 Navigator。

pod 'Navigator', '~> 0.3'

配置

Navigator 有两个核心类: NAVRouterNAVViewController。路由器声明从字符串键到视图控制器类的映射,由这些键组成的 URL 将视图推入堆栈、以模态呈现它们或执行任意动画。

URLs

让我们分析一个例子。这是一个电视应用 URL,它有一个主屏幕、一个在主屏幕之上推送的节目详细屏幕,以及在一个模态中呈现的视频播放器。类似于以下内容:

television://home/show::2?video=v

分析如下:

  • 方案: television 是路由器的方案,并且所有 URL 都必须有方案。
  • 组件: homeshow 是 URL 的组件,它们对应于导航堆栈上的视图。在这种情况下,home 是根视图,而 show 是可见视图。
  • 数据: show 还有一个数据元素 2。这可以是一个字符串,在这种情况下它是一个数字 id。这些在视图出现在屏幕之前传递给视图,以便它有时间进行准备。
  • 参数: video=v 是这个 URL 的唯一参数。参数是键值对,其中键是视图的键,值是视图的状态。在这种情况下,视图是 video,其状态是 visible

实现路由器

声明一个新的 NAVRouter 子类,并在实现中导入 NAVRouter_Subclass.h

方案

最重要的是路由器需要一个方案,您可以 通过实现 +scheme 来指定一个方案。

+ (NSString *)scheme
{
    return @"demoapp";
}
路由

路由器还需要一些路由,并且您可以使用 -routes: 定义其初始路由。

- (void)routes:(NAVRouteBuilder *)route
{
    route.to(@"red").controller(RedViewController.class);
    route.to(@"purple").controller(PurpleViewController.class).as(NAVRouteTypeModal);
}

此方法接受一个NAVRouteBuilder实例,您可以用它来构建路由。通常,路由是通过键创建的to字符串,并给出目的地对象,而在所有这些情况下,目的地对象是传递给controller的视图控制器类(继承自NAVViewController)。

路由构建的详细信息将在后面介绍。可以随时使用-updateRoutes:将路由添加到/从路由器中删除。

实现视图控制器

路由器需要创建视图控制器,而控制器自身定义了它们应该如何被创建。默认情况下,路由器会从一个Storyboard及Storyboard ID创建NAVViewController的子类。

如果您对此表示同意,则至少在您的子类中使用+storyboardName指定Storyboard名称。

+ (NSString *)storyboardName
{
    return @"MainStoryboard";
}

然后路由器会尝试使用控制器类名的字符串版本作为默认ID从这个Storyboard中创建视图控制器。要自定义此行为,重写+storyboardIdentifier。无论您的ID是什么,确保在IB中的“身份检查器”面板中为每个视图控制器指定它。

如果一个控制器需要完全自定义的实例化,它可以通过重写+instance来绕过Storyboard加载过程。

+ (instancetype)instance
{
    return [[self alloc] initWithNibName:NSStringFromClass(self) bundle:nil];
}

连接到导航堆栈

要启用路由器正常运行,最后的步骤是将它与一个导航控制器关联起来。您可以通过显式设置它来做到这一点。

[DemoRouter router].navigationController = self.navigationController;

或者,如果路由器没有导航控制器并且您将其delegate设置为一个既是UINavigationController的实例或有一个-navigationController方法的实例,路由器将尝试使用它作为其导航控制器。

动画

可以通过从NAVAnimation中进行子类化并使用该动画的实例创建一个路由来将自定义动画钩接到路由器上。实际视图更新由-updateIsVisible:animated:completion:驱动。当路由变化引起动画更新时,路由器会调用此方法。

例如,要实现一个简单的侧边菜单动画,您可以定义以下类

@implementation MenuAnimation

- (void)updateIsVisible:(BOOL)isVisible animated:(BOOL)animated completion:(void (^)(BOOL))completion
{
    [UIView animateWithDuration:0.4f delay:0.0f usingSpringWithDamping:0.75f initialSpringVelocity:0.0f options:0 animations:^{
        self.animatingView.transform = CGAffineTransformMakeTranslation(isVisible ? 300.0f : 0.0f, 0.0f);
    } completion:completion];
}

@end

然后向该动画的实例添加一个路由来显示它

MenuAnimation *menuAnimation = [MenuAnimation new];
menuAnimation.animatingView  = self.containerView;

[[DemoRouter router] updateRoutes:(NAVRouteBuilder *route) {
    route.to(@"menu").animation(menuAnimation);
}];

如果动画需要在路由器之外发生,例如通过交互式手势,也应该通过NAVAnimation子类来驱动其逻辑。在这种情况下,当交互完成时,动画应该适当地设置动画的isVisible属性。

用法

您的路由器子类通过+router获得一个隐式(并且非线程安全)的共享实例,您可以使用它来执行转换、更新路由等操作。

转换

如果路由器不能在视图之间转换,那么它就没有多少用处。它指定了一个用于启动转换的-transition方法,该方法返回一个灵活的构造器,用于构建和启动路由变化。让我们分析一些示例转换。

[DemoRouter router].transition
    .root(@"red")
    .animated(NO)
    .start(nil);

此转换将路由器转换到一个新的root视图,从@"red"映射而来,并丢弃堆栈上的任何其他视图。您可能第一次启动应用程序时会做类似的事情。

-start方法完成构建并尝试立即运行转换。它接受一个完成块,当转换完成时调用,或者如果已经有一个正在运行的转换,立即以错误调用。

[DemoRouter router].transition
    .push(@"green")
    .present(@"purple")
    .enqueue(nil).

过渡可以从多个URL变化中组合而成。这个过渡将@"green"视图推入栈中,然后完成时以模态的方式展示@"purple"视图。

这种方法也使用-enqueue而不是-start,它将等待所有正在运行或排队的过渡完成后再解析。如果没有这样的过渡存在,它将立即开始。

过渡中传递数据

您还可以在过渡期间传递数据字符串、对象(例如,模型)和处理程序,这些数据将被传递到视图。

[DemoRouter router].transition
    .push(@"red")
    .data(demoModel.identifier)
    .object(demoModel)
    .start(nil)

这些数据通过-updateWithAttributes:传递给NAVViewControllerNAVAnimation的子类。此方法接收一个包含相关过渡数据的NAVAttributes实例,并且之后会被丢弃。

- (void)updateWithAttributes:(NAVAttributes *)attributes
{
    [super updateWithAttributes:attributes];
    NSLog(@"%@: %@", attributes.data, attributes.userObject);
}

路由构建

虽然最初是在NAVRouter子类的-routes:方法中定义的,但可以使用-updateRoutes:在任何时候更改路由。此方法接受一个被传递并包含NAVRouteBuilder实例的块。

路由可以配置动画、控制器类别和自定义类型。

[[DemoRouter router] updateRoutes:^(NAVRouteBuilder *route) {
    route.to(@"video").controller(VideoViewController.class).as(NAVRouteTypeModal);
    route.to(@"menu").animation(menuAnimation);
}];

如果给路由传入了控制器或动画,它的类型将被隐式地设定为NAVRouteTypeStackNAVRouteTypeAnimation。可以使用-as进进一步指定,例如在NAVRouteTypeModal的情况下。这允许展示视图控制器,而不是推送。