Uma*_*zal 16 uiviewcontroller ios swift swift3
我有一个从底部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)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在正在呈现的viewController中,我正在做如下
var customTransitioningDelegate: MYFadeInFadeOutTransitioning? = MYFadeInFadeOutTransitioning()
init() {
super.init(nibName: "SomeNibName", bundle: Bundle.main)
transitioningDelegate = customTransitioningDelegate
modalPresentationStyle = .custom
customTransitioningDelegate?.backgroundColorAlpha = 0.0
}
Run Code Online (Sandbox Code Playgroud)
它确实呈现了viewController,我也可以看到背景viewController.但我希望它能从底部呈现动画效果.用动画解雇到底部.我怎样才能做到这一点 ?
Sre*_*tan 38
使用UISheetPresentationController
let yourVC = YourViewController()
if let sheet = yourVC.sheetPresentationController {
sheet.detents = [.medium()]
}
self.present(yourVC, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)
在这里阅读更多内容
使用UIPresentationController,它也适用于 ios 15。但如果您的应用程序仅支持 iOS 15,请使用上面的代码。
import UIKit
class PresentationController: UIPresentationController {
let blurEffectView: UIVisualEffectView!
var tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer()
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
let blurEffect = UIBlurEffect(style: .dark)
blurEffectView = UIVisualEffectView(effect: blurEffect)
super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissController))
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.blurEffectView.isUserInteractionEnabled = true
self.blurEffectView.addGestureRecognizer(tapGestureRecognizer)
}
override var frameOfPresentedViewInContainerView: CGRect {
CGRect(origin: CGPoint(x: 0, y: self.containerView!.frame.height * 0.4),
size: CGSize(width: self.containerView!.frame.width, height: self.containerView!.frame.height *
0.6))
}
override func presentationTransitionWillBegin() {
self.blurEffectView.alpha = 0
self.containerView?.addSubview(blurEffectView)
self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
self.blurEffectView.alpha = 0.7
}, completion: { (UIViewControllerTransitionCoordinatorContext) in })
}
override func dismissalTransitionWillBegin() {
self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
self.blurEffectView.alpha = 0
}, completion: { (UIViewControllerTransitionCoordinatorContext) in
self.blurEffectView.removeFromSuperview()
})
}
override func containerViewWillLayoutSubviews() {
super.containerViewWillLayoutSubviews()
presentedView!.roundCorners([.topLeft, .topRight], radius: 22)
}
override func containerViewDidLayoutSubviews() {
super.containerViewDidLayoutSubviews()
presentedView?.frame = frameOfPresentedViewInContainerView
blurEffectView.frame = containerView!.bounds
}
@objc func dismissController(){
self.presentedViewController.dismiss(animated: true, completion: nil)
}
}
extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
Run Code Online (Sandbox Code Playgroud)
将UIViewControllerTransitioningDelegate添加到您呈现的 ViewController
// MARK: - UIViewControllerTransitioningDelegate
extension PresentingViewController: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
PresentationController(presentedViewController: presented, presenting: presenting)
}
}
Run Code Online (Sandbox Code Playgroud)
在 PresentingViewController 中展示你的 VC
let yourVC = YourViewController()
yourVC.modalPresentationStyle = .custom
yourVC.transitioningDelegate = self
self.present(yourVC, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)
代码参考
Dat*_*ris 24
如果你想在半个屏幕上显示一个视图控制器,我建议使用UIPresentationController它,它允许你设置视图控制器的框架.一句忠告,这个方法将停止用户交互,presentingViewController直到你解雇presentedViewController,所以如果你想要显示视图控制器超过一半的屏幕,同时保留用户与presentingViewController你的交互,你应该使用像其他答案建议的容器视图.这是一个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
}
}
Run Code Online (Sandbox Code Playgroud)
当您点击presentedViewController框架外部时,这还会添加模糊视图和点按以关闭.您需要设置transitioningDelegate的presentedViewController贯彻
presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController?
在那里的方法.不要忘记也设置
modalPresentationStyle = .custom
了presentViewController
我发现UIPresentationController的用法是一种更清洁的方法.祝好运
感谢 @aheze 和 @Sreekuttan 提供了 iOS15 解决方案
我提供iOS13-15解决方案
iOS15:
使用UISheetPresentationController
let vc = HalfScreenVC()
if #available(iOS 15.0, *) {
if let sheet = vc.sheetPresentationController {
sheet.detents = [.medium()]
sheet.preferredCornerRadius = 20
}
}
present(vc, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)
iOS13-iOS14
class HalfScreenVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if #available(iOS 15.0, *) {
} else {
// Below iOS 15, change frame here
self.view.frame = CGRect(x: 0, y: UIScreen.main.bounds.height / 5 * 2, width: self.view.bounds.width, height: UIScreen.main.bounds.height / 5 * 3)
self.view.layer.cornerRadius = 20
self.view.layer.masksToBounds = true
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们使用文本字段,我们想要全屏输入
class HalfPresentVC: UIViewController {
let textfield = UITextField(frame: CGRect(x: 20, y: 30, width: 200, height: 40))
var initialBounds: CGRect?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
textfield.borderStyle = .roundedRect
textfield.placeholder = "enter text"
view.addSubview(textfield)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if #available(iOS 15.0, *) {
} else if initialBounds == nil {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
initialBounds = view.bounds
view.layer.cornerRadius = 20
view.layer.masksToBounds = true
view.frame = CGRect(x: 0, y: view.bounds.height / 5 * 2, width: view.bounds.width, height: view.bounds.height / 5 * 3)
}
}
@objc func keyboardWillShow() {
guard let initialBounds = initialBounds else {
return
}
view.frame = initialBounds
}
@objc func keyboardWillHide() {
guard let initialBounds = initialBounds else {
return
}
view.frame = CGRect(x: 0, y: initialBounds.height / 5 * 2, width: initialBounds.width, height: initialBounds.height / 5 * 3)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
Run Code Online (Sandbox Code Playgroud)
有更新的代码来实现此功能。在您想要呈现 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)
}
Run Code Online (Sandbox Code Playgroud)
转到 StoryBoard 选择subViewController并UIView在其中添加一个。
对于模糊效果,将其约束设置为
(top:0,Bottom:0,Leading:0,Trailing:0)
Run Code Online (Sandbox Code Playgroud)
并将其颜色更改black为alpha您想要的颜色。
然后添加另一个UIView选项,将其约束设置为
(top:-,Bottom:0,Leading:0,Trailing:0)
Run Code Online (Sandbox Code Playgroud)
将其height约束设置为equal height with superview(self.View)并将其更改multipler为 0.33 或 0.34。
您可以使用UIPresentationController来实现这一点。在呈现 ViewController 时实现UIViewControllerTransitioningDelegate方法并从委托方法返回您的 PresentationController
func presentationController(forPresented presented: UIViewController,
presenting: UIViewController?,
source: UIViewController) -> UIPresentationController?
Run Code Online (Sandbox Code Playgroud)
你可以参考这个有类似要求的答案。或者,您可以按照其他答案中的建议使用 UIView 动画或嵌入式视图控制器。
编辑:
在 Github 中找到的示例项目
https://github.com/martinnormark/HalfModalPresentationController
有一个新类 ,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)
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
只需更改presentationController.detents = [.medium()]为:
presentationController.detents = [.medium(), .large()]
Run Code Online (Sandbox Code Playgroud)
结果:
| 归档时间: |
|
| 查看次数: |
21055 次 |
| 最近记录: |