在iOS开发中,presentModalViewController是一个非常常用的方法,它可以用来将一个视图控制器(ViewController)以模态的方式展示在另一个视图控制器上面。这个方法广泛应用于多种场景,例如展示警告框、登陆对话框、下拉菜单、详情页等等。但是,对于一些开发新手来说,presentModalViewController的使用可能不够熟悉,存在一些常见的问题,本文将探讨这些问题以及如何更好地掌握presentModalViewController的用法和技巧。
一、presentModalViewController的基本用法
使用presentModalViewController非常简单,只需要在当前视图控制器(sourceViewController)中调用presentModalViewController,将要展示的视图控制器(destinationViewController)以模态的方式展示即可。示例代码如下:
```
destinationViewController.modalPresentationStyle = .fullScreen
sourceViewController.present(destinationViewController, animated: true, completion: nil)
```
其中的modalPresentationStyle参数是模态展示的风格,可以设置成全屏(.fullScreen)、Form表单(.formSheet)等多种样式。
二、正确的视图控制器层级关系
在使用presentModalViewController时,要确保正确的视图控制器层级关系,避免出现一些常见的问题。这里主要讨论两个层级关系,分别是导航控制器(UINavigationController)和标签控制器(UITabBarController)。
1. 导航控制器
当你的应用有多个视图控制器需要以模态的方式展示时,可能会遇到以下问题:展示的视图控制器没有导航栏或者导航栏不可用。
这个问题的原因是,presentModalViewController并不会将展示的视图控制器加入到导航栈中,因此需要将展示的视图控制器包装成一个导航控制器。示例代码如下:
```
let navController = UINavigationController(rootViewController: destinationViewController)
sourceViewController.present(navController, animated: true, completion: nil)
```
上面的代码中,我们将destinationViewController包装成了一个导航控制器,并调用presentModalViewController方法展示。
2. 标签控制器
标签控制器是同时展示多个视图控制器的常用方式。当你的应用中包含了标签控制器,并需要对某个标签里的视图进行模态展示时,也会遇到一些问题:presentModalViewController会在当前选中的标签下展示视图,而非所要展示的标签。
这个问题的解决方式比较简单,只需要在展示前,将所要展示的标签设为当前选中标签即可。示例代码如下:
```
tabBarController.selectedIndex = desiredTabIndex
sourceViewController.present(destinationViewController, animated: true, completion: nil)
```
上面的代码中,我们将wantedTabIndex设为要展示的标签,然后再调用presentModalViewController方法展示。
三、正确的释放presented view controller
当使用presentModalViewController展示视图控制器后,需要在合适的时机释放presented view controller,避免出现内存泄漏问题。释放presented view controller的时机有两个,一个是在视图完成展示后,一个是在视图完成隐藏后。
1. 完成展示后释放
当我们使用presentModalViewController展示一个视图控制器时,需要在其展示完成后释放,避免内存泄漏。可以利用present(completion)方法,参数为一个闭包,代表完成展示后要做的事情(如将presented view controller置nil)。示例代码如下:
```
sourceViewController.present(destinationViewController, animated: true) {
// ViewController is presented
completionHandler?()
}
```
上面的代码中,completionHandler是展示完成后的操作,可以在其中做一些释放资源的工作。
2. 完成隐藏后释放
当presented view controller的任务执行完毕,需要将其dismiss掉,这个时候也需要注意释放问题。与上面类似,可以在dismiss的completion中释放presented view controller。示例代码如下:
```
destinationViewController.dismiss(animated: true) {
// ViewController is dismissed
completionHandler?()
}
```
同样地,completionHandler也可以是你想要执行的任何操作。
四、动画选项的使用
除了基本的present方法,presentModalViewController提供了一些动画选项,可用于自定义展示、隐藏的效果。这些动画选项包括:
1. UIModalTransitionStyle
UIModalTransitionStyle是控制展示效果的选项,可以控制presented view controller出现的方式,如从底部弹出(.coverVertical)、淡入淡出(.crossDissolve)等。示例代码如下:
```
destinationViewController.modalTransitionStyle = .coverVertical
sourceViewController.present(destinationViewController, animated: true, completion: nil)
```
2. UIModalPresentationStyle
UIModalPresentationStyle是控制展示形式的选项,可以控制presented view controller的展示方式,如覆盖(.fullScreen)、表单(.formSheet)等。示例代码如下:
```
destinationViewController.modalPresentationStyle = .overFullScreen
sourceViewController.present(destinationViewController, animated: true, completion: nil)
```
3. UIModalPresentationCapturesStatusBarAppearance
UIModalPresentationCapturesStatusBarAppearance是一个布尔值选项,可以让presented view controller展示时,使状态栏的外观与展示它的视图控制器保持一致。示例代码如下:
```
destinationViewController.modalPresentationCapturesStatusBarAppearance = true
sourceViewController.present(destinationViewController, animated: true, completion: nil)
```
以上三种动画选项可以自由组合使用,以达到更好的效果。
五、presentModalViewController的调用方式
除了基本的present方法,presentModalViewController还有一些其他的调用方式,可以根据不同的场景选择不同的调用方式。
1. 使用UIViewController的方法
如果你的场景是当前视图控制器需要展示一个新的视图控制器,可以使用UIViewController的present方法,示例代码如下:
```
let destinationViewController = UIViewController()
destinationViewController.modalPresentationStyle = .fullScreen
sourceViewController.present(destinationViewController, animated: true, completion: nil)
```
2. 使用UIWindow的方法
如果你的场景是展示全屏的视图(如启动界面),可以使用UIWindow的方法,示例代码如下:
```
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = destinationViewController
window.windowLevel = UIWindow.Level.alert + 1
window.makeKeyAndVisible()
destinationViewController.view.alpha = 0
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseInOut], animations: {
destinationViewController.view.alpha = 1
}, completion: nil)
```
上面的代码中,我们首先创建了一个新的UIWindow(window),将destinationViewController设置为窗口的rootViewController,然后展示窗口。最后使用UIView.animate将presented view controller渐隐渐出地展示出来,在completion中可以做一些释放资源的工作。
六、技巧和注意事项
1. 在展示前,要确保destinationViewController已经初始化完成。如果在展示过程中,需要动态地生成destinationViewController,可以使用闭包方式来生成,保证在需要时才进行初始化。
2. 在展示过程中,要禁止用户操作父视图控制器上的控件,防止出现多次点击等问题。
3. 在presentModalViewController结束后,要对父视图控制器上的控件重新启用。
4. 在释放presented view controller时,要在合适的时机进行。如果释放过早,可能会出现视图未展示完整就被释放的问题;如果释放过晚,可能会导致内存泄漏的问题。
5. 在选择动画选项时,要注意不同选项的兼容性和效果,以达到最佳的展示效果。
总的来说,presentModalViewController是iOS开发中非常重要的方法,掌握它的用法和技巧,可以让我们更好地开发出高质量的应用。在实际的开发过程中,我们还需要根据具体的场景灵活使用这个方法,以达到最好的效果。