更改模态视图控制器的大小

15

当用户点击按钮时,我希望我的modalViewController以一个小正方形出现在屏幕中央(此时您仍然可以看到原始视图控制器在背景中)。

我在stackoverflow上找到的几乎每个答案都使用storyboard来创建模态视图控制器,但是我已经通过找到的所有内容走到了这一步。

当您点击应该显示模态视图的按钮时,将调用此函数:

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)。

显然,我在这里漏了一步,但我想尽可能地以编程方式完成所有操作,因为在我的项目中完全没有使用故事板(除了设置开场控制器)。

提前感谢您的帮助!


你需要使用自定义演示控制器。例如在这里:https://github.com/mattneub/custom-alert-view-iOS7 - matt
是的,您需要覆盖frameOfPresentedViewInContainerView以返回所需的CGRect。这需要从UIPresentationController创建自定义呈现控制器。 - Cameron Porter
2个回答

40

modalPresentationStyle文档告诉我们:

在水平紧凑的环境下,模态视图控制器总是全屏显示。

因此,如果您想在纵向模式下的 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
    }
}

这只是自定义转场的冰山一角。您可以指定动画控制器(用于自定义动画),使背景变暗/模糊等。请参阅WWDC 2013 使用视图控制器进行自定义转场视频,了解有关自定义转场的基础知识,以及WWDC 2014视频iOS 8中的视图控制器改进演示控制器内部深入了解演示控制器的详细信息。


例如,当您呈现模态视图时,您可能希望调暗和模糊背景。因此,您可以添加presentationTransitionWillBegindismissalTransitionWillBegin来动画显示这个“调暗”视图。{{请注意保留代码标签和引号}}
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()
        })
    }
}

这将产生:

enter image description here


如何在使用UIPresentationController呈现视图控制器后更改其大小?我想在呈现的视图控制器内放置一个UIButton,当点击它时,我想改变该呈现视图控制器的大小。 - JAHelia

9

您可以将视图控制器的背景颜色设置为透明,然后在视图控制器中央创建一个视图,并将模态呈现样式设置为.overCurrentContext,这样您就可以从后面看到视图控制器。

以下是编辑过的示例:

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)
}

以下是您提供的视图控制器类:

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)
    }
}

你可以从这里开始构建:为“较小”的视图控制器添加你想要的外观 :)

就我个人而言,虽然自定义动画和演示控制器可以让我们完全掌控自定义转换,但你的答案恰恰是我在生产应用程序中所采用的方法。这是一个不错、简单的方法!如果你喜欢的话,你也可以完全在故事板中完成它。 - Rob
这是一个非常简单的方法。它运行良好,甚至可以在iOS 13页面表上运行! - AnthonyMDev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接