[UIAlertController] UIAlertController 기본 사용법부터 커스텀 방법까지 모두 정리해보자

2021. 10. 1. 20:56UIKit, H.I.G

728x90

1️⃣ UIAlertController 기본 용어와 사용법


Alert는 우리말로 "알리다", "경보"라는 뜻을 가지고 있다.

iOS에서는 사용자에게 경고 메시지를 표시하거나, 사용자의 응답을 받기 위한 개체로 UIAlertController라는 기능을 제공하는데, 본격적인 코드를 살펴보기에 앞서 우선 UIAlertController에 쓰이는 용어부터 살펴보자.

가장 상위에 bold처리가 되어 사용자의 주의를 끄는 부분을 title이라 부른다.
그 아래 추가적인 세부 정보를 제공하는 설명 텍스트 부분을 message라 부르고,
아래 버튼들은 UIAlertAction이라는 메서드로 UIAlertController에 각각 연결을 해주어서 사용을 하게 된다.

AlertController를 처음 생성하기 위해서는 title, message, preferredStyle이라는 세 개의 매개변수를 받게 된다.

title과 message는 위에 설명했던 용어와 같고, preferredStyle은 말그대로 AlertController의 스타일을 입력받는 곳이다.
스타일은 .actionSheet와 .alert로 구분된다.

다시 말해 액션 시트(actionSheet)를 구현하는 방법은 style을 제외하고, 오늘 다룰 AlertController와 동일하다는 뜻이다.

왼쪽이 alert style, 오른쪽이 actionsheet style

버튼을 추가하기 위해서는 UIAlertAction으로 선언한 객체를 만들어서, AlertController에 addAction 메서드로 넣어주면 된다.

alertAction은 액션 버튼의 이름을 나타내는 title, 그리고 버튼의 스타일을 정의하는 style, 그리고 버튼을 누른 이후의 작업을 정의할 Completion Handler로 인수를 받아 사용하게 된다.

UIAlertAction 스타일은 .default .cancel .destructive 3가지를 제공한다.
default는 기본 스타일, cancel은 강조하고 싶을 때 사용 (기본 스타일에 볼드가 적용), destructive는 삭제와 같은 파괴 액션에 사용 (빨간색 글씨 색 적용) 할 수 있도록 구분되어 있다.

UIAlertController에 정의할 수 있는 액션의 개수는 일반적으로 제한이 없다.

하지만 일반적으로 Alert 스타일에서는 2개 이하까지 양 옆쪽으로 배치되는 자연스러운 레이아웃을 제공하고, 3개 이상의 액션부터는 수직으로 배치되기 때문에 2개 이하의 액션일 경우에는 .alert 스타일을, 3개 이상의 액션일 경우에는 .actionSheet 스타일을 권장하는 편이다.
*화면에 표시될 수 있는 액션의 개수를 초과하는 경우에는 스크롤 되는 레이아웃을 제공한다.

AlertController에 추가된 Action 개수에 따른 레이아웃의 변화, 그리고 AlertAction의 style에 따라 제공되는 Action 버튼의 변화

그리고 당연하게도, AlertController는 present 방식으로 사용자에게 표출된다.

만약 프로젝트에서 비슷한 형태의 Alert가 반복되는 형태라면,
ViewController Extension에 따로 선언해두고, 필요할 때마다 메서드를 불러와서 사용하는 방법도 고려해볼 수 있겠다.

아래는 Extension에 makeAlert라는 이름의 함수로 따로 구현을 해서 사용한 예시 코드이다.

// Alert창 구현 Extension
extension TestViewController
{
    func makeAlert(title: String,
                   message: String,
                   cancelAction: ((UIAlertAction) -> Void)? = nil,
                   deleteAction: ((UIAlertAction) -> Void)? = nil,
                   completion: (() -> Void)? = nil)
    {
        let alertViewController = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
        
        let cancelAction = UIAlertAction(title: "취소", style: .cancel, handler: cancelAction)
        alertViewController.addAction(cancelAction)
        
        let deleteAction = UIAlertAction(title: "삭제", style: .default, handler: deleteAction)
        alertViewController.addAction(deleteAction)
        
        self.present(alertViewController, animated: true, completion: completion)
    }
}

// 다음 버튼 클릭 시
@IBAction func nextButtonClicked(_ sender: Any) {
	self.makeAlert(title: "명함 삭제", message: "명함을 정말 삭제하시겠습니까?", cancelAction: { _ in
    	// 취소 눌렀을 때 액션이 들어갈 부분
	}, deleteAction: { _ in
        // 삭제 눌렀을 때 액션이 들어갈 부분
    })
}

 

2️⃣ UIAlertController 커스텀해서 사용하기 (1) : 배경색 변경


지금부터는 기본적으로 제공해주는 UIAlertController를 직접 커스텀해서 사용하는 방법에 대해 설명해보겠다.
먼저, 배경색을 변경해주는 방법에 대해 알아보자.

일반적으로 떠오르는 방식은 아래 코드와 같이 AlertController의 view에 백그라운드 색상을 적용하는 방법일 것이다.

alertController.view.backgroundColor = .black

하지만 위 코드로 색상을 지정해주면, 아래와 같은 이상한 곳에 배경색이 지정되는 것을 확인할 수 있었다.

엥? 도대체 어디에 배경색이 지정되는거지?하고 뷰 계층을 살펴보았는데, 생각보다 계층이 엄청 복잡한 것을 확인할 수 있었다.
첫번째 뷰의 백그라운드 컬러를 지정해주니, 이는 UIAlertContollerPhoneTVMacView라는 이상한 뷰에 적용이 되고 있었던 것!

즉, 내가 원하는 색상 지정 공간까지 가려면 꽤 많은 계층을 거슬러 올라가야했던 것이다.

처음 적용되었던 Background Color 적용 부분

해당 문제는 subviews.first?.의 반복된 계층 진입으로 해결할 수 있었으며,
본격적으로 AlertController의 색상을 적용시키기 위해서는 두 계층을 더 안으로 들어가 UIVIew의 색상을 변경시켜주게 된다.

alertViewController.view.subviews.first?.subviews.first?.subviews.first?.backgroundColor = UIColor

계층 안으로 들어가 BackgroundColor를 변경해준 레이아웃 계층

 

3️⃣ UIAlertController 커스텀해서 사용하기 (2) : 버튼색 변경


버튼색은 위에서 말했듯이 ButtonAction의 스타일로 기본 제공해주는 스타일을 구분할 수도 있지만,
tintColor라는 속성을 지정해서 변경해줄 수도 있다.

alertController.view.tintColor = .red

tintColor를 적용해 버튼 변경

 

4️⃣ UIAlertController 커스텀해서 사용하기 (3) : Title과 Message의 Text 속성을 변경해주기


attributedString이라는 속성을 지정해서 타이틀 혹은 Message의 폰트와 색상을 변경해줄 것이다.

아래와 같이 Extension으로 분리해서 사용하면 더 편하게 사용할 수 있으며, AlertController의 하위 메서드 형태로 지정해서 사용하면 되겠다.

extension UIAlertController {
    // 타이틀 폰트, 색상 바꾸는 메서드
    func setTitle(font: UIFont?, color: UIColor?) {
        guard let title = self.title else { return }
        let attributeString = NSMutableAttributedString(string: title)
        
        if let titleFont = font {
            attributeString.addAttributes([NSAttributedString.Key.font: titleFont],
                                          range: NSRange(location: 0, length: title.count))
        }
        if let titleColor = color {
            attributeString.addAttributes([NSAttributedString.Key.foregroundColor: titleColor],
                                          range: NSRange(location: 0, length: title.count))
        }
        self.setValue(attributeString, forKey: "attributedTitle")
        
    }

    // 메시지 폰트, 색상 바꾸는 메서드
    func setMessage(font: UIFont?, color: UIColor?) {
        guard let message = self.message else { return }
        let attributeString = NSMutableAttributedString(string: message)
        if let messageFont = font {
            attributeString.addAttributes([NSAttributedString.Key.font: messageFont],
                                          range: NSRange(location: 0, length: message.count))
        }
        
        if let messageColorColor = color {
            attributeString.addAttributes([NSAttributedString.Key.foregroundColor: messageColorColor],
                                          range: NSRange(location: 0, length: message.count))
            
        }
        self.setValue(attributeString, forKey: "attributedMessage")
    }
}
728x90