首页 > 解决方案 > 如何获得弹出的自定义modalPresentationStyle VC的圆角和动态高度

问题描述

展示 VC 时,默认样式不覆盖全屏,并带有圆角,如下 gif 所示。

gif

但是我想控制modalPresentation的高度,假设默认为1/4屏幕高度,并根据tableView弹出VC的行动态更改。所以我custom在下面的代码基础上实现了一个 modalPresentationStyle 。

但是,我在之后发现了这些问题:

  1. 弹出的 VC 不是圆角,而是矩形角。
  2. 我不能再拖动来移动弹出的 VC,它处于固定位置。
  3. 如果我可以根据其 tableView 行数增加弹出的 VC 的高度会更好。不是必须品。
    @objc func collectButtonTapped(_ sender: Any?) {
        
        let vc = PlayListViewController()
        vc.modalPresentationStyle = .custom
        vc.transitioningDelegate = self
        
        present(vc, animated: true)
        
    }
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        return HalfSizePresentationController(presentedViewController: presented, presenting: presentingViewController)
    }

class HalfSizePresentationController: UIPresentationController {
    override var frameOfPresentedViewInContainerView: CGRect {
        guard let bounds = containerView?.bounds else { return .zero }
        return CGRect(x: 0, y: bounds.height * 0.75, width: bounds.width, height: bounds.height * 0.75)
    }
}

标签: iosswiftuimodalpresentationstyle

解决方案


尝试将cornerRadius分配给您的vc:

@objc func collectButtonTapped(_ sender: Any?) {
    
    let vc = PlayListViewController()
    vc.modalPresentationStyle = .custom
    vc.transitioningDelegate = self
    // assign corner radius
    vc.view.layer.cornerRadius = 20
    vc.view.clipsToBounds = true
    vc.view.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner] // this is for corner radius only for top
    present(vc, animated: true)
}

对于 vc 呈现位置的完全控制,您可以使用子 vc 和自动布局,对于当前子 vc(如模态演示样式),您可以在子 vc 顶部约束上使用 UIView.animate。

这是子 vc 和自动布局的示例:

import UIKit

class YourController: UIViewController {

private lazy var firstChildVc = AiutiFirst()

let myButton: UIButton = {
    let b = UIButton(type: .system)
    b.layer.cornerRadius = 10
    b.clipsToBounds = true
    b.backgroundColor = .black
    b.setTitleColor(.white, for: .normal)
    b.setTitle("Present", for: .normal)
    b.addTarget(self, action: #selector(handlePresent), for: .touchUpInside)
    b.translatesAutoresizingMaskIntoConstraints = false
    
    return b
}()

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .blue
    addChildVC()
}

var up = false

@objc fileprivate func handlePresent() {
    
    print("present")
    
    if up == false {
        UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut) {
            self.menuDown?.isActive = false
            self.menuUp?.isActive = true
            self.myButton.setTitle("Dismiss", for: .normal)
            self.view.layoutIfNeeded()
        } completion: { _ in
            print("Animation completed")
            self.up = true
        }
    } else {
        UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut) {
            self.menuUp?.isActive = false
            self.menuDown?.isActive = true
            self.myButton.setTitle("Present", for: .normal)
            self.view.layoutIfNeeded()
        } completion: { _ in
            print("Animation completed")
            self.up = false
        }
    }
}

var menuUp: NSLayoutConstraint?
var menuDown: NSLayoutConstraint?

fileprivate func addChildVC() {
    addChild(firstChildVc)

    firstChildVc.view.translatesAutoresizingMaskIntoConstraints = false

    firstChildVc.view.layer.cornerRadius = 20
    firstChildVc.view.clipsToBounds = true
    firstChildVc.view.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner] // this is for corner radius only for top
    
    view.addSubview(firstChildVc.view)

    menuUp = firstChildVc.view.topAnchor.constraint(equalTo: view.centerYAnchor)
    menuDown = firstChildVc.view.topAnchor.constraint(equalTo: view.bottomAnchor)
    menuDown?.isActive = true
    firstChildVc.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    firstChildVc.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    firstChildVc.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    firstChildVc.didMove(toParent: self)
    
    view.addSubview(myButton)
    myButton.bottomAnchor.constraint(equalTo: view.centerYAnchor, constant: -40).isActive = true
    myButton.widthAnchor.constraint(equalToConstant: 200).isActive = true
    myButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
    myButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
 }
}

这是结果:

在此处输入图像描述

要为子 vc 演示动画制作动画,您可以将 UIView.animate 函数用于顶级子 vc 约束,或者使用平移手势拖动它,或者任何您认为必要且有效的使用...

显示它全屏简单设置子 vc 顶部锚点到兴趣视图顶部:

menuUp = firstChildVc.view.topAnchor.constraint(equalTo: view.topAnchor)

推荐阅读