본문 바로가기

iOS/Deep dive!!!

[Swift] UIAlertController 커스텀 하는 방법

 

 UIAlertController를 만들고 title과 action button중간에 textField를 넣을 것이다.

요런식!!

let alert = UIAlertController(title: nil, message: "사용자님 이름을 입력해주세요", preferredStyle: .alert)
let btn   = UIAlertAction(title:확인,style:.default)
{
	(_) in 
    //추후 사용자의 tf 입력시 alert를 종료하면서 다른 view의 label text 갱신할 거에요.
}
alert.addAction(btn)

기본적인 alert 생성하고

  • 첫번째의 경우는
//컨테이너 뷰
let centerView = UIView()
//텍스트 필드
let tf 		   = UITextField()
tf.frame	   = CGRect(x:0,y:0,width: self.view.frame.width,height: 30)
tf.text		   = "홍길동"
centerView.addSubView(tf)
alert.view.addSubview(centerView)

present(alert,animated:false)

이렇게 할 경우

그림1

이렇게 된다..

UIAlertController의 title 이 nil이고 message가 String이 있지만, 반대로 title에 "사용자님 이름을..."으로 해도 centerView의 뷰는 저렇게 0,0에 위치한다.

title, message도 nil 처리 할 경우 여전히 좌표가 0,0이다.

그림2

여기서 궁금한 것은 centerView의 frame을 지정해주지 않았는데, subView는 centerView에 감싸져있는데 centerView는 subView의 CGPoint를 따라가는 것일까?.. 

또한 왜 UIView는 적어도 tf의 크기만큼의 영역을 갖추지 못하는 것일까?..



alert의 view에 addSubview로 추가했기 때문에 당연한 결과이다.

 

여기서 centerView의 constraint를 지정해준다면..

NSLayoutConstraint.activate([
                centerView.bottomAnchor.constraint(equalTo: alert.view.bottomAnchor, constant: -200),
                centerView.heightAnchor.constraint(equalToConstant: 100)
            ])

이런식으로 바뀌게 된다.

 

근데 계속 시도를 해보니 이것보단 UIViewController()를 사용하는게 더 좋은 방안인 것 같다. alert의 center 좌표가 이상해 지는 것 같다. alert의 title이나 message, OK 버튼의 인스턴스나 위치를 얻고 싶었는데 어려웠다. 그래서 textfield의 위치를 정하기가 수작업이아닌 이상.. 나에게는 어려웠다.

 

때에 따라서는 그냥 alert또한 UIAlertController()를 사용하는게 아닌

아예 UIView들로 구성된 틀 안에 label과 button, textfield를 직접 지정해 주면서 Alert처럼 만들었을 때.. 더 쉽게 다룰 수 있을 것 같다. 그래서 현재 UIAlertController에서 UIView를 사용하는 것은 pass...


  • 두번째의 경우는 UIViewController()를 넣는 것이다.
let centerVC = UIViewController()
let tf 		 = UITextField()
tf.frame	 = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 20)
tf.text  	 = "홍길동"
centerVC.view.addSubView(tf)
alert.view.addSubview(centerVC.view)

그림1

이 경우도 위에서 UIView로 선언한 경우와 같이 된다.

 

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

를 추가하면

그림3

이렇게 된다. forkey에 다른 값을 지정해 주면 에러가 발생한다. 그 이유는 contentViewController key값은 apple api에서 정해진 키 값이라고 한다.

contentViewController가 너무 궁금해서 여러 분들에게 조언을 구했는데 알 수 있었다.

setValue를 통해 알림창에 내가 커스텀으로 구현한 UIViewController를 등록할 수 있다. 여기서 중요한것은 위에서 한 UIView와 달리 UIViewController()를 통해 알림창을 커스텀으로 구현하고 setValue(_:forKey:"contentViewController")를 이용한다면 alert의 title과 action버튼 사이에 내가 커스텀으로 정의한 뷰컨트롤러가 끼워져서 구현이 된다.

 

그래서 콘텐츠 뷰 컨트롤러 영역(숨겨진 영역)이라 하나보다(꼼꼼한 재은씨 swift p 393)

 

여기서 content.view의 frame을 조절하면 텍스트 필드의 크기에 맞게 줄을까?

content.view.frame = CGRect(x: 0, y: 0, width: tf.frame.width, height: tf.frame.height)

줄지 않고 그대로 그림3 과 같다.

content.preferredContentSize = CGSize(width: tf.frame.width, height: tf.frame.height)

frame이 아닌 preferredContentSize을 해야 textfield의 사이즈가 조절이 된 content가 된다.


추가적으로 textField의 layer등을 설정하면

tf.textAlignment      = .center
tf.backgroundColor    = .white
tf.layer.cornerRadius = 3
tf.layer.borderColor  = UIColor.lightGray.cgColor
tf.layer.borderWidth  = 0.3

 



요런식의 알림창이 된다.

 

전체적인 코드는

let alert = UIAlertController(title:"사용자님의 이름을 입력해주세요.", message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title:"OK",style: .default) 
{
	(_) in 
    //확인 버튼 이후 실행해야 할것,,
}
contents  = UIViewController()
let tf	  : UITextField = 
{
	let myTf   = UITextField()
    myTf.frame = CGRect(x: 0 ,y:0,width:alert.view.frame.width/2 , height: 30)
    myTf.text  = "홍길동"
    myTf.textAlignment 	 = NSTextAlignment.center
    myTf.backgroundColor = .white
    myTf.layer.cornerRadius = 3
    myTf.layer.borderColor  = UIColor.lightGray.cgColor
    myTf.layer.borderWidth  = 0.3
    return myTf
}()

centerVC.view.addSubview(tf)
centerVC.preferredContentSize = CGSize(width: tf.frame.width, height: tf.frame.height)
alert.view.addSubview(centerVC.view)
alert.setValue(centerVC, forKey: "contentViewController")
self.present(alert,animated: true)

 

꼼꼼한 재은씨를 공부한 알림창!!