滑轮
一个库,用于模仿 iOS 10/11 中地图应用中的抽屉。主分支遵循 Swift 的最新已发布版本。如果您需要 Swift 的较旧版本,可以在 Podfile 中指定其版本(例如 1.0.x),或者使用该版本的分支上的代码。旧分支不受支持。
更新/迁移信息
注意: Pulley 2.9.0 新增了支持新 displayMode 的属性。基本功能应在没有重大更改的情况下运行。最大的变化是增加了新的 displayMode:.compact
,以在 iPhone SE 尺寸的设备上复制 Apple 地图的行为。这是 Apple 地图滑屉行为的精确复制品;因此,当 PulleyViewController
的 currentDisplayMode
为 .compact
时,在 .compact
模式下,视图控制器支持的唯一 supportedDrawerPositions
是 .open
、.closed
和 .collapsed
。此模式还具有新的 @IBInspectable 属性,即 compactInsets
和 compactWidth
。此模式的行为与 .panel
模式非常类似。关于此功能背后的动机,请参阅这里的拉取请求。此外,在这次发布中,setDrawerContentViewController(controller: UIViewController, position: PulleyPosition? = nil, animated: Bool = true, completion: PulleyAnimationCompletionBlock?)
有了新的可选参数 position
,以在设置新的 DrawerContentViewController
时设置新的抽屉位置。有关此功能背后的动机,请参阅此处的拉取请求。
Pulley 2.5.0 进行了重大的命名更改以支持新功能。尽管属性名称已更改,但功能应在没有重大更改的情况(除了重命名之外)下运行。有关更多信息,请参阅这个线程。
Pulley 2.4.0 将 PulleyPosition 从枚举更改为类。这不会影响大部分使用,但可能会影响您的 switch 语句。继续像往常一样使用静态 PulleyPosition 值,并添加一个默认情况。这样做是为了允许将某些 PulleyDrawerViewControllerDelegate
方法标记为可选,这样如果您不使用某些位置(或希望使用默认值),则不需要实现它们。如果您有任何问题,请提出问题。
技术原因:可选协议方法需要 @objc 属性。Swift 枚举数组的数组不能暴露给 Objective-C,并且 supportedDrawerPositions 之前返回一个 PulleyPosition 枚举数组。此更改允许标记协议为 @objc,以便可以将方法标记为可选。
介绍
Pulley 是一个易于使用的抽屉库,旨在模仿 iOS 10/11 地图应用中的抽屉。它公开了一个简单的 API,允许您使用任何 UIViewController
子类作为抽屉内容或主内容。
以下是一个预览(对于土豆动图表示歉意)
安装
使用 Cocoapods 进行安装
pod 'Pulley'
使用 Carthage 进行安装
github "52inc/Pulley"
请阅读有关设置的此 问题(如果使用 Carthage)。
使用 Swift Package Manager 进行安装
请参考 Swift Package Manager 的 开发者文档(2.8.x 版本)。
手动安装
仅需将 PulleyLib 文件夹中的文件复制到您的项目中。
如何使用
Interface Builder
Pulley 支持从 Interface Builder 加载嵌入的视图控制器。为了使用 Pulley 与 Interface Builder,您需要设置您的 PulleyViewController
,如下所示:
- 向
PulleyViewController
视图中添加 2 个容器视图。一个用于抽屉内容,一个用于主要(背景)内容。 - 将主要(背景)内容的容器视图连接到名为 primaryContentContainerView 的出口。
- 将抽屉内容的容器视图连接到名为 drawerContentContainerView 的出口。
- 在每个容器视图和您想为本部分抽屉显示的视图控制器之间创建一个'embed' segue。
- 确保将视图控制器的模块设置为'Pulley'。 查看此问题。
如果您想自定义抽屉的"折叠"或"部分显示"高度,让您的抽屉内容视图控制器实现 PulleyDrawerViewControllerDelegate
。您可以为折叠和部分显示状态提供抽屉内容的高度。
程序化实现
Pulley支持程序化加载视图控制器。为了程序化使用Pulley,请考虑以下代码片段
let mainContentVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("PrimaryContentViewController")
let drawerContentVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("DrawerContentViewController")
let pulleyController = PulleyViewController(contentViewController: mainContentVC, drawerViewController: drawerContentVC)
API
重要:内部抽屉视图的背景为透明。如果您的视图控制器的视图也是透明的,将会看到视图下面渲染的阴影。建议为您的视图设置颜色或使用UIVisualEffectView以确保看不到阴影。如果想要隐藏阴影,可以将阴影不透明度设置为0.0。
重要:Drawer内容视图因考虑弹跳动画而会过长的20pt。请确保您的抽屉内容视图知道底部20pt将会不在屏幕上。
重要:如果从Storyboard加载Pulley,则在 VIEWWillAppear: 期间或之后,PulleyViewController 才可以作为父视图或在 self.pulleyViewController 中访问。
iOS 11、安全区域以及iPhone X
Pulley支持安全区域和iPhone X。示例项目完全支持这一点,并采取了一些UI技巧使事物看起来更好。这些在示例项目中都有文档说明。
在iOS 11之后使用Pulley的基本概念
- 属性 -topInset 是从顶部安全区域,而不是从屏幕顶部开始的。
- 大多数代理方法都有一个新参数,它告诉您当前的底部安全区域。
- 抽屉本身对底部安全区域没有做特殊处理,因为每个人的UI都想以不同的方式处理它。然而:已更新代理方法,以便在任何需要您请求抽屉位置值时提供当前底部安全区域。您可以使用此变量来计算您想要返回的抽屉位置的值。请查看示例项目,其中包含一个简单示例,展示了一种简单的方法来实现这一点。
- 如果你需要对UI底部安全区域进行自定义设置,我建议使用代理方法
drawerPositionDidChange(drawer:bottomSafeArea:)
根据底部安全区的值修改你的UI。每当Pulley视图控制器的尺寸发生变化时,该方法将使用新的底部安全区高度被调用。示例项目就是用它来修改抽屉的'header'高度,以及调整UITableView的内容缩进。这不是自动处理的,但是添加起来应该相当简单。 - 我不建议将视图约束到抽屉内容视图控制器的安全区域。这实际上不会为安全区域工作。
- 如果你想让主视图控制器中的地图(或其他UI)在状态栏下方(或在iPhone X的耳朵上)渲染,请确保将它直接约束到父视图的'top'。你可能需要双击约束,并确保它不使用'相对于外边距'的方式约束。
- 为了与旧版本兼容,iOS 9/10应使用topLayoutGuide作为顶部安全区域。由于Pulley已经为你处理了这一点,因此你的实现不必担心iOS版本。
如果在将Pulley更新到iOS 11 SDK时遇到任何问题/疑问,请在上述信息没有解决你的问题的情况下,随时创建一个问题。
即使你已经看过示例项目,我也强烈建议查看新版本的示例项目(iOS 11之后的版本)。它可能包含有助于你的iPhone X/安全区域实现的某些内容。
存在3个协议供你使用
PulleyDelegate
:其他协议继承的协议。它通过PulleyViewController
的%.delegate属性公开。注意:如果你希望接收代理回调的对象要么是主内容,要么是抽屉内容视图控制器...不要使用%.delegate属性。继续阅读下面的其他协议。PulleyDrawerViewControllerDelegate
:包括来自PulleyDelegate
的所有方法,并添加了提供折叠和部分显示状态的自定义高度的方法。如果你的抽屉内容视图控制器希望接收与抽屉状态变化相关的回调或为上述抽屉状态提供自定义高度,则应该实现此协议。对于抽屉内容视图控制器实现此协议是可选的,但如果你不这样做,则将使用默认值。PulleyPrimaryContentControllerDelegate
:目前与PulleyDelegate
相同。然而,如果你的主内容视图控制器想接收与抽屉状态变化相关的回调,它可以实现此协议。最终可能会添加专门的方法到这个协议中。
在创建后更改视图控制器
你很可能需要在创建后更改抽屉或主视图控制器的内容。以下是如何以编程方式实现这一点的方法。
注意:如果你传入animated: true,则会得到一个微妙的交叉淡入动画。这不适用于所有视图/视图层次(特别是UIVisualEffectView)。已发出警告。
修改主内容视图控制器
if let drawer = self.parentViewController as? PulleyViewController
{
let primaryContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("PrimaryContentViewController")
drawer.setPrimaryContentViewController(primaryContent, animated: true)
}
修改抽屉内容视图控制器
if let drawer = self.parentViewController as? PulleyViewController
{
let drawerContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("DrawerContentViewController")
drawer.setDrawerContentViewController(drawerContent, animated: false)
}
自定义抽屉
- 请参阅上面的3个协议。
- 您可以通过在
PulleyViewController
上设置-topInset
属性来调整“打开”状态时屏幕顶部的内嵌。 - 您可以通过在您的'drawer'视图控制器中实现
PulleyDrawerViewControllerDelegate
来启用/禁用抽屉位置。如果需要更改它,在PulleyViewController
上调用setNeedsSupportedDrawerPositionsUpdate()
,以便根据新设置重新计算抽屉。 - 您可以通过在
PulleyViewController
上设置-drawerCornerRadius
属性来调整应用到的抽屉的圆角。 - 您可以通过在
PulleyViewController
上设置-shadowOpacity
属性来调整应用到的抽屉的阴影不透明度。 - 您可以通过在
PulleyViewController
上设置-shadowRadius
属性来调整应用到的抽屉的阴影半径。 - 您可以通过在
PulleyViewController
上设置-backgroundDimmingColor
为一个不透明颜色来调整背景暗淡颜色。 - 您可以通过在
PulleyViewController
上设置-drawerBackgroundVisualEffectView
来调整/移除背景模糊效果。 - 您可以通过在
PulleyViewController
上设置-backgroundDimmingOpacity
来调整背景暗淡颜色的alpha值。 - 您可以通过在
PulleyViewController
上调用setDrawerPosition( : )
来更改抽屉位置。 - 如果一个对象需要接收代理回调而不是视图控制器中呈现的对象之一,您可以在
PulleyViewController
上使用-delegate
属性。 PulleyViewController
的Swift接口有文档说明,如果您想查看实际的文档而不是有用的项目列表,请参考。- 您可以使用
PulleyViewController
上的initialDrawerPosition
属性来设置初始抽屉位置。 - 大多数
PulleyViewController
的设置都可以在Interface Builder中找到。选择PulleyViewController
视图控制器(不是视图)来通过IBInspectable访问它们。 - 默认情况下,Pulley将只使用“底部”显示模式(以保留向后兼容性)。如果您想使用iPad/iPhone的横屏模式,可以使用“面板”作为显示模式。如果您想让它自动切换,就像iOS上的Maps.app一样,可以设置显示模式为“自动”。
- 您可以通过将您的drawerViewController的view.layer.mask属性设置为CAShapeLayer来为Pulley抽屉应用自定义遮罩。此遮罩也将应用于Pulley中的抽屉。
- 您可以通过使用
panelCornerPlacement
属性来指定当处于“面板”显示模式时面板应显示的角落。
要求
- iOS 9.0+
- Swift 4.0+