본문 바로가기
아이폰 개발/Swift

swift custom popup - 재사용가능한 팝업

by 인생여희 2021. 8. 9.

swift custom popup - 재사용가능한 팝업

 

 

 

xib - 디자인

 

 

popupVC.swift - 공통 팝업 뷰컨트롤러

//
//  PopupVC.swift
//  Po
//
//  Created by k on 2021/08/09.
//

import UIKit

/// 팝업 타입
enum PopupTpye {
    case alarm              //라벨 + 닫기
    case textField          //라벨 + 텍스트 + (닫기,ok)
    case closeAndOk         //라벨 + (닫기,ok)
}


class PopupVC: UIViewController {
    
    /// 팝업 뷰
    @IBOutlet weak var popUpView: UIView!
    
    /// 라벨
    @IBOutlet weak var labelContent: UILabel!
    /// 텍스트 필드
    @IBOutlet weak var textFieldContent: UITextField!
    /// 취소 버튼
    @IBOutlet weak var cancelBtn: UIButton!
    /// ok 버튼
    @IBOutlet weak var okBtn: UIButton!
    /// 취소, ok 버튼 감싼 View
    @IBOutlet weak var buttonWrapperView: UIView!
    
    /// 완전 취소 - 한개 버튼
    @IBOutlet weak var cancelOneBtn: UIButton!
    
    /// 취소 or 확인 중 선택된 버튼  0 : 취소, 1 확인
    var clickedBtn = ""
    
    ///팝업 타입
    var popupType :PopupTpye = .alarm
    ///팝업 텍스트
    var popupText = ""
    /// 취소 버튼 이름
    var cancelBtnName = ""
    /// ok 버튼 이름
    var okBtnName = ""
    
    /// 취소 단독 버튼 이름
    var cancelOneBtnName = ""
    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        
        self.popUpView.layer.cornerRadius = 10
        
        switch popupType {
        case .alarm:
           
            print("alarm")
            labelContent.text = popupText
            cancelOneBtn.setTitle(cancelOneBtnName, for: .normal)   //단독취소버튼 이름 set
            
            textFieldContent.isHidden = true                        //텍스트필드 숨김
            buttonWrapperView.isHidden = true                       //확인버튼, 취소버튼 wrapper view 숨김
            
        case .textField:
            print("textField")
            
            labelContent.text = popupText
            okBtn.setTitle(okBtnName, for: .normal)                 //확인버튼 이름 set
            cancelBtn.setTitle(cancelBtnName, for: .normal)         //취소버튼 이름 set
            cancelOneBtn.isHidden = true                            //단독취소버튼 숨김
            
            
        case .closeAndOk:
            
            print("closeAndOk")
            
            labelContent.text = popupText
            
            okBtn.setTitle(okBtnName, for: .normal)                 //확인버튼 이름 set
            cancelBtn.setTitle(cancelBtnName, for: .normal)         //취소버튼 이름 set
            textFieldContent.isHidden = true                        //텍스트필드 숨김
            cancelOneBtn.isHidden = true                            //단독취소버튼 숨김

        }

    }


    /// 취소버튼 이벤트와 확인 ok 이벤트
    @IBAction func clickCancelAndOkBtn(_ sender: UIButton) {

        /// 클릭한 버튼 : 0 취소, 1 확인
        clickedBtn = "\(sender.tag)"
        NotificationCenter.default.post(name: .getPopupEventResult,object: self)
        
    }
    

    /// 완전 취소
    @IBAction func clickCancelOneBtn(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }


    // willMove -> It appears on the parent screen.
    override func willMove(toParent parent: UIViewController?) {
        print(#function)
        if let parent = parent as UIViewController? {
            print(parent)
        }
    }
    
    // It appears on the parent screen. -> didMove
    override func didMove(toParent parent: UIViewController?) {
        print(#function)
        if let parent = parent as UIViewController? {
            print(parent)
        }
    }
    
    //https://medium.com/@jang.wangsu/swift-containerview-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC-ee2ed07ec4e8
    
    
}

 

 

controllCenter.swit - 싱글톤으로 공통팝업 열여주기

 

//
//  ControllCenter.swift
//  Po
//
//  Created by k on 2021/08/09.
//

import UIKit
import Foundation

class ControllCenter {
    
    static let shared = ControllCenter()
    
    var testVal = ""
    let window = UIApplication.shared.windows.first { $0.isKeyWindow}
    
    /**
     - Author: k
     - Date:
     - Parameters:
        - popupText: 알림내용 text
        - cancelOneBtnName: 닫기or 확인 버튼 명
        - vc : 팝업 델리게이트 메소드 대리자
     - Returns:
     - Note: 알람 팝업 띄우기
    */
    public func showAlarmPopup(vc:UIViewController, popupText:String , cancelOneBtnName :String){
        print("showBasicPopup")
    
        /// 최상위 뷰컨트롤러
        if let rootVc = window?.rootViewController{
            
            let visibleController = self.getRootViewController(vc: rootVc)
            
            ///팝업
            let popvc = PopupVC(nibName: "PopupVC", bundle: nil)
            popvc.modalPresentationStyle = .overCurrentContext
            popvc.popupText = popupText
            popvc.popupType = .alarm
            popvc.cancelOneBtnName = cancelOneBtnName
            
            visibleController?.present(popvc, animated: true, completion: nil)
        }
    }
    
    
    /**
     - Author: k
     - Date:
     - Parameters:
        - popupText: 알림내용 text
        - okBtnName: 확인 버튼 명
        - cancelBtnName: 닫기 버튼 명
        - vc : 팝업 델리게이트 메소드 대리자
     - Returns:
     - Note: 텍스트필드 입력 팝업 띄우기
    */
    public func showInputTextFieldPopup(vc:UIViewController, popupText:String , okBtnName :String , cancelBtnName :String){
        print("showInputTextFieldPopup")
    
        /// 최상위 뷰컨트롤러
        if let rootVc = window?.rootViewController{
            
            let visibleController = self.getRootViewController(vc: rootVc)
            
            ///팝업
            let popvc = PopupVC(nibName: "PopupVC", bundle: nil)
            popvc.modalPresentationStyle = .overCurrentContext
            popvc.popupText = popupText
            popvc.popupType = .textField
            popvc.okBtnName = okBtnName
            popvc.cancelBtnName = cancelBtnName
            
            visibleController?.present(popvc, animated: true, completion: nil)
        }
    }
    
    
    /**
     - Author: k
     - Date:
     - Parameters:
        - popupText: 알림내용 text
        - okBtnName: 확인 버튼 명
        - cancelBtnName: 닫기 버튼 명
        - vc : 팝업 델리게이트 메소드 대리자
     - Returns:
     - Note: 닫기, 확인 팝업 띄우기
    */
    public func showOkAndClosePopup(vc:UIViewController, popupText:String , okBtnName :String , cancelBtnName :String){
        print("showInputTextFieldPopup")
    
        /// 최상위 뷰컨트롤러
        if let rootVc = window?.rootViewController{
            
            let visibleController = self.getRootViewController(vc: rootVc)
            
            ///팝업
            let popvc = PopupVC(nibName: "PopupVC", bundle: nil)
            popvc.modalPresentationStyle = .overCurrentContext
            popvc.popupText = popupText
            popvc.popupType = .closeAndOk
            popvc.okBtnName = okBtnName
            popvc.cancelBtnName = cancelBtnName
            
            visibleController?.present(popvc, animated: true, completion: nil)
        }
    }
    


    /**
     # getRootViewController
     - Author: k
     - Date:
     - Parameters:
        - vc: rootViewController 혹은 UITapViewController
     - Returns: UIViewController?
     - Note: vc내에서 가장 최상위에 있는 뷰컨트롤러 반환
    */
    public func getRootViewController(vc:UIViewController) ->UIViewController?{

    
        ///[1] 네비게이션 컨트롤러
        if let nc = vc as? UINavigationController {

            if let vcOfnavController = nc.visibleViewController {
                return self.getRootViewController(vc: vcOfnavController)
            }
        
        ///[2] 탭뷰 컨트롤러
        }else if let tc = vc as? UITabBarController {
            
            if let tcOfnavControler = tc.selectedViewController {
                return self.getRootViewController(vc: tcOfnavControler)
            }
            
        ///[3] 뷰 컨트롤러
        }else{
            if let pvc = vc.presentedViewController{
                return self.getRootViewController(vc: pvc)
            }else {
                return vc
            }
        }
        
        return nil
    }
    
}

 

 

팝업띄우기

//
//  LoginViewController.swift
//  QuestionIOS
//
//  Created by k2 on 2021/04/11.
//

import UIKit
import RealmSwift

class LoginViewController: UIViewController {
    
    /// 옵저버
    var observer: NSObjectProtocol?
    
    /// 코디네이터
    var coordinator: SiginCoordinator?
    
    @IBOutlet weak var emailTxtfield: UITextField!
    @IBOutlet weak var pwTxtfield: UITextField!
    @IBOutlet weak var emailPwCheckMsg: UILabel!
    @IBOutlet weak var loginBtn: UIButton!
    
    @IBOutlet weak var siginBtn: UIButton!
    
    //MARK: 로그인 체크 후 탭바 띄우기
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        /// 로그인 체크 후 탭바 띄우기
        self.openMainTabBarController()
        
        ///notificaion 옵저버 등록
        self.regNotificationObserver()
        
    }
    
    //MARK: 옵저버 등록
    /// 옵저버 등록
    private func regNotificationObserver(){
        
        ///팝업 노티
        observer = NotificationCenter.default.addObserver(forName: .getPopupEventResult, object: nil, queue: OperationQueue.main) { notification in
            
            let popUpVC = notification.object as! PopupVC
            
            Log.debug("팝업타입 : \(popUpVC.popupType)" )
            Log.debug("눌린버튼 : \(popUpVC.clickedBtn)" )
            Log.debug("텍스트내용 : \(popUpVC.textFieldContent.text ?? "")" )
        }
    }
    
    //MARK: viewDidDisappear
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        if let observer = observer{
            NotificationCenter.default.removeObserver(observer)
        }
    }
    



    
    //MARK:테스트 팝업
    @IBAction func testPopup(_ sender: UIButton) {
    
//        ControllCenter.shared.showAlarmPopup(vc:self, popupText: "일반 알람...", cancelOneBtnName: "오게이..")
        
        ControllCenter.shared.showInputTextFieldPopup(vc:self, popupText: "텍스트필드 위드 팝업", okBtnName: "오게이", cancelBtnName: "놉")
       
//        ControllCenter.shared.showOkAndClosePopup(vc:self, popupText: "확인, 닫기 팝업....", okBtnName: "응", cancelBtnName: "아냐..") 
    }
}

 

LoginViewController.swift
0.01MB
ControllCenter.swift
0.00MB
Notification+Extension.swift
0.00MB
PopupVC.swift
0.00MB
PopupVC.xib
0.01MB

 

 

 

*콜백함수로 데이터 전달하기

 

popupVC.swift

 

class PopupVC: UIViewController {

    

    /// 팝업 완료 콜백 함수 선언

    var callBackFunc: ((_ popupType: PopupTpye ,_ clickedBtn: String ,_ txt: String) -> ())?

    

 

    /// 취소버튼 이벤트와 확인 ok 이벤트

    @IBAction func clickCancelAndOkBtn(_ sender: UIButton) {

 

        /// 클릭한 버튼 : 0 취소, 1 확인

           

//콜백함수 호출

        callBackFunc?(popupType, "\(sender.tag)", textFieldContent.text ?? "")

        

        self.dismiss(animated: true, completion: nil)

    }

 

...

}

 

 

ControllCenter.swift

 

    public func showOkAndClosePopup(vc:UIViewController, popupText:String , okBtnName :String , cancelBtnName :String , complete: @escaping (PopupTpye ,String ,String) -> ()){

        print("showInputTextFieldPopup")

    

        /// 최상위 뷰컨트롤러

        if let rootVc = window?.rootViewController{

            

            let visibleController = self.getRootViewController(vc: rootVc)

            

            ///팝업

            let popvc = PopupVC(nibName: "PopupVC", bundle: nil)

            popvc.modalPresentationStyle = .overCurrentContext

            popvc.popupText = popupText

            popvc.popupType = .closeAndOk

            popvc.okBtnName = okBtnName

            popvc.cancelBtnName = cancelBtnName

            popvc.callBackFunc = { (popupType , clickedBtn , txt) in

                complete(popupType , clickedBtn , txt)

            }

            

            visibleController?.present(popvc, animated: true, completion: nil)

        }

    }

 

 

 

LoginViewController.swift - 호출해서 콜백받기

 

        ControllCenter.shared.showInputTextFieldPopup(vc:self, popupText: "텍스트필드 위드 팝업", okBtnName: "오게이", cancelBtnName: "놉") { (popupType , clickedBtn , txt) in

 

            if popupType == .textField {

      

            }

            Log.debug("팝업타입 : \(popupType)" )

            Log.debug("눌린버튼 : \(clickedBtn)" )

            Log.debug("텍스트내용 : \(txt)" )

        }

 

 

 

 

 

참고할만한 블로그 - addChild

https://medium.com/@jang.wangsu/swift-containerview-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC-ee2ed07ec4e8

https://sujinnaljin.medium.com/swift-addchild%EC%9D%98-frame-%EB%AC%B8%EC%A0%9C-961cc2361424

https://minominodomino.github.io/devlog/2019/05/19/ios-ContainerViewController/