iOS/UIKIt

[iOS/UI kit] 스토리보드 없이 모달 구현하기 (modal without storyboard)

개발하는 감자입니다 2024. 1. 25. 03:57
728x90

 

 

안녕하세요! 개발감자입니다🥔

저는 현재 스토리보드 없이 UI kit로 앱 개발 중입니다. 모달을 구현해야 하는 상황이지만, 구글링을 해본 결과 스토리보드없이 모달을 구현한 예제를 찾기가 어려웠습니다. 혹시나 저와 같은 상황일 분들을 위하여 예제를 공유합니다!

구현해볼 예제

1.  모달을 부를 버튼 만들기

 

모달을 부를 빨간색 버튼

< 카테고리를 선택해주세요> 옆에 있는 빨간색 버튼을 클릭하면 모달을 불러오도록 구현해볼 것입니다.

일단 버튼을 구현해줍니다. 버튼의 isUserInteractionEnabled의 속성을 true로 설정하여 사용자와 상호작용할 수 있도록 합니다.

 // 카테고리 선택 버튼 추가
    lazy var categoryChooseButton: UIButton = {
        let button = UIButton()
        let arrowImage = UIImage(systemName:"pencil") // Replace "arrow_down" with the actual image name in your assets
        button.setImage(arrowImage, for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.isUserInteractionEnabled = true  // 클릭 활성화
        button.backgroundColor = UIColor.red
      
        return button
        
    }()

 

2. 버튼 클릭 시 모달을 부르는 함수 구현하기

버튼 클릭 시 바뀌는 배경색

button.addTarget(self, action: #selector(showCategoryModal), for: .touchUpInside) //클릭시 모달 띄우기

 

위의 함수를 1번의 버튼 구현한 부분에 추가하면, 버튼 클릭시 <showCategoryModal>함수를 실행하게 됩니다.

추가한 코드는 아래와 같습니다.

/ 카테고리 선택 버튼 추가
    lazy var categoryChooseButton: UIButton = {
        let button = UIButton()
        let arrowImage = UIImage(systemName:"pencil") // Replace "arrow_down" with the actual image name in your assets
        button.setImage(arrowImage, for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.isUserInteractionEnabled = true  // 클릭 활성화
        button.backgroundColor = UIColor.red
        button.addTarget(self, action: #selector(showCategoryModal), for: .touchUpInside) //클릭시 모달 띄우기
        return button
        
    }()

 

3. 모달 뷰 컨트롤러 생성하기

모달 구현

이제 showCategoryModal 함수를 구현하면 모달을 띄울 수 있게 됩니다.

@objc
    private func showCategoryModal() {
        print("Category Button clicked")// 버튼 클릭 표시
        categoryChooseButton.backgroundColor = UIColor.green // 버튼 배경을 초록색으로 변경
        
        let categoryModalVC = CategoryModalViewController()
        categoryModalVC.modalPresentationStyle = .overCurrentContext // 모달이 전체 뷰를 덮도록 설정
        // 모달을 띄우기
        present(categoryModalVC, animated: true, completion: nil)
        }

 

버튼을 클릭했다는 것을 파악하기 위하여 위에서 2번째까지의 코드를 작성하였습니다. 빨간색 버튼을 클릭했을 때에 초록색 버튼으로 바뀌고 콘솔에 버튼이 클릭됐다는 문장이 찍히게 됩니다.  그 나머지의 코드는 `CategoryModalViewController`를 생성하고, 해당 뷰 컨트롤러를 모달로 띄우기 위한 부분입니다. 각 줄에 대한 설명은 다음과 같습니다.

  1. `let categoryModalVC = CategoryModalViewController()`: `CategoryModalViewController`의 인스턴스를 생성합니다.
  2. `categoryModalVC.modalPresentationStyle = .overCurrentContext`: `modalPresentationStyle` 속성을 `.overCurrentContext`로 설정합니다. 이 설정은 모달이 현재 뷰 컨트롤러의 내용 위에 나타나도록 합니다. 즉, 모달이 전체 뷰를 덮게 됩니다.
  3. `present(categoryModalVC, animated: true, completion: nil)`: `present` 메서드를 사용하여 `categoryModalVC`를 현재의 뷰 컨트롤러 위에 모달로 띄웁니다. `animated` 매개변수를 `true`로 설정하면 모달이 애니메이션과 함께 나타납니다. `completion` 클로저는 모달 표시가 완료된 후에 실행될 코드를 지정할 수 있습니다. 이 경우에는 `nil`로 설정되어 있습니다.

이 코드를 통해 `CategoryModalViewController`가 모달로 나타나고, 해당 모달이 전체 화면을 덮도록 설정됩니다. 이후에 모달에서 카테고리를 선택하면 해당 모달이 닫히게 됩니다.

 

4. 모달 뷰 컨트롤러 구현하기

import UIKit

class CategoryModalViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    let categories = ["Food", "Shopping", "Entertainment", "Utilities", "Transportation"]
    
    lazy var tableView: UITableView = {
        let tableView = UITableView()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "categoryCell")
        tableView.translatesAutoresizingMaskIntoConstraints = false
        return tableView
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(white: 0, alpha: 0.5)
        setupTableView()
    }

    func setupTableView() {
        view.addSubview(tableView)
        
        NSLayoutConstraint.activate([
            tableView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            tableView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            tableView.widthAnchor.constraint(equalToConstant: 200),
            tableView.heightAnchor.constraint(equalToConstant: 300)
        ])
    }

    // MARK: - UITableViewDataSource

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return categories.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "categoryCell", for: indexPath)
        cell.textLabel?.text = categories[indexPath.row]
        return cell
    }

    // MARK: - UITableViewDelegate

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let selectedCategory = categories[indexPath.row]
        print("Selected category: \(selectedCategory)")
        
        dismiss(animated: true, completion: nil)
    }
}

 

이 코드는 카테고리를 보여주는 간단한 모달 뷰 컨트롤러인 `CategoryModalViewController`를 정의합니다. 각 부분에 대한 설명은 다음과 같습니다

  1. `categories`: 모달에 표시할 카테고리를 저장하는 문자열 배열입니다.
  2. `tableView`: `UITableView` 인스턴스를 선언하고, 이 뷰 컨트롤러의 메인 뷰에 추가합니다. `delegate`와 `dataSource`는 현재 뷰 컨트롤러 자체로 설정되어 있으며, `UITableView`의 기본 셀을 사용하기 위해 "categoryCell"이라는 식별자로 셀을 등록합니다.
  3. `viewDidLoad()`: 뷰 컨트롤러의 뷰가 로드되면 호출되는 메서드입니다. 여기서는 배경을 반투명하게 설정하고, `setupTableView()` 메서드를 호출하여 `tableView`를 초기화합니다.
  4. `setupTableView()`: `tableView`의 제약 조건을 설정하여 화면 중앙에 위치하도록 합니다.
  5. `tableView(_:numberOfRowsInSection:)`: 데이터 소스 메서드로, 섹션당 행의 수를 반환합니다. 여기서는 카테고리 배열의 항목 수를 반환합니다.
  6. `tableView(_:cellForRowAt:)`: 데이터 소스 메서드로, 각 행에 대한 셀을 반환합니다. 재사용 큐에서 셀을 가져와 카테고리 배열에서 해당하는 텍스트를 설정합니다.
  7. 'tableView(_:didSelectRowAt:)`: 델리게이트 메서드로, 사용자가 특정 행을 선택했을 때 호출됩니다. 선택한 카테고리를 출력하고 `dismiss(animated:completion:)` 메서드를 사용하여 모달을 닫습니다.

이제 이 코드를 사용하여 다른 뷰 컨트롤러에서 `CategoryModalViewController`를 모달로 띄우고, 사용자가 카테고리를 선택하면 모달이 닫히게 됩니다.

 

5. 최종적으로 구현한 화면 보기

728x90
반응형