使用 UIModalPresentationStyleCurrentContext 呈现视图控制器时的布局问题
Layout issues when presenting a view controller with UIModalPresentationStyleCurrentContext
我 运行 遇到了与 UISplitViewController
和 iPad 上的模态视图控制器有关的问题,所以我尝试在一个小项目中重现该问题,看看我是否可以弄清楚发生了什么事。不幸的是,问题似乎仍然存在,但我不明白为什么。
我在下面包含了一个非常小的、完整的 Swift 程序,它重现了这个问题。基本上,如果您 运行 在 iPad 上的新 Swift iOS 项目中编写该代码,您将看到以下行为:
该应用将从以下 UI 开始:
如果我点击 Present,一个新的模态控制器将出现在拆分控制器的细节侧。如果我点击那个模态控制器上的关闭,我将 return 到相同的初始界面,一切都很好。
但是,如果我点击 Present,然后在出现的模态控制器上点击 Present(所以我在原始详细信息视图上有两个模态控制器),然后关闭最上面的一个,RightViewController
接管整个屏幕,消除拆分视图控制器:
我整个下午都在为这个问题苦苦思索。有什么我想念的吗?
这是示例应用程序的完整源代码:
import UIKit
class RightController: UIViewController {
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.title = "Right"
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
super.loadView()
let label = UILabel(frame: CGRect(x: 0, y: 100, width: 100, height: 20))
label.text = "Top Left"
self.view.addSubview(label)
let presButton = UIBarButtonItem(title: "Present", style: .Plain, target: self, action: Selector("present:"))
self.navigationItem.rightBarButtonItem = presButton
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Dismiss", style: .Plain, target: self, action: Selector("dismiss:"))
}
func dismiss(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func present(sender: AnyObject) {
let rc = RightController()
let nav = UINavigationController(rootViewController: rc)
nav.modalPresentationStyle = .CurrentContext
self.presentViewController(nav, animated: true, completion: nil)
}
}
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let splitViewController = UISplitViewController()
splitViewController.delegate = self
let nav1 = UINavigationController(rootViewController: UIViewController())
nav1.title = "Left"
let nav2 = UINavigationController(rootViewController: RightController())
splitViewController.viewControllers = [nav1, nav2]
self.window!.rootViewController = splitViewController
return true
}
}
extension AppDelegate: UISplitViewControllerDelegate {
func splitViewController(svc: UISplitViewController, shouldHideViewController vc: UIViewController, inOrientation orientation: UIInterfaceOrientation) -> Bool {
return false
}
}
编辑:循环通过设备的方向会导致拆分视图控制器正确重绘自身,至少在再次按下关闭之前是这样。
EDIT:如果我在 iOS 8 中使用新的 .OverCurrentContext
演示风格,我也可以让它工作。但是,我不能放弃与 iOS 7 的兼容性,所以我需要一个不同的解决方案。
我有一个可行的解决方案,但我会第一个承认,它确实感觉有点老套。我认为您的问题很大一部分源于 .CurrentContext
的变化,经过一些测试后我发现它在 iOS 7 和 8+ 中的功能不同。因此,如果您根据 iOS 版本选择合适的样式,一切都会按预期进行:
var presStyle: UIModalPresentationStyle = (UIDevice.currentDevice().systemVersion as NSString).integerValue == 7 ? .CurrentContext : .OverCurrentContext
nav.modalPresentationStyle = presStyle
我 运行 遇到了与 UISplitViewController
和 iPad 上的模态视图控制器有关的问题,所以我尝试在一个小项目中重现该问题,看看我是否可以弄清楚发生了什么事。不幸的是,问题似乎仍然存在,但我不明白为什么。
我在下面包含了一个非常小的、完整的 Swift 程序,它重现了这个问题。基本上,如果您 运行 在 iPad 上的新 Swift iOS 项目中编写该代码,您将看到以下行为:
该应用将从以下 UI 开始:
如果我点击 Present,一个新的模态控制器将出现在拆分控制器的细节侧。如果我点击那个模态控制器上的关闭,我将 return 到相同的初始界面,一切都很好。
但是,如果我点击 Present,然后在出现的模态控制器上点击 Present(所以我在原始详细信息视图上有两个模态控制器),然后关闭最上面的一个,RightViewController
接管整个屏幕,消除拆分视图控制器:
我整个下午都在为这个问题苦苦思索。有什么我想念的吗?
这是示例应用程序的完整源代码:
import UIKit
class RightController: UIViewController {
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.title = "Right"
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
super.loadView()
let label = UILabel(frame: CGRect(x: 0, y: 100, width: 100, height: 20))
label.text = "Top Left"
self.view.addSubview(label)
let presButton = UIBarButtonItem(title: "Present", style: .Plain, target: self, action: Selector("present:"))
self.navigationItem.rightBarButtonItem = presButton
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Dismiss", style: .Plain, target: self, action: Selector("dismiss:"))
}
func dismiss(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func present(sender: AnyObject) {
let rc = RightController()
let nav = UINavigationController(rootViewController: rc)
nav.modalPresentationStyle = .CurrentContext
self.presentViewController(nav, animated: true, completion: nil)
}
}
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let splitViewController = UISplitViewController()
splitViewController.delegate = self
let nav1 = UINavigationController(rootViewController: UIViewController())
nav1.title = "Left"
let nav2 = UINavigationController(rootViewController: RightController())
splitViewController.viewControllers = [nav1, nav2]
self.window!.rootViewController = splitViewController
return true
}
}
extension AppDelegate: UISplitViewControllerDelegate {
func splitViewController(svc: UISplitViewController, shouldHideViewController vc: UIViewController, inOrientation orientation: UIInterfaceOrientation) -> Bool {
return false
}
}
编辑:循环通过设备的方向会导致拆分视图控制器正确重绘自身,至少在再次按下关闭之前是这样。
EDIT:如果我在 iOS 8 中使用新的 .OverCurrentContext
演示风格,我也可以让它工作。但是,我不能放弃与 iOS 7 的兼容性,所以我需要一个不同的解决方案。
我有一个可行的解决方案,但我会第一个承认,它确实感觉有点老套。我认为您的问题很大一部分源于 .CurrentContext
的变化,经过一些测试后我发现它在 iOS 7 和 8+ 中的功能不同。因此,如果您根据 iOS 版本选择合适的样式,一切都会按预期进行:
var presStyle: UIModalPresentationStyle = (UIDevice.currentDevice().systemVersion as NSString).integerValue == 7 ? .CurrentContext : .OverCurrentContext
nav.modalPresentationStyle = presStyle