iOS에는 다양하고 예쁜 기본 UI 컴포넌트를 제공해준다 ! 버튼, 텍스트 필드, 이미지뷰, 스위치 컨트롤 등 ... 애플 기본 앱에서 많이 보이는 바로 그것들 ! 그런데 안드로이드에는 있는 그것을 제공해주지 않는다 ... 바로 토스트 메시지 ...
기본 제공이 안 되는 걸 보니 아마도 권장하지 않는 것 같은데 ~.. 간단한 정보나 알림을 잠시동안 보여주는 데 토스트 메시지만한 것이 없다고 생각했는지 많은 개발자들이 직접 구현해서 사용하는 것 같다. ( 나도 그렇게 생각 ... )
어떻게 구현할 수 있을까 ?
현재 뷰컨트롤러에 뷰를 붙여서 UIView.animate() 메서드을 통해 잠시 나타났다가 사라지는 형태로 구현할 수 있을 것 같다. extension을 사용하여 UIView에 토스트 메시지를 보여주는 기능을 확장하면 모든 뷰에서 사용할 수 있을 것이다. 실제로 구현해보니 충분히 잘 동작했다.
extension UIView {
func makeToast(_ message: String) {
// UI
let backView = UIView()
backView.backgroundColor = .black.withAlphaComponent(0.7)
backView.layer.cornerRadius = 15
let messageLabel = UILabel()
messageLabel.text = message
messageLabel.textColor = .white
messageLabel.font = UIFont.systemFont(ofSize: 13)
messageLabel.sizeToFit()
self.addSubview(backView)
backView.addSubview(messageLabel)
// 제약사항
backView.snp.makeConstraints {
$0.width.equalTo(messageLabel.snp.width).multipliedBy(1.5)
$0.height.equalTo(messageLabel.snp.height).multipliedBy(2)
$0.centerX.equalToSuperview()
$0.bottom.equalToSuperview().inset(200)
}
messageLabel.snp.makeConstraints {
$0.center.equalToSuperview()
}
// 애니메이션
UIView.animate(withDuration: 1.0, delay: 1.5, options: .curveEaseIn, animations: {
backView.alpha = 0.0
}) { _ in
messageLabel.removeFromSuperview()
backView.removeFromSuperview()
}
}
}
그런데 문제가 있다 !
예를 들어, UINavigationController 또는 UITabBarController 안에서 토스트 메시지 함수를 호출한 후 뷰 컨트롤러를 이동했다면 ? 토스트 메시지가 뷰 컨트롤러와 함께 사라지는 일이 발생할 것이다 … 아래처럼 !

그럼 어떻게 해결할 수 있을까 ?
예전에 UIWindow를 공부하면서 궁금했던 점이 있었다. 아래는 당시에 내가 정리해 놓은 글의 일부이다.
- 앱에서 화면을 관리하는 컨테이너 역할을 한다.
- 주로 기기의 main window에 앱의 인터페이스를 표시하는 데 사용된다.
- 외부 화면에 콘텐츠를 표시하는 등의 특정 목적으로 추가적인 window를 만들 수 있다.
- 창의 Z-축 레벨을 설정하여 창의 가시성을 관리할 수 있다.
- 키보드 이벤트 대상으로 창을 지정할 수 있다.
- 창에 속한 뷰들을 관리하는 류트 뷰 컨트롤러를 변경할 수 있다.
궁금했던 부분은 (1)특정 목적으로 추가적인 window을 만들 수 있다 (2)창의 Z-축 레벨을 설정하여 창의 가시성을 관리할 수 있다 인데 ... 검색을 해도 외부 디바이스 등에 사용한다는 그닥 와닿지 않는 설명밖에 없어서 이해를 포기하고 글로만 남겨뒀었다 ( 그러면 안 됨 )
그런데 토스트 메시지 구현 고민을 하다가 갑자기 이게 생각이 났다 !!!!!!!!!!!!!!!! 추가적인 window를 만들어서 키 윈도우 위에 Z-축으로 쌓아서 보여주면 뷰 컨트롤러가 이동해도 변함없이 보여지겠구나 !!!!!!!!!!! ( 별 거 아닐 수 있지만 매우매우 기뻤당 )
final class Toast {
// MARK: - Properties
private var window: UIWindow? // 추가적으로 만들 window 객체
private var backView = UIView().then {
$0.backgroundColor = .black.withAlphaComponent(0.7)
$0.layer.cornerRadius = 15
}
private var messageLabel = UILabel().then {
$0.textColor = .white
$0.font = UIFont.systemFont(ofSize: 13)
$0.sizeToFit()
}
// MARK: - Initializer
static let shared = Toast() // singleton
private init() {
configureUI()
}
// MARK: - Configure UI
private func configureUI() {
// window 객체 생성
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
else { return }
window = UIWindow(windowScene: windowScene)
window?.windowLevel = .alert // 디폴트는 normal
window?.isUserInteractionEnabled = false // 터치 이벤트 무시하도록
print("window 개수 : \(windowScene.windows.count)")
// 서브뷰 추가
window?.addSubview(backView)
backView.addSubview(messageLabel)
// 뷰 제약사항
backView.snp.makeConstraints {
$0.width.equalTo(messageLabel.snp.width).multipliedBy(1.5)
$0.height.equalTo(messageLabel.snp.height).multipliedBy(2)
$0.centerX.equalToSuperview()
$0.bottom.equalToSuperview().inset(200)
}
messageLabel.snp.makeConstraints {
$0.center.equalToSuperview()
}
}
// MARK: - Make Toast !!! 🍞
func makeToast(_ message: String) {
messageLabel.text = message
window?.isHidden = false
UIView.animate(withDuration: 1.0, delay: 1.5, options: .curveEaseIn, animations: {
self.window?.alpha = 0.0
}) { _ in
self.window?.isHidden = true
self.window?.alpha = 1.0
}
}
}
야무지게 정말로 window 개수가 늘어나는지 출력도 해보았당 ... 결과는 ?

예상대로 아주 잘 동작한다 뿌듯 <3
내친김에 배포까지 ..!
이걸 오픈 소스 라이브러리로 만들어보면 너무 좋은 경험이 될 것 같아서 UI 기능을 조금 추가하여 바로 배포했다. SPM과 CocoaPods 두 가지를 사용했는데,
1. SPM은 단순히 Github 저장소에 소스를 업로드해두면 Xcode에서 바로 사용할 수 있었고
2. CocosPods은 Pod에 등록 및 배포를 하는 과정이 필요하지만, Github 저장소 링크 및 설정 파일 등 몇 가지 정보만 입력하면 쉽게 할 수 있었다.
SwiftyToaster Github : https://github.com/noeyiz/SwiftyToaster
GitHub - noeyiz/SwiftyToaster: 🍞✨ Toaster for Swift
🍞✨ Toaster for Swift. Contribute to noeyiz/SwiftyToaster development by creating an account on GitHub.
github.com
SwiftyToaster CocoaPods : https://cocoapods.org/pods/SwiftyToaster
SwiftyToaster
🍞 Toaster for Swift
cocoapods.org
마지막은 귀여운 CocoaPods 배포 성공 메시지 !

'iOS 🍎 Swift' 카테고리의 다른 글
Xcode 메모리 누수 체크하기 (2) | 2024.08.05 |
---|---|
Github OAuth 앱 스토어 심사 (iOS에서 URL을 여는 방법) (8) | 2024.07.18 |
iOS 민감한 정보 숨기기 (0) | 2024.07.18 |
타겟 간 같은 Realm 저장소 사용하기 (feat. Tuist) (0) | 2024.07.18 |
Tuist 환경에서 Xcode Cloud CI/CD 구축 (1) | 2024.07.15 |