更改模态视图控制器的大小
Changing the size of a modal view controller
一旦用户点击一个按钮,我希望我的 modalViewController 在屏幕中间显示为一个小方块(您仍然可以在背景中看到原始视图控制器)。
我在 Whosebug 上找到的几乎每个答案都使用情节提要来创建模态视图控制器,但我已经找到了这么多。
当您点击应该调出模态视图的按钮时,将调用此函数:
func didTapButton() {
let modalViewController = ModalViewController()
modalViewController.definesPresentationContext = true
modalViewController.modalPresentationStyle = .overCurrentContext
navigationController?.present(modalViewController, animated: true, completion: nil)
}
并且 modalViewController 包含:
import UIKit
class ModalViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
view.isOpaque = false
self.preferredContentSize = CGSize(width: 100, height: 100)
}
}
根据我找到的答案,我的印象是如果我设置 preferredContentSize = CGSize(width: 100, height: 100)
,那么模态视图控制器将变为 100px x 100px。
但是,视图控制器占据了整个屏幕(标签栏除外,因为我设置了modalViewController.modalPresentationStyle = .overCurrentContext
我显然在这里遗漏了一步,但我想以编程方式完成所有事情,因为我在我的项目中根本没有使用 Storyboard(设置打开控制器除外)
在此先感谢您的帮助!!
你可以设置view controller的背景色为clear,然后在view controller的中间创建一个view,设置modal presentation style为.overCurrentContext,这样你就可以从后面看到view controller了。
这里是编辑后的例子:
func didTapButton() {
let modalViewController = storyboard?.instantiateViewController(withIdentifier: "ModalViewController") as! ModalViewController
modalViewController.modalPresentationStyle = .overCurrentContext
modalViewController.modalTransitionStyle = .crossDissolve // this will look more natural for this situation
navigationController?.present(modalViewController, animated: true, completion: nil)
}
这是您呈现的视图控制器class:
import UIKit
class ModalViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
createTheView()
}
private func createTheView() {
let xCoord = self.view.bounds.width / 2 - 50
let yCoord = self.view.bounds.height / 2 - 50
let centeredView = UIView(frame: CGRect(x: xCoord, y: yCoord, width: 100, height: 100))
centeredView.backgroundColor = .blue
self.view.addSubview(centeredView)
}
}
您已经可以从这里构建:为 "smaller" 视图控制器添加您想要的外观 :)
modalPresentationStyle
documentation告诉我们
In a horizontally compact environment, modal view controllers are always presented full-screen.
因此,如果您想在 iPhone 纵向模式下执行此操作,则必须指定 .custom
演示样式并让您的过渡委托提供自定义演示控制器。
我个人会让我的第二个视图控制器管理它自己的呈现参数,所以我的第一个视图控制器可能只会:
class FirstViewController: UIViewController {
@IBAction func didTapButton(_ sender: Any) {
let controller = storyboard!.instantiateViewController(withIdentifier: "SecondViewController")
present(controller, animated: true)
}
}
然后我的第二个视图控制器将指定一个自定义转换并指定一个自定义转换委托:
class SecondViewController: UIViewController {
private var customTransitioningDelegate = TransitioningDelegate()
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
}
private extension SecondViewController {
func configure() {
modalPresentationStyle = .custom
modalTransitionStyle = .crossDissolve // use whatever transition you want
transitioningDelegate = customTransitioningDelegate
}
}
然后那个转换委托将出售自定义呈现控制器:
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return PresentationController(presentedViewController: presented, presenting: presenting)
}
}
并且该演示控制器将指定其大小:
class PresentationController: UIPresentationController {
override var frameOfPresentedViewInContainerView: CGRect {
let bounds = presentingViewController.view.bounds
let size = CGSize(width: 200, height: 100)
let origin = CGPoint(x: bounds.midX - size.width / 2, y: bounds.midY - size.height / 2)
return CGRect(origin: origin, size: size)
}
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
presentedView?.autoresizingMask = [
.flexibleTopMargin,
.flexibleBottomMargin,
.flexibleLeftMargin,
.flexibleRightMargin
]
presentedView?.translatesAutoresizingMaskIntoConstraints = true
}
}
这只是自定义转场的冰山一角。您可以指定动画控制器(用于自定义动画)、dim/blur 背景等。请参阅 WWDC 2013 Custom Transitions Using View Controllers video for a primer on custom transitions, and WWDC 2014 videos View Controller Advancements in iOS 8 and A Look Inside Presentation Controllers 深入了解演示控制器。
例如,您可能希望在呈现模态视图时使背景变暗和模糊。所以你可以添加 presentationTransitionWillBegin
和 dismissalTransitionWillBegin
来动画这个“变暗”视图的演示:
class PresentationController: UIPresentationController {
...
let dimmingView: UIView = {
let dimmingView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
dimmingView.translatesAutoresizingMaskIntoConstraints = false
return dimmingView
}()
override func presentationTransitionWillBegin() {
super.presentationTransitionWillBegin()
let superview = presentingViewController.view!
superview.addSubview(dimmingView)
NSLayoutConstraint.activate([
dimmingView.leadingAnchor.constraint(equalTo: superview.leadingAnchor),
dimmingView.trailingAnchor.constraint(equalTo: superview.trailingAnchor),
dimmingView.bottomAnchor.constraint(equalTo: superview.bottomAnchor),
dimmingView.topAnchor.constraint(equalTo: superview.topAnchor)
])
dimmingView.alpha = 0
presentingViewController.transitionCoordinator?.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 1
}, completion: nil)
}
override func dismissalTransitionWillBegin() {
super.dismissalTransitionWillBegin()
presentingViewController.transitionCoordinator?.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 0
}, completion: { _ in
self.dimmingView.removeFromSuperview()
})
}
}
产生:
一旦用户点击一个按钮,我希望我的 modalViewController 在屏幕中间显示为一个小方块(您仍然可以在背景中看到原始视图控制器)。
我在 Whosebug 上找到的几乎每个答案都使用情节提要来创建模态视图控制器,但我已经找到了这么多。
当您点击应该调出模态视图的按钮时,将调用此函数:
func didTapButton() {
let modalViewController = ModalViewController()
modalViewController.definesPresentationContext = true
modalViewController.modalPresentationStyle = .overCurrentContext
navigationController?.present(modalViewController, animated: true, completion: nil)
}
并且 modalViewController 包含:
import UIKit
class ModalViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
view.isOpaque = false
self.preferredContentSize = CGSize(width: 100, height: 100)
}
}
根据我找到的答案,我的印象是如果我设置 preferredContentSize = CGSize(width: 100, height: 100)
,那么模态视图控制器将变为 100px x 100px。
但是,视图控制器占据了整个屏幕(标签栏除外,因为我设置了modalViewController.modalPresentationStyle = .overCurrentContext
我显然在这里遗漏了一步,但我想以编程方式完成所有事情,因为我在我的项目中根本没有使用 Storyboard(设置打开控制器除外)
在此先感谢您的帮助!!
你可以设置view controller的背景色为clear,然后在view controller的中间创建一个view,设置modal presentation style为.overCurrentContext,这样你就可以从后面看到view controller了。
这里是编辑后的例子:
func didTapButton() {
let modalViewController = storyboard?.instantiateViewController(withIdentifier: "ModalViewController") as! ModalViewController
modalViewController.modalPresentationStyle = .overCurrentContext
modalViewController.modalTransitionStyle = .crossDissolve // this will look more natural for this situation
navigationController?.present(modalViewController, animated: true, completion: nil)
}
这是您呈现的视图控制器class:
import UIKit
class ModalViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
createTheView()
}
private func createTheView() {
let xCoord = self.view.bounds.width / 2 - 50
let yCoord = self.view.bounds.height / 2 - 50
let centeredView = UIView(frame: CGRect(x: xCoord, y: yCoord, width: 100, height: 100))
centeredView.backgroundColor = .blue
self.view.addSubview(centeredView)
}
}
您已经可以从这里构建:为 "smaller" 视图控制器添加您想要的外观 :)
modalPresentationStyle
documentation告诉我们
In a horizontally compact environment, modal view controllers are always presented full-screen.
因此,如果您想在 iPhone 纵向模式下执行此操作,则必须指定 .custom
演示样式并让您的过渡委托提供自定义演示控制器。
我个人会让我的第二个视图控制器管理它自己的呈现参数,所以我的第一个视图控制器可能只会:
class FirstViewController: UIViewController {
@IBAction func didTapButton(_ sender: Any) {
let controller = storyboard!.instantiateViewController(withIdentifier: "SecondViewController")
present(controller, animated: true)
}
}
然后我的第二个视图控制器将指定一个自定义转换并指定一个自定义转换委托:
class SecondViewController: UIViewController {
private var customTransitioningDelegate = TransitioningDelegate()
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
}
private extension SecondViewController {
func configure() {
modalPresentationStyle = .custom
modalTransitionStyle = .crossDissolve // use whatever transition you want
transitioningDelegate = customTransitioningDelegate
}
}
然后那个转换委托将出售自定义呈现控制器:
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return PresentationController(presentedViewController: presented, presenting: presenting)
}
}
并且该演示控制器将指定其大小:
class PresentationController: UIPresentationController {
override var frameOfPresentedViewInContainerView: CGRect {
let bounds = presentingViewController.view.bounds
let size = CGSize(width: 200, height: 100)
let origin = CGPoint(x: bounds.midX - size.width / 2, y: bounds.midY - size.height / 2)
return CGRect(origin: origin, size: size)
}
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
presentedView?.autoresizingMask = [
.flexibleTopMargin,
.flexibleBottomMargin,
.flexibleLeftMargin,
.flexibleRightMargin
]
presentedView?.translatesAutoresizingMaskIntoConstraints = true
}
}
这只是自定义转场的冰山一角。您可以指定动画控制器(用于自定义动画)、dim/blur 背景等。请参阅 WWDC 2013 Custom Transitions Using View Controllers video for a primer on custom transitions, and WWDC 2014 videos View Controller Advancements in iOS 8 and A Look Inside Presentation Controllers 深入了解演示控制器。
例如,您可能希望在呈现模态视图时使背景变暗和模糊。所以你可以添加 presentationTransitionWillBegin
和 dismissalTransitionWillBegin
来动画这个“变暗”视图的演示:
class PresentationController: UIPresentationController {
...
let dimmingView: UIView = {
let dimmingView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
dimmingView.translatesAutoresizingMaskIntoConstraints = false
return dimmingView
}()
override func presentationTransitionWillBegin() {
super.presentationTransitionWillBegin()
let superview = presentingViewController.view!
superview.addSubview(dimmingView)
NSLayoutConstraint.activate([
dimmingView.leadingAnchor.constraint(equalTo: superview.leadingAnchor),
dimmingView.trailingAnchor.constraint(equalTo: superview.trailingAnchor),
dimmingView.bottomAnchor.constraint(equalTo: superview.bottomAnchor),
dimmingView.topAnchor.constraint(equalTo: superview.topAnchor)
])
dimmingView.alpha = 0
presentingViewController.transitionCoordinator?.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 1
}, completion: nil)
}
override func dismissalTransitionWillBegin() {
super.dismissalTransitionWillBegin()
presentingViewController.transitionCoordinator?.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 0
}, completion: { _ in
self.dimmingView.removeFromSuperview()
})
}
}
产生: