我使用UISplitViewController
为我的应用程序创建一个侧边栏-它的风格是.doubleColumn
,我离开preferredDisplayMode
设置为默认的自动行为。它看起来就像照片应用程序,在横向中,主列和副列都是可见的,而在纵向中,只有副列是可见的(有一个后退按钮来显示主列的顶部)。
在横屏状态下,如果用户轻按侧边栏按钮隐藏主列(或通过键盘快捷键切换),旋转到竖屏状态,然后再旋转回横屏状态,则侧边栏将不被隐藏。这与照片应用不同,在照片应用中,一旦用户隐藏了侧边栏,它就会一直隐藏起来,直到他们取消隐藏(即使在应用启动时也是如此)。我想达到同样的行为。
要做到这一点,我想我可以使用委托函数splitViewController(_willChangeTo:)
并检查新的显示模式是否为.secondaryOnly
,旧的显示模式是否为.oneBesideSecondary
,然后我将在UserDefaults
中存储bool,指示用户隐藏了侧边栏,我将preferredDisplayMode
设置为.secondaryOnly
以保留其隐藏状态之间的旋转。在下次应用启动时,我会检查这是否正确,并将preferredDisplayMode
设置为.secondaryOnly
。(同样地,当从次要到次要旁边的一个时,将标志和首选显示模式重置为.automatic
。)问题是当你旋转设备时委派函数会以相同的状态被调用,这会导致我不恰当地设置标志和首选显示模式。我只需要在用户手动切换侧边栏时这样做,而不是当系统由于可用空间的变化而隐藏它时,例如
如何做到这一点?
我把这个问题带到WWDC的实验室,在那里我得到了一个很好的解决方案!为了保持侧边栏在旋转之间的隐藏状态,您可以实现viewWillTransition(to:with:)
来设置一个标志,如systemIsChangingViewSize
为true
,调用super
,然后将其设置为false
。在委托函数.splitViewController(_:willChangeTo:)
中检查此标志。当系统启动大小更改时,它将是true
;当用户通过切换侧边栏启动大小更改时,它将是false
。只有当它是false
时,才执行问题中提到的逻辑,以保持用户期望的侧边栏可见性。
private var systemIsChangingViewSize = false
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
systemIsChangingViewSize = true
super.viewWillTransition(to: size, with: coordinator)
systemIsChangingViewSize = false
}
func splitViewController(_ svc: UISplitViewController, willChangeTo displayMode: UISplitViewController.DisplayMode) {
navigationDelegate?.navigationSplitViewController(self, willChangeDisplayMode: displayMode)
if !systemIsChangingViewSize {
if displayMode == .secondaryOnly && svc.displayMode == .oneBesideSecondary {
DispatchQueue.main.async {
svc.preferredDisplayMode = .secondaryOnly
}
} else if displayMode == .oneBesideSecondary && svc.displayMode == .secondaryOnly {
DispatchQueue.main.async {
svc.preferredDisplayMode = .automatic
}
}
}
}