如何在半屏上呈现 ViewController [英] How to present a ViewController on Half screen
问题描述
我有一个 UIViewController
,它只有一个 UIView
,它从底部覆盖了 viewController 的 1/3.像这样
I have a UIViewController
which have only a UIView
which covers 1/3 of the viewController from bottom. Like this
我想在另一个 ViewController 上展示这个 viewController.它应该从底部动画出现,它应该消失到底部动画.
I want to present this viewController on an other ViewController. It should appear from bottom animated and it should dismiss to the bottom animated.
但我不希望它覆盖整个屏幕.呈现它的 viewController 应该在后面可见.
But I do not want it to cover the whole Screen. The viewController on which it is presented should be visible in the back.
这似乎是一个基本问题,但我无法完成.有人可以指点我的方向吗?
It seems like a basic question But I am unable to get it done. Can someone please point me to the direction ?
这是我迄今为止尝试过的.我已经创建了这些类
This is what I have tried so Far. I have created these classes
// 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 中,我的操作如下
And in the viewController which is being presented, I am doing as follows
var customTransitioningDelegate: MYFadeInFadeOutTransitioning? = MYFadeInFadeOutTransitioning()
init() {
super.init(nibName: "SomeNibName", bundle: Bundle.main)
transitioningDelegate = customTransitioningDelegate
modalPresentationStyle = .custom
customTransitioningDelegate?.backgroundColorAlpha = 0.0
}
它确实显示了 viewController,我也可以看到背景 viewController.但我希望它通过动画从底部呈现.并用动画解散到底部.我该怎么做?
It do present the viewController and I can see the background viewController as well. But I want it to be presented from bottom with animation. And dismiss to bottom with animation. How can I do that ?
推荐答案
如果你想在半个屏幕上显示一个视图控制器,我建议使用 UIPresentationController
类,它允许你设置框架视图控制器出现时的视图.忠告,此方法将停止 presentingViewController
的用户交互,直到您关闭 presentedViewController
,因此如果您想在保留一半屏幕的同时显示视图控制器与 presentingViewController
的用户交互,您应该像建议的其他答案一样使用容器视图.这是一个 UIPresentationController 类的例子,它可以做你想要的
If you want to present a view controller over half a screen I suggest using the UIPresentationController
class it will allow you to set the frame of the view controller when it is presented. A word of advice, this method will stop the user interaction of the presentingViewController
until you dismiss the presentedViewController
, so if you want to show the view controller over half the screen while retaining user interaction with the presentingViewController
you should use container views like the other answers suggested.
This is an example of a UIPresentationController class that does what you want
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
框架外轻按时,这还会添加一个模糊视图和一个轻按以关闭.你需要设置presentedViewController
的transitioningDelegate
并实现
This also adds a blur view and a tap to dismiss when you tap outside the presentedViewController
frame. You need to set the transitioningDelegate
of the presentedViewController
and implement the
presentationController(forPresentedpresented: UIViewController,presenting: UIViewController?, source: UIViewController) ->UIPresentationController?
方法在那里.别忘了也设置modalPresentationStyle = .custom
呈现的ViewController
method in there. Don't forget to also set
modalPresentationStyle = .custom
of the presentedViewController
我发现使用 UIPresentationController 是一种更简洁的方法.祝你好运
I find the usage of the UIPresentationController to be a much cleaner approach. Good luck
这篇关于如何在半屏上呈现 ViewController的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!