Details
- Xcode 12.2 (12B45b)
- Swift 5.3
Solution 1. Default transition
Idea:
Hide root view
of the ChildViewController
and add new view that will be used as the root view
.
Main logic:
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
let contentView = UIView()
contentView.backgroundColor = .lightGray
view.addSubview(contentView)
//...
}
}
Solution 1. Full sample
import UIKit
// MARK: ParentViewController
class ParentViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 50, y: 50, width: 200, height: 60))
button.setTitle("Present VC", for: .normal)
button.setTitleColor(.blue, for: .normal)
button.addTarget(self, action: #selector(touchedUpInside), for: .touchUpInside)
view.addSubview(button)
}
@objc func touchedUpInside(source: UIButton) {
let viewController = ChildViewController()
present(viewController, animated: true, completion: nil)
}
}
// MARK: ChildViewController
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
let contentView = UIView()
contentView.backgroundColor = .lightGray
view.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5).isActive = true
contentView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
contentView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
}
Solution 2. Custom transition
Idea:
Change size of the root view of the ChildViewController
.
Main logic:
ModalPresentationController
protocol ModalPresentationControllerDelegate: class {
func updateFrameOfPresentedViewInContainerView(frame: CGRect) -> CGRect
}
class ModalPresentationController: UIPresentationController {
private weak var modalPresentationDelegate: ModalPresentationControllerDelegate!
convenience
init(delegate: ModalPresentationControllerDelegate,
presentedViewController: UIViewController,
presenting presentingViewController: UIViewController?) {
self.init(presentedViewController: presentedViewController,
presenting: presentingViewController)
self.modalPresentationDelegate = delegate
}
override var frameOfPresentedViewInContainerView: CGRect {
get { modalPresentationDelegate.updateFrameOfPresentedViewInContainerView(frame: super.frameOfPresentedViewInContainerView) }
}
}
Update root view size
class ChildViewController: UIViewController {
init() {
//...
transitioningDelegate = self
modalPresentationStyle = .custom
}
}
extension ChildViewController: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController,
presenting: UIViewController?,
source: UIViewController) -> UIPresentationController? {
ModalPresentationController(delegate: self, presentedViewController: presented, presenting: presenting)
}
}
extension ChildViewController: ModalPresentationControllerDelegate {
func updateFrameOfPresentedViewInContainerView(frame: CGRect) -> CGRect {
CGRect(x: 0, y: frame.height/2, width: frame.width, height: frame.height/2)
}
}
Solution 2. Full sample
Do not forget to paste here ModalPresentationController
that defined above
import UIKit
// MARK: ParentViewController
class ParentViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 50, y: 50, width: 200, height: 60))
button.setTitle("Present VC", for: .normal)
button.setTitleColor(.blue, for: .normal)
button.addTarget(self, action: #selector(touchedUpInside), for: .touchUpInside)
view.addSubview(button)
}
@objc func touchedUpInside(source: UIButton) {
let viewController = ChildViewController()
present(viewController, animated: true, completion: nil)
}
}
// MARK: ChildViewController
class ChildViewController: UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
transitioningDelegate = self
modalPresentationStyle = .custom
view.backgroundColor = .lightGray
}
required init?(coder: NSCoder) { super.init(coder: coder) }
}
extension ChildViewController: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController,
presenting: UIViewController?,
source: UIViewController) -> UIPresentationController? {
ModalPresentationController(delegate: self, presentedViewController: presented, presenting: presenting)
}
}
extension ChildViewController: ModalPresentationControllerDelegate {
func updateFrameOfPresentedViewInContainerView(frame: CGRect) -> CGRect {
CGRect(x: 0, y: frame.height/2, width: frame.width, height: frame.height/2)
}
}