【swift4】自作でポップアップを作成してみた。

 

ポップアップだったり、アラートを表示したい場合はswiftが用意してくれてるやつとかライブラリとかあると思うんですけど

実際に自分で作って見たので使って見たい人いたらコピペで使ってみてね。

2パターン用意しました。個人的にはパターン2がいいかなと思います。

 

パターン1:swfit4でポップアップウィンドウを作成

まずは1つ目の実装

viewControllerとポップアップViewControllerで構成されています。

まずはviewcontrollerでボタンとUIViewを作成。 

これがViewController.swift


class ViewController: UIViewController {

    var popupViewController = PopupViewController()
    var popupBtn = UIButton()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        addChildViewController(popupViewController)
        popupViewController.didMove(toParentViewController: self)
        
        // 押されたときにポップアップを表示するボタンを作成。
        self.popupBtn.backgroundColor = UIColor.red
        self.popupBtn.frame = CGRect(x: 0, y: 100, width: 100, height: 50)
        self.popupBtn.setTitle("popup", for: .normal)
        self.popupBtn.addTarget(self, action: #selector(self.popup(_:)), for: .touchUpInside)
        self.view.addSubview(self.popupBtn)
    }

    // ボタンが押されたときにaddSubviewする。
    @objc func popup(_ sender: Any) {
        view.addSubview(popupViewController.view)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

popupViewController.swiftを作成

class PopupViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let screenWidth:CGFloat = self.view.frame.width
        let screenHeight:CGFloat = self.view.frame.height
        
        let popupWidth = (screenWidth * 3)/4
        let popupHeight = (screenWidth * 4)/5

        // uiviewの作成 ポップアップ
        let testUIView = UIView()
        testUIView.frame = CGRect(
            x:screenWidth/8,
            y:screenHeight/5,
            width:popupWidth,
            height:popupHeight
        )
        testUIView.backgroundColor = UIColor.white
        testUIView.layer.cornerRadius = 10
        
        self.view.addSubview(testUIView)
        
        // 画面のどこかがタップされたらポップアップを消す処理
        let tapGesture:UITapGestureRecognizer = UITapGestureRecognizer(
            target: self,
            action: #selector(self.tapped(_:)))
        
        // デリゲートをセット
        tapGesture.delegate = self as? UIGestureRecognizerDelegate
        
        self.view.addGestureRecognizer(tapGesture)
        
        // ポップアップ以外のところを半透明のグレーに。
        self.view.backgroundColor = UIColor(
            red: 150/255,
            green: 150/255,
            blue: 150/255,
            alpha: 0.6
        )
    }

    // どこかタップされたときポップアップを消し去る関数
    @objc func tapped(_ sender: UITapGestureRecognizer){
        self.view.removeFromSuperview()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

 

この中のUIviewとかにlabelやtextFieldを追加してけば、いろいろ作れるはずです!

 

パターン2:swift4でポップアップを作成

 

こちらは既存のモーダルをカスタムするパターンです。 まずはViewControllerから。

こちらは単純にボタンを用意。 そしたらModalViewControllerのインスタンスを生成させてpresentで表示させるというもの。

そこでそのpresentの処理をcustomとしているので、そのcustomeにしているUIPresentationControllerを呼び出す。


class ViewController: UIViewController {

    let sampleBtn = UIButton()

    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.sampleBtn.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
        self.sampleBtn.backgroundColor = UIColor.red
        self.sampleBtn.setTitle("button", for: .normal)
        self.sampleBtn.addTarget(
            self,
            action: #selector(self.btnTapped(sender:)),
            for: .touchUpInside
        )

        self.view.addSubview(self.sampleBtn)
    }
    
    // タップされたときのアクション
    @objc func btnTapped(sender: UIButton){
        let modalViewController = ModalViewController()
        modalViewController.modalPresentationStyle = .custom
        modalViewController.transitioningDelegate = self
        present(modalViewController, animated: true, completion: nil)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}


// modalViewController.modalPresentationStyle = .custom
// でカスタムとしたので、こちらで設定するように呼び出す。
extension ViewController: UIViewControllerTransitioningDelegate {
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        return CustomPresentationController(presentedViewController: presented, presenting: presenting)
    }
}

UIPresentationControllerの設定をする。

// モーダル用のカスタム  UIPresentationController
class CustomPresentationController: UIPresentationController {
    // 表示されるモーダル
    var modalView = UIView()
    let margin = (x: CGFloat(30), y: CGFloat(220.0))
    
    // 表示トランジション開始前に呼ばれる
    override func presentationTransitionWillBegin() {
        guard let containerView = containerView else {
            return
        }
        self.modalView.frame = containerView.bounds

        let tapGesture:UITapGestureRecognizer = UITapGestureRecognizer(
            target: self,
            action: #selector(self.modalViewTouched(_:)))

        self.modalView.addGestureRecognizer(tapGesture)
        self.modalView.backgroundColor = .black
        self.modalView.alpha = 0.0
        
        containerView.addSubview(self.modalView)
        
        // トランジションを実行
        presentedViewController.transitionCoordinator?.animate(
            alongsideTransition: { (context) in
                self.modalView.alpha = 0.7
            },
            completion: nil
        )
    }
    
    // 非表示トランジション開始前
    override func dismissalTransitionWillBegin() {
        presentedViewController.transitionCoordinator?.animate(
            alongsideTransition: { (context) in
                self.modalView.alpha = 0.0
            },
            completion: nil
        )
    }
    
    // 非表示トランジション開始後
    override func dismissalTransitionDidEnd(_ completed: Bool) {
        if completed {
            self.modalView.removeFromSuperview()
        }
    }
    
    // モーダルのサイズを返す。
    override func size(forChildContentContainer container: UIContentContainer, withParentContainerSize parentSize: CGSize) -> CGSize {
        // parentSizeに呼び出し元のviewControllerのサイズが入ってる。
        return CGSize(width: parentSize.width - margin.x, height: parentSize.height - margin.y)
    }

    // モーダルの場所設定
    override var frameOfPresentedViewInContainerView: CGRect {
        var presentedViewFrame = CGRect()
        let containerBounds = containerView!.bounds
        let childContentSize = size(
            forChildContentContainer: presentedViewController,
            withParentContainerSize: containerBounds.size
        )
        presentedViewFrame.size = childContentSize
        presentedViewFrame.origin.x = margin.x / 2.0
        presentedViewFrame.origin.y = margin.y / 2.0

        return presentedViewFrame
    }

    // レイアウト開始前に呼ばれる
    override func containerViewWillLayoutSubviews() {
        self.modalView.frame = containerView!.bounds
        presentedView?.frame = frameOfPresentedViewInContainerView
        presentedView?.layer.cornerRadius = 10
        presentedView?.clipsToBounds = true
    }
    
    // モーダルを消す処理。
    @objc func modalViewTouched(_ sender: UITapGestureRecognizer) {
        presentedViewController.dismiss(animated: true, completion: nil)
    }
}

以上!

 

じゃーの