Ios 在一半大小的父控制器中显示模态视图控制器
我试图在另一个大小为一半父视图控制器的viewcontroller上显示模式视图控制器。但它总是以全屏显示 我已经在我的故事板中创建了具有固定帧大小的自由形式大小的视图控制器。320 X 250Ios 在一半大小的父控制器中显示模态视图控制器,ios,swift,uiviewcontroller,presentmodalviewcontroller,Ios,Swift,Uiviewcontroller,Presentmodalviewcontroller,我试图在另一个大小为一半父视图控制器的viewcontroller上显示模式视图控制器。但它总是以全屏显示 我已经在我的故事板中创建了具有固定帧大小的自由形式大小的视图控制器。320 X 250 var storyboard = UIStoryboard(name: "Main", bundle: nil) var pvc = storyboard.instantiateViewControllerWithIdentifier("CustomTableViewController") as Pr
var storyboard = UIStoryboard(name: "Main", bundle: nil)
var pvc = storyboard.instantiateViewControllerWithIdentifier("CustomTableViewController") as ProductsTableViewController
self.presentViewController(pvc, animated: true, completion: nil)
我已尝试设置frame.superview,但没有任何帮助
请给出建议。您可以使用
UIPresentationController
来实现这一点
为此,您可以让演示ViewController
实现UIViewControllerTransitioningDelegate
,并为半尺寸演示返回您的PresentationController
:
func presentationController(用于呈现:UIViewController,呈现:UIViewController?,来源:UIViewController)->UIPresentationController?{
返回半尺寸表示控制器(presentedViewController:presented,presenting:presentingViewController)
}
演示时,请将演示样式设置为.Custom
,并设置过渡代理:
pvc.modalPresentationStyle=.custom
pvc.transitioningDelegate=self
表示控制器仅返回表示视图控制器的帧:
class HalfSizePresentationController:UIPresentationController{
重写PresentedViewContainerView的var框架:CGRect{
guard let bounds=containerView?.bounds else{return.zero}
返回CGRect(x:0,y:bounds.height/2,width:bounds.width,height:bounds.height/2)
}
}
以下是完整的工作代码:
类ViewController:UIViewController、UIViewControllerTransitioningDelegate{
@iAction func点击(发送方:任意对象){
let storyboard=UIStoryboard(名称:“Main”,捆绑包:nil)
将pvc=storyboard.InstanceEviewController(标识符为“CustomTableViewController”)设为!UITableViewController
pvc.modalPresentationStyle=.custom
pvc.transitioningDelegate=self
pvc.view.backgroundColor=.red
当前(pvc,动画:真实)
}
func presentationController(用于呈现:UIViewController,呈现:UIViewController?,来源:UIViewController)->UIPresentationController{
返回半尺寸表示控制器(presentedViewController:presented,presenting:presentingViewController)
}
}
类HalfSizePresentationController:UIPresentationController{
重写PresentedViewContainerView的var框架:CGRect{
guard let bounds=containerView?.bounds else{return.zero}
返回CGRect(x:0,y:bounds.height/2,width:bounds.width,height:bounds.height/2)
}
}
要添加到Jannis的答案中:
如果pop视图是UIViewController,在加载/设置时向其添加表格,则需要确保创建的表格框架与实际视图的所需宽度相匹配
例如:
let tableFrame: CGRect = CGRectMake(0, 0, chosenWidth, CGFloat(numOfRows) * rowHeight)
其中,chosenWidth是您在自定义类中设置的宽度(在上面:containerView.bounds.width)
您不需要对单元格本身强制执行任何操作,因为表容器(至少在理论上)应该将单元格强制到正确的宽度。如果您在ViewController中推送一些希望显示为半模式的
UIViewControllerTransitioningDelegate
委托方法,这将是一个干净的架构师
假设我们有带半模态的ViewControllerA
显示ViewControllerB
在ViewControllerA
仅显示ViewControllerB
中,使用自定义modalPresentationStyle
func gotoVCB(_ sender: UIButton) {
let vc = ViewControllerB()
vc.modalPresentationStyle = .custom
present(vc, animated: true, completion: nil)
}
在ViewControllerB中:
import UIKit
final class ViewControllerB: UIViewController {
lazy var backdropView: UIView = {
let bdView = UIView(frame: self.view.bounds)
bdView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
return bdView
}()
let menuView = UIView()
let menuHeight = UIScreen.main.bounds.height / 2
var isPresenting = false
init() {
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .custom
transitioningDelegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
view.addSubview(backdropView)
view.addSubview(menuView)
menuView.backgroundColor = .red
menuView.translatesAutoresizingMaskIntoConstraints = false
menuView.heightAnchor.constraint(equalToConstant: menuHeight).isActive = true
menuView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
menuView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
menuView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewControllerB.handleTap(_:)))
backdropView.addGestureRecognizer(tapGesture)
}
@objc func handleTap(_ sender: UITapGestureRecognizer) {
dismiss(animated: true, completion: nil)
}
}
extension ViewControllerB: UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 1
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
guard let toVC = toViewController else { return }
isPresenting = !isPresenting
if isPresenting == true {
containerView.addSubview(toVC.view)
menuView.frame.origin.y += menuHeight
backdropView.alpha = 0
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {
self.menuView.frame.origin.y -= self.menuHeight
self.backdropView.alpha = 1
}, completion: { (finished) in
transitionContext.completeTransition(true)
})
} else {
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {
self.menuView.frame.origin.y += self.menuHeight
self.backdropView.alpha = 0
}, completion: { (finished) in
transitionContext.completeTransition(true)
})
}
}
}
结果是:
所有代码都发布在my上,Jannis很好地掌握了总体战略。在iOS 9.x和swift 3中它对我不起作用。在演示VC上,启动演示VC的操作与上面演示的操作类似,但有一些非常微小的更改,如下所示:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let pvc = storyboard.instantiateViewController(withIdentifier: "SomeScreen") as SomeViewController
pvc.modalPresentationStyle = .custom
pvc.transitioningDelegate = self
present(pvc, animated: true, completion: nil)
class HalfSizePresentationController: UIPresentationController {
override var frameOfPresentedViewInContainerView: CGRect {
return CGRect(x: 0, y: 0, width: containerView!.bounds.width, height: containerView!.bounds.height/2)
}
}
要在同一个呈现VC上实现UIViewControllerTransitioningDelegate
,语法与中的SO答案中突出显示的完全不同。这对我来说是最棘手的部分。以下是协议实现:
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return HalfSizePresentationController(presentedViewController:presented, presenting: presenting)
}
对于UIPresentationController
类,我必须重写变量FrameofPresentedViewWinContainerView
,而不是方法,如下所示:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let pvc = storyboard.instantiateViewController(withIdentifier: "SomeScreen") as SomeViewController
pvc.modalPresentationStyle = .custom
pvc.transitioningDelegate = self
present(pvc, animated: true, completion: nil)
class HalfSizePresentationController: UIPresentationController {
override var frameOfPresentedViewInContainerView: CGRect {
return CGRect(x: 0, y: 0, width: containerView!.bounds.width, height: containerView!.bounds.height/2)
}
}
在演示后,有一些关于如何消除视图的问题。你可以像其他VC一样在你的VC上实现所有的常规逻辑。当用户在显示的VC之外进行选项卡操作时,我在
SomeViewController
中执行一个关闭视图的操作。我使用下面的逻辑显示半屏幕ViewController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let expVC = storyboard.instantiateViewController(withIdentifier: "AddExperinceVC") as! AddExperinceVC
expVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(expVC, animated: true, completion: nil)
以防万一有人像我一样希望用Swift 4这样做
class MyViewController : UIViewController {
...
@IBAction func dictionaryButtonTouchUp(_ sender: UIButton) {
let modalViewController = ...
modalViewController.transitioningDelegate = self
modalViewController.modalPresentationStyle = .custom
self.present(modalViewController, animated: true, completion: nil)
}
}
extension MyViewController : UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return HalfSizePresentationController(presentedViewController: presented, presenting: presenting)
}
}
其中,HalfSizePresentationController类由以下部分组成:
class HalfSizePresentationController : UIPresentationController {
override var frameOfPresentedViewInContainerView: CGRect {
get {
guard let theView = containerView else {
return CGRect.zero
}
return CGRect(x: 0, y: theView.bounds.height/2, width: theView.bounds.width, height: theView.bounds.height/2)
}
}
}
干杯
下面是Swift 4.0一些类名是changeFrameofPresentedViewWinContainerView
get方法
步骤1:设置委托
class ViewController: UIViewController, UIViewControllerTransitioningDelegate
步骤2:设置委托方法
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return SetSizePresentationController(presentedViewController: presented, presenting: presenting)
}
步骤3:在这里,您可以为set size(CGRect)创建自己的类
步骤4:这里有两行重要的transitioningdelegate
和UIModalPresentationStyle.custom
let storyboard = UIStoryboard(name: "User", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "LicenceViewController") as! LicenceViewController
vc.modalPresentationStyle = UIModalPresentationStyle.custom
vc.transitioningDelegate = self
present(vc, animated: true)
细节
- 代码12.2(12B45b)
- Swift 5.3
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
let contentView = UIView()
contentView.backgroundColor = .lightGray
view.addSubview(contentView)
//...
}
}
隐藏子视图控制器的根视图
,并添加将用作根视图的新视图
主逻辑:
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
let contentView = UIView()
contentView.backgroundColor = .lightGray
view.addSubview(contentView)
//...
}
}
解决方案1。全样本
解决方案2。自定义转换
创意:
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
let contentView = UIView()
contentView.backgroundColor = .lightGray
view.addSubview(contentView)
//...
}
}
更改ChildViewController
的根视图的大小
主逻辑:
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
let contentView = UIView()
contentView.backgroundColor = .lightGray
view.addSubview(contentView)
//...
}
}
ModalPresentationController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let expVC = storyboard.instantiateViewController(withIdentifier: "AddExperinceVC") as! AddExperinceVC
expVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(expVC, animated: true, completion: nil)
更新根视图大小
解决方案2。全样本
别忘了在这里粘贴定义的ModalPresentationController