Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 아래에서 위로 올라오는 팝업 구현 방법 (커스텀 팝업, viewController 팝업 형태, present, coverVertical) 본문

UI 컴포넌트 (swift)

[iOS - swift] 아래에서 위로 올라오는 팝업 구현 방법 (커스텀 팝업, viewController 팝업 형태, present, coverVertical)

jake-kim 2023. 3. 4. 22:36

present로 여는 커스텀 팝업

커스텀  팝업 ViewController

* UIView 를 이용한 커스텀 팝업은 이전 포스팅 글 참고

  • 커스텀 팝업
    • 사용하는 쪽에서 present로 접근하여 사용할 수 있게끔 UIViewController를 상속받아서 구현되어야 하는 형태
    • 팝업을 오픈하면 아래에서 위로 올라오는 애니메이션이 있는 형태의 팝업

구현 아이디어

  • UIViewController를 상속받아서 구현
  • modalTransitionStyle을 .coverVertical로 하면 아래에서 위로 올라오는 애니메이션이 적용되는데 이걸 그대로 사용
    • modalTransitionStyle 관련 개념은 이전 포스팅 글 참고
  • dimmed시키는 기능은 viewWillAppear에서 UIView를 추가하고, viewWillDisappear에서 UIView를 제거하는 방식
    • UIView를 추가할땐 해당 UIViewController의 view에다 추가하는것이 아닌, 해당 뷰컨을 오픈시킨 뷰컨 (presentingViewController에 추가하게끔 구현)

커스텀 팝업 구현 

* 코드로 UI 작성을 편리하게 하기 위해 SnapKit 사용

  • DimmedViewController는 팝업 뿐 아니라 다양한 곳에서 사용될 수 있으므로 별도로 구현 후 팝업 뷰컨에서 이를 상속받아서 구현하도록 설계
  • 뒷 배경을 흐리게 시키는 DimmedViewController를 먼저 구현하고, 이를 상속받아서 팝업의 contents가 있는CustomPopupViewController를 구현

DimmedViewController 구현

  • viewWillAppear, viewWillDisappear에서 dimmed 뷰를 추가하고 제거하는 뷰컨을 하나 추가
    • 아래에서 위로 올라오는 modal 스타일 (modalTransitionStyle은 coverVertical로 설정)
    • 화면 전체를 덮는 스타일 (overFullScreen)
import UIKit
import SnapKit

class DimmedViewController: UIViewController {
    private let dimmedView = UIView()
    
    init() {
        super.init(nibName: nil, bundle: nil)
        modalTransitionStyle = .coverVertical
        modalPresentationStyle = .overFullScreen
    }
    
    required public init?(coder: NSCoder) {
        fatalError()
    }
}
  • dimmed 뷰 추가
    • 애니메이션을 주어서 alpha값이 서서히 들어나도록 구현
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    guard let presentingViewController else { return }
    dimmedView.backgroundColor = .black
    dimmedView.alpha = 0
    presentingViewController.view.addSubview(dimmedView)
    
    dimmedView.snp.makeConstraints {
        $0.edges.equalToSuperview()
    }
    
    UIView.animate(withDuration: 0.3) {
        self.dimmedView.alpha = 0.25
    }
}
  • dismiss될 때 dimmed뷰도 같이 없어지도록 viewWillDisappear에서 removeFromSuperview 호출
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    UIView.animate(withDuration: 0.3) {
        self.dimmedView.alpha = 0
    } completion: { _ in
        self.dimmedView.removeFromSuperview()
    }
}

CustomPopupViewController 구현 

  • DimmedViewController를 상속받아서 구현
import UIKit
import SnapKit

final class CustomPopupViewController: DimmedViewController {

}
  • containerView하나를 두어서 팝업 콘텐츠 영역을 잡고, 그 안에 vertical stackView를 넣어서 내용 채우기
private let containerView: UIView = {
    let view = UIView()
    view.backgroundColor = .white
    return view
}()
private let stackView: UIStackView = {
    let view = UIStackView()
    view.axis = .vertical
    view.spacing = 12
    view.backgroundColor = .white
    return view
}()
private let label: UILabel = {
    let label = UILabel()
    label.textColor = .black
    label.text = "iOS 앱 개발 알아가기 jake"
    return label
}()
private let closeButton: UIButton = {
    let button = UIButton()
    button.setTitle("닫기", for: .normal)
    button.setTitleColor(.systemBlue, for: .normal)
    button.setTitleColor(.blue, for: .highlighted)
    button.addTarget(self, action: #selector(close), for: .touchUpInside)
    return button
}()

@objc private func close() {
    dismiss(animated: true)
}
  • 레이아웃 설정
override init() {
    super.init()
    setUp()
}

required init?(coder: NSCoder) {
    fatalError()
}

private func setUp() {
    view.addSubview(containerView)
    containerView.addSubview(stackView)
    stackView.addArrangedSubview(label)
    stackView.addArrangedSubview(closeButton)
    
    containerView.snp.makeConstraints {
        $0.leading.trailing.equalToSuperview().inset(20)
        $0.centerY.equalToSuperview()
    }
    stackView.snp.makeConstraints {
        $0.center.equalToSuperview()
        $0.leading.top.greaterThanOrEqualToSuperview()
        $0.bottom.trailing.lessThanOrEqualToSuperview()
    }
}

사용하는 쪽

import UIKit
import SnapKit

class ViewController: UIViewController {
    private let presentButton: UIButton = {
        let button = UIButton()
        button.setTitle("present popuup", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.setTitleColor(.blue, for: .highlighted)
        button.addTarget(self, action: #selector(tap), for: .touchUpInside)
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(presentButton)
        presentButton.snp.makeConstraints {
            $0.center.equalToSuperview()
        }
    }
    
    @objc private func tap() {
        let popupVC = CustomPopupViewController()
        present(popupVC, animated: true)
    }
}

(완료)

present로 여는 커스텀 팝업

* 전체 코드: https://github.com/JK0369/CustomPopupViewController

Comments