[iOS] 커스텀 알림창 만들기

Make Custom Alert iOS Sample

Posted by JungHoon-Park on May 20, 2019

Sample : iOS Custom Alert


CustomAlert_ios

1.contentViewController 를 이용한 Alert 커스텀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
override func viewDidLoad() {
    super.viewDidLoad()
        
    //기본 알림창 버튼
    let defaultAlertbtn = UIButton(type: .system)
    defaultAlertbtn.frame = CGRect(x: 0 , y: 100, width: 100, height: 30)
    defaultAlertbtn.center.x = self.view.frame.width/2
    defaultAlertbtn.setTitle("커스텀 알림", for: .normal)
    defaultAlertbtn.addTarget(self, action: #selector(defaultAlert(_:)), for: .touchUpInside)
        
    self.view.addSubview(defaultAlertbtn)
}
    
@objc func defaultAlert(_ sender: Any){
    //알림창을 정의
    let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert)
        
    //버튼을 정의
    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
    let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
        
    //알림창에 버튼 추가
    alert.addAction(cancelAction)
    alert.addAction(okAction)
        
    //알림창에 들어갈 뷰 컨트롤러
    let v = UIViewController()
    v.view.backgroundColor = UIColor.gray
    //알림창에 뷰 컨트롤러를 등록
    alert.setValue(v, forKey: "contentViewController")
        
    //알림창 화면에 표시
    self.present(alert, animated: false)
}

2.MapKit 활용한 Alert 띄우기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@objc func mapAlert(_ sender: Any){
    //경고창 객체를 생성하고, ok 및 cancel 버튼을 추가한다.
    let alert = UIAlertController(title: nil, message: "여기가 맞습니까?", preferredStyle: .alert)
        
    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
    let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
        
    alert.addAction(cancelAction)
    alert.addAction(okAction)
            
    //컨텐츠 뷰 영역에 들어갈 뷰 컨트롤러를 생성하고, 알림창에 등록한다.
    let contentVC = UIViewController()
        
    //뷰 컨트롤러에 맵킷 뷰를 추가한다.
    let mapKitView = MKMapView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
    contentVC.view = mapKitView
    contentVC.preferredContentSize.height = 200
        
    //맵킷 설정
    //1.위치 정보를 설정한다. 위/경도를 사용한다.
    let pos = CLLocationCoordinate2D(latitude: 37.514322, longitude: 126.894623)
        
    //2.지도에서 보여줄 넓이.축척/ 숫자가 작을수록 좁은 범위를 확대시켜서 보여준다.
    let span = MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005)
        
    //3.지도 영역을 정의
    let region = MKCoordinateRegion(center: pos, span: span)
        
    //4.지도 뷰에 표시
    mapKitView.region = region
    mapKitView.regionThatFits(region)
        
    //5.위치를 핀으로 표시
    let point = MKPointAnnotation()
    point.coordinate = pos
    mapKitView.addAnnotation(point)
        
    //뷰 컨트롤러를 알림창의 컨텐츠 뷰 컨트롤러 속성에 등록한다.
    alert.setValue(contentVC, forKey: "contentViewController")
        
    self.present(alert, animated: false)
}
  • 코드 분리 (MapKitViewController.swift)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    class MapKitViewController : UIViewController{
      override func viewDidLoad() {
          super.viewDidLoad()
          // 뷰 컨트롤러에 맵킷 뷰를 추가한다.
          let mapKitView = MKMapView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
          self.view = mapKitView
          self.preferredContentSize.height = 200
            
          //표시할 위치
          let pos = CLLocationCoordinate2D(latitude: 37, longitude: 126)
            
          let span = MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005)
            
          //3.지도 영역을 정의
          let region = MKCoordinateRegion(center: pos, span: span)
            
          //4.지도 뷰에 표시
          mapKitView.region = region
          mapKitView.regionThatFits(region)
            
          //5.위치를 핀으로 표시
          let point = MKPointAnnotation()
          point.coordinate = pos
          mapKitView.addAnnotation(point)
      }
    }
    
  • MapAlertViewController 수정
    1
    2
    
    //let contentVC = UIViewController() 코드 삭제
    let contentVC = MapKitViewController()
    

3.이미지 추가 Alert 띄우기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ImageViewController : UIViewController{
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //1.이미지와 이미지 뷰 객체를 생성
        let icon = UIImage(named: "rating5")
        let iconV = UIImageView(image: icon)
        
        //2. 이미지 뷰의 영역과 위치를 지정
        iconV.frame = CGRect(x: 0, y: 0, width: (icon?.size.width)!, height: (icon?.size.height)!)
        
        //3. 루트 뷰에 이미지뷰를 추가
        self.view.addSubview(iconV)
        
        //4. 외부에서 참조할 뷰 컨트롤러 사이즈를 이미지 크기와 동일하게 설정
        self.preferredContentSize = CGSize(width: (icon?.size.width)!, height: (icon?.size.height)!+10)
        
    }
}
  • MapAlertViewController
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    @objc func imageAlert(_ sender: Any){
      let alert = UIAlertController(title: nil, message: "이번 글의 평점은 다음과 같습니다.", preferredStyle: .alert)
            
      let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
      let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
            
      alert.addAction(okAction)
      alert.addAction(cancelAction)
            
      let contentVC = ImageViewController()
      alert.setValue(contentVC, forKey: "contentViewController")
            
      self.present(alert, animated: false)
    }
    

4.UISlider() 이용한 Alert 띄우기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class ControlViewController : UIViewController{
    //슬라이더 객체 정의
    let slider = UISlider()
    
    var sliderValue : Float{
        return self.slider.value
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //슬라이더의 최소값 / 최대값 설정
        self.slider.minimumValue = 0
        self.slider.maximumValue = 100
        
        //슬라이더의 영역과 크기를 정의하고 루트 뷰에 추가한다.
        self.slider.frame = CGRect(x: 0, y: 0, width: 170, height: 30)
        self.view.addSubview(self.slider)
        
        //뷰 컨트롤러의 콘텐츠 사이즈를 지정한다.
        self.preferredContentSize = CGSize(width: self.slider.frame.width, height: self.slider.frame.height + 10)   
    }
}
  • MapAlertViewController
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    @objc func sliderAlert(_ sender : Any){
      //콘텐츠 뷰 영역에 들어갈 뷰 컨트롤러를 생성
      let contentVC = ControlViewController()
            
      //경고창 객체를 생성
      let alert = UIAlertController(title: nil, message: "글의 평점을 입력해주세요", preferredStyle: .alert)
            
      alert.setValue(contentVC, forKey: "contentViewController")
            
      let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
      alert.addAction(okAction)
            
      self.present(alert, animated: false)
    }
    

5.TableView 이용한 Alert 띄우기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class ListViewController : UITableViewController{
    
    var delegate: MapAlertViewController?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.preferredContentSize.height = 220
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 7
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel!.text = "\(indexPath.row) 번째 옵션"
        cell.textLabel!.font = UIFont.systemFont(ofSize: 13)
        return cell
    }
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.delegate?.didSelectRowAt(indexPath: indexPath)
    }
}

MapAlertViewController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@objc func listAlert(_ sender: Any){
    let contentVC = ListViewController()
        
    let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert)
        
    alert.setValue(contentVC, forKey: "contentViewController")
        
    let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
    alert.addAction(okAction)
        
    //델리게이트 객체를 자신으로 지정
    contentVC.delegate = self
        
    self.present(alert, animated: false)
}

Delegate Pattern 사용

- MapAlertViewController 에 함수추가

1
2
3
func didSelectRowAt(indexPath: IndexPath){
    print(">>>선택된 행은\(indexPath.row)")
}

- ListViewController 에 MapAlertViewController 타입의 변수 선언

1
var delegate: MapAlertViewController?

- ListViewController 에 테이블 뷰의 델리게이트 메소드 오버라이드

1
2
3
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    self.delegate?.didSelectRowAt(indexPath: indexPath)
}

- MapAlertViewController 에 델리게이트 메소드 호출 등록

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@objc func listAlert(_ sender: Any){
    let contentVC = ListViewController()

    let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert)
        
    alert.setValue(contentVC, forKey: "contentViewController")
        
    let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
    alert.addAction(okAction)
        
    //델리게이트 객체를 자신으로 지정
    contentVC.delegate = self
        
    self.present(alert, animated: false)
}

소스코드링크(github)