ios - 如何在半屏上呈现 ViewController

标签 ios swift uiviewcontroller swift3

我有一个 UIViewController,它只有一个 UIView,它从底部覆盖了 1/3 的 viewController。像这样

enter image description here

我想在另一个 ViewController 上显示这个 viewController。它应该从底部动画出现,并且应该消失到底部动画。

但我不希望它覆盖整个屏幕。显示它的 viewController 应该在后面可见。

这似乎是一个基本问题,但我无法完成它。有人可以给我指个方向吗?

编辑:

这是我迄今为止尝试过的。我创建了这些类

// MARK: -

class MyFadeInFadeOutTransitioning: NSObject, UIViewControllerTransitioningDelegate {
var backgroundColorAlpha: CGFloat = 0.5
var shoulDismiss = false

func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {

    let fadeInPresentAnimationController = MyFadeInPresentAnimationController()
        fadeInPresentAnimationController.backgroundColorAlpha = backgroundColorAlpha

    return fadeInPresentAnimationController
}

func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {

    let fadeOutDismissAnimationController = MyFadeOutDismissAnimationController()

    return fadeOutDismissAnimationController
}

}

// MARK: -

class MYFadeInPresentAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

let kPresentationDuration = 0.5
var backgroundColorAlpha: CGFloat?

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return kPresentationDuration
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!

    toViewController.view.backgroundColor = UIColor.clear

    let toViewFrame = transitionContext.finalFrame(for: toViewController)
    let containerView = transitionContext.containerView

    if let pickerContainerView = toViewController.view.viewWithTag(kContainerViewTag) {
        let transform = CGAffineTransform(translationX: 0.0, y: pickerContainerView.frame.size.height)
        pickerContainerView.transform = transform
    }

    toViewController.view.frame = toViewFrame
    containerView.addSubview(toViewController.view)

    UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveLinear , animations: {
        toViewController.view.backgroundColor = UIColor(white: 0.0, alpha: self.backgroundColorAlpha!)

        if let pickerContainerView = toViewController.view.viewWithTag(kContainerViewTag) {
            pickerContainerView.transform = CGAffineTransform.identity
        }

    }) { (finished) in
        transitionContext.completeTransition(true)
    }
}

}

// MARK: -

class MYFadeOutDismissAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
let kDismissalDuration = 0.15

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return kDismissalDuration
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
    let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
    let containerView = transitionContext.containerView

    containerView.addSubview(toViewController.view)
    containerView.sendSubview(toBack: toViewController.view)

    UIView.animate(withDuration: kDismissalDuration, delay: 0.0, options: .curveLinear, animations: {
        //            fromViewController.view.backgroundColor = UIColor.clearColor()
        //            if let pickerContainerView = toViewController.view.viewWithTag(kContainerViewTag) {
        //                let transform = CGAffineTransformMakeTranslation(0.0, pickerContainerView.frame.size.height)
        //                pickerContainerView.transform = transform
        //            }
        fromViewController.view.alpha = 0.0

    }) { (finished) in
        let canceled: Bool = transitionContext.transitionWasCancelled
        transitionContext.completeTransition(true)

        if !canceled {
            UIApplication.shared.keyWindow?.addSubview(toViewController.view)
        }
    }
}

}

在呈现的 viewController 中,我正在执行以下操作

var customTransitioningDelegate: MYFadeInFadeOutTransitioning? = MYFadeInFadeOutTransitioning()

    init() {
    super.init(nibName: "SomeNibName", bundle: Bundle.main)
    transitioningDelegate = customTransitioningDelegate
    modalPresentationStyle = .custom

    customTransitioningDelegate?.backgroundColorAlpha = 0.0
} 

它确实显示了 viewController,我也可以看到背景 viewController。但我希望它从底部用动画呈现。并用动画解雇到底部。我该怎么做?

最佳答案

如果你想在半个屏幕上显示一个 View Controller ,我建议使用 UIPresentationController 类,它允许你在显示 View Controller 时设置它的框架。忠告,此方法将停止 presentingViewController 的用户交互,直到您关闭 presentedViewController,因此如果您想在保留屏幕的一半以上显示 View Controller 用户与 presentingViewController 的交互你应该像建议的其他答案一样使用容器 View 。 这是一个 UIPresentationController 类的示例,它可以执行您想要的操作

import UIKit
class ForgotPasswordPresentationController: UIPresentationController{
    let blurEffectView: UIVisualEffectView!
    var tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer()
    func dismiss(){
        self.presentedViewController.dismiss(animated: true, completion: nil)
    }
    override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
        let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
        blurEffectView = UIVisualEffectView(effect: blurEffect)
        super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
        tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismiss))
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        self.blurEffectView.isUserInteractionEnabled = true
        self.blurEffectView.addGestureRecognizer(tapGestureRecognizer)
    }
    override var frameOfPresentedViewInContainerView: CGRect{
        return CGRect(origin: CGPoint(x: 0, y: self.containerView!.frame.height/2), size: CGSize(width: self.containerView!.frame.width, height: self.containerView!.frame.height/2))
    }
    override func dismissalTransitionWillBegin() {
        self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
            self.blurEffectView.alpha = 0
        }, completion: { (UIViewControllerTransitionCoordinatorContext) in
            self.blurEffectView.removeFromSuperview()
        })
    }
    override func presentationTransitionWillBegin() {
        self.blurEffectView.alpha = 0
        self.containerView?.addSubview(blurEffectView)
        self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
            self.blurEffectView.alpha = 1
        }, completion: { (UIViewControllerTransitionCoordinatorContext) in

        })
    }
    override func containerViewWillLayoutSubviews() {
        super.containerViewWillLayoutSubviews()
        presentedView!.layer.masksToBounds = true
        presentedView!.layer.cornerRadius = 10
    }
    override func containerViewDidLayoutSubviews() {
        super.containerViewDidLayoutSubviews()
        self.presentedView?.frame = frameOfPresentedViewInContainerView
        blurEffectView.frame = containerView!.bounds
    }
}

当您在 presentedViewController 框架外点击时,这还会添加模糊 View 和关闭点击。您需要设置 presentedViewControllertransitioningDelegate 并实现

presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController?

里面有方法。不要忘记也设置 modalPresentationStyle = .custom 呈现的 ViewController

我发现使用 UIPresentationController 是一种更简洁的方法。祝你好运

关于ios - 如何在半屏上呈现 ViewController,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42106980/

相关文章:

ios - SwiftUI 列表中所有行的高度相同

ios - 将谷歌自动完成限制为仅限城市和国家 iOS Swift

ios - 合并两个不同大小的 UIImageView

swift - 如何让SCNNode在用户旋转时水平旋转

ios - 关于自动布局

ios - 实例化 ViewController 并将其从 Swift 中的字符串转换为类

ios - 如何将 nil 类型传递给 Swift 中的参数?

ios - 如何在 iOS 中的表格 View 底部制作固定单元格?

ios - 在 iPad 上打开新 View ,并关闭现有 View 。

ios - 当我关闭模态呈现的 viewController 时,我的 GameScene 卡住