본문 바로가기
감정일기(가칭)

Popover 위에 “어두운 배경(딤)” 깔고 싶다

by 밤새는 탐험가89 2025. 11. 19.
728x90
SMALL

나는 일기 작성 화면(DiaryEditorViewController) 에서 날짜 셀을 누르면
CustomCalendarViewController 를 popover 형태로 띄우고 있었지:

cell.onTapDate = { [weak self] in
    guard let self else { return }

    let calendarVC = CustomCalendarViewController(initializedDate: diaryEditorVM.diary.createdAt) { selectedDate in
        cell.configure(date: selectedDate)
        self.diaryEditorVM.diary.createdAt = selectedDate
    }

    calendarVC.modalPresentationStyle = .popover
    calendarVC.preferredContentSize = CGSize(width: 320, height: 280)

    if let popover = calendarVC.popoverPresentationController {
        popover.sourceView = self.view
        popover.sourceRect = CGRect(
            x: self.view.bounds.midX,
            y: self.view.bounds.midY,
            width: 0,
            height: 0
        )
        popover.delegate = self
        popover.permittedArrowDirections = []
    }

    self.present(calendarVC, animated: true)
}

 

여기까지는 잘 동작하는데,
캘린더가 뜰 때 뒤 배경을 살짝 어둡게(dimming) 만들고 싶은 욕심이 생김.

문제는…

 

modalPresentationStyle = .popover 인 경우, UIKit이 기본으로 “딤 배경”을 안 깔아준다.

그냥 뒤쪽이 투명하게 보인다.

 

그래서 배경을 어둡게 하고 싶으면 직접 구현해야 한다.

 


첫 번째 시도: CustomCalendarViewController 안에 dimView 넣기

처음 제안은 아주 단순했어.

class CustomCalendarViewController: UIViewController {

    private let dimView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.black.withAlphaComponent(0.3)
        view.alpha = 0
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(dimView)
        dimView.frame = view.bounds

        UIView.animate(withDuration: 0.2) {
            self.dimView.alpha = 1
        }
    }
}

 

❗️CustomCalendarViewController는 “공용”으로 여러 화면에서 재사용할 예정인데,
거기 안에 dimView를 넣어버리면 캘린더가 자기 뒤 배경까지 책임지는 이상한 구조가 되어버린다.

 

그래서 dim 처리는 캘린더 내부가 아니라, “캘린더를 띄우는 쪽(부모 ViewController)”에서 관리하는 게 더 맞는 구조라는 결론이 나왔다.


최종 설계: “딤 배경”은 Presenting ViewController가 관리한다

우리가 최종적으로 선택한 방식은:

 

📌 공통으로 쓸 수 있는 UIViewController Extension을 만들고,
필요한 화면에서 showDim(), hideDim()만 호출해서 배경을 어둡게/원래대로 만들기


UIViewController Extension으로 dimView 공통화

import UIKit

extension UIViewController {

    // 딤 뷰를 찾기 위한 고유 태그
    private var dimViewTag: Int { 987654 }

    /// 배경을 어둡게(딤) 깔기
    func showDim(animated: Bool = true, alpha: CGFloat = 0.35) {
        // 이미 dimView가 있으면 다시 만들지 않음
        if let _ = view.viewWithTag(dimViewTag) { return }

        let dim = UIView(frame: view.bounds)
        dim.backgroundColor = UIColor.black.withAlphaComponent(alpha)
        dim.alpha = 0
        dim.tag = dimViewTag
        view.addSubview(dim)

        if animated {
            UIView.animate(withDuration: 0.25) {
                dim.alpha = 1
            }
        } else {
            dim.alpha = 1
        }
    }

    /// 깔려 있는 딤 배경 제거
    func hideDim(animated: Bool = true) {
        guard let dim = view.viewWithTag(dimViewTag) else { return }

        if animated {
            UIView.animate(withDuration: 0.25, animations: {
                dim.alpha = 0
            }) { _ in
                dim.removeFromSuperview()
            }
        } else {
            dim.removeFromSuperview()
        }
    }
}

 

private var dimViewTag: Int { 987654 }

 

 

UIView에는 tag: Int 라는 속성이 있어서,

-> view.viewWithTag(숫자) 로 나중에 다시 찾을 수 있음

 

우리는 딤 배경 뷰를 나중에 다시 찾아서 제거해야 하니까
이 뷰에 고유한 tag 값을 하나 박아둔 것이야.

 

숫자 자체에는 특별한 의미는 없고,

-> 다른 뷰들과 겹치지 않을 것 같은 “적당히 큰 값”을 넣어준 것뿐이야.

-> 예: 999, 123456, 987654 등 아무거나 상관 없음

 

중요한 건 계속 일관되게 같은 숫자를 써야 한다는 점.

 

 

showDim() → 새로운 dimView를 만들고 tag = 987654로 설정

hideDim() → view.viewWithTag(987654)로 찾아서 제거


실제 적용 예시: Date 셀 눌렀을 때 dim + popover 띄우기

이제 이걸 DiaryEditorViewController 에 적용해 보자.

case .date:
    guard let cell = collectionView.dequeueReusableCell(
        withReuseIdentifier: DiaryDateCell.reuseIdentifier,
        for: indexPath
    ) as? DiaryDateCell else {
        return UICollectionViewCell()
    }

    cell.configure(date: Date())

    cell.onTapDate = { [weak self] in
        guard let self else { return }

        // 🔥 1) 딤 배경 깔기
        self.showDim()

        // 🔥 2) 캘린더 VC 생성
        let calendarVC = CustomCalendarViewController(initializedDate: diaryEditorVM.diary.createdAt) { selectedDate in
            print("선택된 날짜:", selectedDate)
            cell.configure(date: selectedDate)
            self.diaryEditorVM.diary.createdAt = selectedDate
        }

        calendarVC.modalPresentationStyle = .popover
        calendarVC.preferredContentSize = CGSize(width: 320, height: 280)

        if let popover = calendarVC.popoverPresentationController {
            popover.sourceView = self.view
            popover.sourceRect = CGRect(
                x: self.view.bounds.midX,
                y: self.view.bounds.midY,
                width: 0,
                height: 0
            )
            popover.delegate = self
            popover.permittedArrowDirections = []
        }

        // 🔥 3) 캘린더 표시
        self.present(calendarVC, animated: true)
    }

    return cell

마무리

요약하면, 이 글의 핵심은:

 

1. popover는 기본적으로 배경 딤 처리가 없다.

 

2. 딤 처리를 캘린더 VC 내부에 넣어버리면 “공용 컴포넌트”로 쓰기 불편해진다.

 

3. 그래서 UIViewController Extension으로 dimView를 관리하는 공통 함수를 만들고,

-> showDim()으로 깔고

-> hideDim()으로 지우는 흐름으로 구현했다.

 

4. tag는 딤 뷰를 다시 찾고 제거하기 위한 식별자일 뿐이고,
-> 다른 뷰와 겹치지 않을 만큼 유니크하게만 정해주면 된다.

 

728x90
LIST