![]() | ![]() | ![]() |
|---|---|---|
| 아이폰 SE | 아이폰 15 Pro | 아이폰 16 Pro |
alertHighlightView의 centerY를 Safe Area Insets 또는 Navigation Bar의 높이를 기준으로 설정하려 했으나, 특정 디바이스에서 값이 예상대로 동작하지 않았음.
앱에서 사용자 권한 설정을 요청하는 UIAlertController를 표시하면서, 사용자에게 권한 요청을 강조하기 위해 alertHighlightView와 화살표(arrowImageView)를 알럿 주변에 배치하려고 했다. 그러나 디바이스와 화면 크기마다 알럿의 위치가 다르기 때문에 정확히 alertHighlightView의 centerY를 계산하는 데 어려움을 겪었다.
permissionView.alertHighlightView.snp.makeConstraints {
$0.centerY.equalToSuperview().offset(-100)
}
alertHighlightView의 위치가 알럿과 겹치거나, 너무 멀리 떨어지는 문제가 발생.permissionView.alertHighlightView.snp.makeConstraints {
$0.centerY.equalToSuperview().offset((navigationController?.navigationBar.frame.minY ?? 0) / 2)
}
alertHighlightView를 배치.frame.minY 값이 0으로 반환되는 문제가 발생.permissionView.alertHighlightView.snp.makeConstraints {
$0.centerY.equalToSuperview().offset(view.safeAreaInsets.top / 2)
}
viewDidAppear 이전에는 safeAreaInsets 값이 0으로 반환되므로, 정확한 위치를 계산할 수 없음.UIAlertController가 렌더링된 후 실제 위치와 높이를 가져와 동적으로 alertHighlightView를 배치하는 방법으로 해결할 수 있었다.
![]() | ![]() |
|---|---|
| 아이폰 SE | 아이폰 16 Pro |
alertHighlightView의 위치를 동적으로 조정.alertHighlightView가 항상 정확히 정렬.private func showPermissionSystemAlert() {
let alert = UIAlertController(
title: "'STAR' 앱이 스크린타임에 접근하려고 함",
message: """
'STAR'에 스크린타임 접근을 허용하면,
이 앱이 사용자의 활동 데이터를 보고,
콘텐츠를 제한하며, 앱 및 웹사이트의
사용을 제한할 수도 있습니다.
""",
preferredStyle: .alert
)
let denyAction = UIAlertAction(title: "허용 안 함", style: .cancel, handler: { _ in
self.navigateToStarList()
})
alert.addAction(denyAction)
let allowAction = UIAlertAction(title: "허용", style: .default, handler: { _ in
print("허용")
})
alert.addAction(allowAction)
alert.preferredAction = allowAction
/// 다크모드
if #available(iOS 13.0, *) {
alert.overrideUserInterfaceStyle = .dark
}
**present(alert, animated: true) {
let alertHeight = alert.view.frame.height
let alertCenterY = alert.view.frame.midY
self.permissionView.updateAlertHighlightViewY(alertCenterY: alertCenterY, alertHeight: alertHeight)
}**
}
func updateAlertHighlightViewY(alertCenterY: CGFloat, alertHeight: CGFloat) {
let screenHeight = UIScreen.main.bounds.height
let offset = alertCenterY - (screenHeight / 2)
alertHighlightView.snp.makeConstraints{
$0.centerY.equalToSuperview().offset(offset)
}
layoutIfNeeded()
}
alert.view.frame 값을 반영할 수 있었음present(alert, animated: true) 완료 핸들러 안에서 alert.view.frame 값을 읽으면 UIAlertController가 화면에 렌덜이된 후의 프레임을 가져온다고 함
그래서 시스템 알럿의 실제 높이와 중앙 Y 좌표를 계산할 수 있었음
문제 전: 알럿 렌더링 되기 전에 값을 읽으려 해서 해결이 안되었던 것 같음
문제 해결 후: 렌더링 완료 후의 값을 사용해서 정확한 높이와 중앙 Y좌표 값을 가져올 수 있었따.
screenHeight / 2)이랑 시스템 알럿의 중앙(alertCenterY) 간의 차이를 계산해, 그 차이를 offset으로 정의 후 alertHighlightView의 위치에 반영할 수 있었삼.centerY 제약 조건을 동적으로 업데이트하면서, 알럿과 alertHighlightView의 상대적 위치를 일관되게 유지할 수 있었음.let offset = alertCenterY - (screenHeight / 2)
alertCenterY 시스템 알럿 중앙 좌표screenHeight / 2 화면의 중앙 좌표offset 시스템 알럿 중앙이 화면 중앙에서 얼마나 벗어나 있는지 계산… 첨부터 중앙에 있을 것이지…..updateAlertHighlightViewY메서드 생성 후 alertHighlightView.snp.makeConstraints를 다시 호출해, 기존 제약 조건에서 업데이트 해줌.alertHighlightView.snp.makeConstraints {
$0.centerX.equalToSuperview()
$0.width.equalTo(270 + 28)
$0.height.equalTo(195 + 28)
}func updateAlertHighlightViewY(alertCenterY: CGFloat, alertHeight: CGFloat) {
let screenHeight = UIScreen.main.bounds.height
let offset = alertCenterY - (screenHeight / 2)
**alertHighlightView.snp.makeConstraints{
$0.centerY.equalToSuperview().offset(offset)
}**
layoutIfNeeded()
}layoutIfNeeded()로 즉시 적용layoutIfNeeded()를 호출하여, 변경된 제약 조건을 즉시 화면에 반영함