我有一个UIViewController
只有一个UIView
,从底部覆盖了viewController的1/3。喜欢这个
我想在另一个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。但我希望它能从底部呈现动画效果。用动画解雇到底部。我怎么能这样做?
答案 0 :(得分:23)
如果你想在半个屏幕上呈现一个视图控制器,我建议使用UIPresentationController
类,它允许你设置视图控制器的框架。建议一下,此方法将停止presentingViewController
的用户交互,直到您关闭presentedViewController
为止,因此如果您希望将视图控制器显示在屏幕的一半以上,同时保留用户与{{}的交互1}}你应该使用容器视图,就像建议的其他答案一样。
这是一个UIPresentationController类的例子,可以做你想要的事情
presentingViewController
当您点击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
的{{1}}并实施
transitioningDelegate
那里的方法。不要忘记也设置
presentedViewController
presentViewController的内容
我发现UIPresentationController的用法是一种更清洁的方法。祝你好运
答案 1 :(得分:7)
我建议使用容器视图来实现此功能。看看here以供参考。
这意味着您可以在另一个ViewController中的UIView中显示嵌入的UIViewController(及其子类)。然后你可以为淡入或任何你想要的动画制作动画。
答案 2 :(得分:2)
您可以使用UIPresentationController来实现此目的。在呈现ViewController时实现UIViewControllerTransitioningDelegate方法,并从委托方法
返回PresentationControllerfunc presentationController(forPresented presented: UIViewController,
presenting: UIViewController?,
source: UIViewController) -> UIPresentationController?
您可以参考具有类似要求的answer。或者,您可以按照其他答案中的建议使用UIView动画或嵌入式视图控制器。
编辑:
在Github中找到的示例项目
https://github.com/martinnormark/HalfModalPresentationController
答案 3 :(得分:2)
有更新的代码来实现此功能。在您要呈现ViewController的操作
@IBAction func btnShow(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let pvc = storyboard.instantiateViewController(withIdentifier: "SubViewController") as! SubViewController
pvc.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(pvc, animated: true, completion: nil)
}
转到StoryBoard选择 subViewController 在其中添加 UIViews 以获取模糊效果将其约束设置为(顶部:0,底部) :0,领先:0,尾随:0)所有方面,并将其颜色更改为黑色,并根据需要设置 alpha 。之后添加其他 UIViews for options ,将其约束设置为(top: - ,Bottom:0,Leading:0,Trailing:0),设置它&#39 ; 高度约束与superview(self.View)相等的高度并将其倍数更改为0.33或0.34。 希望能帮助到你。 屏幕短片。
答案 4 :(得分:2)
有一个新类 UISheetPresentationController
,它包含一个名为 detents
的属性。这可让您指定所需的行为类型。
class ViewController: UIViewController {
@IBAction func nextButtonPressed(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "NextViewController")
if let presentationController = viewController.presentationController as? UISheetPresentationController {
presentationController.detents = [.medium()] /// set here!
}
self.present(viewController, animated: true)
}
}
结果:
只需将 presentationController.detents = [.medium()]
更改为:
presentationController.detents = [.medium(), .large()]
结果:
答案 5 :(得分:0)
如果您希望使用@DatForis答案中的功能,但又不想弄乱重写演示文稿控制器,则可以使用如下所示的全屏模式来创建一种明显的破解方法:
您可以执行的操作是像平常一样显示全屏模式,但是在设计模式时,请创建两个顶视图,一个用于模式,另一个视图放置在背景上。放在背景上的视图应该是透明的,以便可以从呈现的视图控制器中看到该视图。
然后将其消除,您将执行以下操作:
@IBOutlet weak var transparentView: UIView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(false)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(backgroundTapped(gesture:)))
transparentView.addGestureRecognizer(tapGesture)
}
@objc func backgroundTapped(gesture: UIGestureRecognizer) {
self.dismiss(animated: true, completion: nil)
}
希望/能帮助某人!
答案 6 :(得分:-1)
您还可以通过以模态方式呈现视图控制器并将演示样式属性设置为全屏,将过渡样式属性设置为覆盖垂直并将视图背景颜色的alpha分量设置为0.1来实现效果。