본문 바로가기

MOBILE/ios

[iOS] UIKit 알림창 UIAlertController customizing 하기

UIKit에서 알림창을 띄우는 객체는 UIAlertController이다. 경고창과 액션 시트 두 가지를 모두 구현 가능하며 다음과 같이 구현할 수 있다.

 

1. Alert 구현

let alert = UIAlertController(title: "Alert", message: "Alert창 입니다.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true);

 

위와 같이 알림창의 버튼은 UIAlertAction 객체이며 이 객체를 addAction 메소드를 사용하여 UIAlertController 객체에 추가해줘야 한다.

 

 

2. Action Sheet 구현

let alert = UIAlertController(title: "Action Sheet", message: "Action Sheet창 입니다.", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alert, animated: true)

 

 

 

 

3. 커스터마이징

UIAlertController의 커스터마이징은 제한적이다. 하지만 private API를 사용해서 커스터마이징 하는 방법이 하나 있다.

알림창은 3가지 영역으로 나누어진다. 타이틀과 메시지가 들어가는 영역, 텍스트 필드의 영역, 버튼이 있는 영역이다.

이 때 텍스트 필드 영역과 버튼 영역 사이에는 contentViewController 가 들어간다.

따라서 이 contentViewController 영역에 view를 설정해서 넣어주는 형태로 커스터마이징이 가능하며, 이때 setValue() 메소드를 사용할 수 있다.

 

alert.setValue(view, forKey: "contentViewController")

 

4. 커스터마이징 예시: image 추가하기

알림창에 이미지를 넣어서 커스터마이징 해보도록 하자.

기본적인 코드는 위에서 알림창을 사용했을 때와 똑같이 진행된다.

 

이미지 뷰를 설정하기 위한 controller 파일을 따로 생성해서 다음과 같이 이미지 뷰 작업을 해준다.

 

class ImgViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

	// UIImage 객체
        let data = UIImage(named: "dessert.jpg")
        
        // UIImageView 객체
        let imgView = UIImageView(image: data)
        imgView.frame = CGRect(x: 0, y: 0, width: 300, height: 500)
        
        self.view.addSubview(imgView)
        
        // 외부에서 참조할 때의 사이즈를 이미지와 똑같이 설정
        self.preferredContentSize = CGSize(width: 300, height: 510)
    }
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    @IBAction func doAlert(_ sender: Any) {
        let alert = UIAlertController(title: "Alert", message: "Alert창 입니다.", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        
        // 커스터마이징 영역
        let customize = ImgViewController()
        alert.setValue(customize, forKey: "contentViewController")
        
        self.present(alert, animated: true);
    }
}

 

이때 perferredContentSize 속성을 통해서 외부 객체가 ImageViewController를 나타낼때 참고할 사이즈를 지정한다. 이때 사이즈는 이미지 객체의 크기를 기준으로 하여서 설정한다.

 

결과는 다음과 같다.

 

알림창에 이미지가 들어가있음

 

5. 커스터마이징 예시: 컨트롤 추가하기

커스터마이징을 하는 contentViewController 영역은 컨트롤을 넣어서 유저의 입력을 받을 수도 있다.

알림창에 slider를 넣는 예시를 해보자. 

 

UI는 다음과 같다. 사용자는 알림창의 slider로 값을 조정하고, 이 값을 받아서 화면에 나타내자.

 

 

먼저 slider view controller는 다음과 같다.

// slider view controller

class ControlViewController: UIViewController {

    // slier 객체 생성
    private let slider = UISlider()
    
    var value: Float{
        return self.slider.value
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // slider의 최소 최대 결정
        slider.maximumValue = 100
        slider.minimumValue = 0
        
        slider.frame = CGRect(x: 0, y: 0, width: 170, height: 40)
        self.view.addSubview(slider)
        
        self.preferredContentSize = CGSize(width: slider.frame.width, height: slider.frame.height)
    }

}

 

이때 뷰 컨트롤러에 추가된 객체는 외부에서 참조될 수 없도록 하는 것이 좋다는 구조상의 설계에 따라 slider 객체는 private으로 선언하였다. 객체를 외부에서 참조하는 것은 오류의 가능성이 많기 때문이다. 따라서 private으로 선언하고 값을 읽을 수 있도록 연산 프로퍼티를 제공하는 방식으로 구현하였다.

 

class ViewController: UIViewController {
    @IBOutlet weak var txt: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    @IBAction func doAlert(_ sender: Any) {
        let slider = ControlViewController()
        
        let alert = UIAlertController(title: "Alert", message: "Alert창 입니다.", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default) { (_) in
            self.txt.text = "value: \(slider.value)"
        })
        
        alert.setValue(slider, forKey: "contentViewController")
        
        self.present(alert, animated: true);
    }
}

 

이때 사용자가 slider의 값을 조정하고 OK 버튼을 눌렀을 때 화면의 label에 slider의 값을 보여줘야 하기 때문에 UIAlertAction의 handler에 text를 바꾸는 코드를 넣었다. 이때 trailing closure를 사용하였다.

 

결과는 다음과 같다.

slider를 조정할 수 있다.

 

 

그 결과를 받아서 사용할 수 있다.