아이폰마다 생김새가 조금씩 다름
어떤 기기는 노치가 있고 어떤 기기는 없고
홈바나 상태 표시줄도 크기가 다를 수 있음
그래서 화면에서 안전하게 보여야 할 영역을 정해둔 것.
한 마디로
앱이 안전하게 내용을 보여줄 수 있는 구역
이걸 지켜서 UI를 만들면 어떤 기기에서 보더라도 잘려나가지 않고 깔끔하게 보여줄 수 있음
기기 크기마다 화면이 다르게 생겼는데
ex) 작은 아이폰, 큰 아이패드...
그럴 때 각 기기에 맞춰서 UI 크기랑 위치를 자동으로 조정해주는 시스템.
예를 들어 사진을 화면 위쪽에 고정하고 싶을 때
그냥 그림 위치만 맞춰두면 기기 바뀌면 이상해지는데
위쪽에서 몇 만큼 떨어지게 해달라고 설정하면 기기 크기에 맞게 자동으로 조정됨
오토 레이아웃은 어떻게 배치할지 규칙이 있어야 작동하는데
이 규칙이 Constraint.
top / bottom / left / right : 화면 위/아래/왼쪽/오른쪽과의 거리
leading / trailing : 왼쪽에서 오른쪽으로 읽는 나라에서는
leading = 왼쪽, trailing = 오른쪽
반대로 읽는 나라는 반대
이걸 설정해두면 어떤 기기든 내가 원하는 모양으로 유지됨
👉 밖의 여백
요소와 요소 사이 간격을 띄우고 싶을 때 사용
👉 안의 여백
내용이 너무 테두리에 붙지 않게 안쪽 여백을 넣는 것
ex) 사진이 너무 테두리에 딱 붙어 있다고 가정하면 UI적으로 안 예쁘고 답답하니까 Padding을 넣어서 안쪽 공간을 확보하는 것
리스트 형태로 보여줄 때 사용
하나하나의 줄은 UITableViewCell
그리드 형태도 만들 수 있음
하나하나의 박스는 UICollectionViewCell이
사용자에게 메시지를 띄울 때 사용
정말 삭제할까요? 같은 확인창
글을 입력하는 칸
댓글 쓰는 거..?
페이지를 넘기듯 옆으로 쓱쓱 넘기는 뷰
인스타그램 스토리 느낌인 듯
사실 지금까지 SwiftUI만 썼어서
UIKit을 다루는 게 처음....인데
UI를 다루게 돼서 좀 당황스러웠다..!!!!!!!
그래도 튜터님의 강의를 듣고 감을 잡아보긴 함
실습!!도 재미있었는데
올려도 되는지 솔직히 잘 모르겠지만
코드 분석만 좀 깔짝거려 보자면
contentView.snp.makeConstraints {
$0.top.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(20)
}
상단, 좌우를 safeArea 기준으로 20pt 인셋을 줌
bottom은 설정하지 않아서 내부 내용 높이에 따라 크기 자동 결정
$0.top.leading.trailing.equalToSuperview()
$0.height.equalTo(profileImageView.snp.width).multipliedBy(0.75)
상단, 좌우는 contentView에 꽉 채움
높이는 가로 폭의 0.75배로 설정 → 비율 기반 제약
let infoLayoutGuide = UILayoutGuide()
infoLayoutGuide.snp.makeConstraints {
$0.top.equalTo(profileImageView.snp.bottom).offset(20)
$0.leading.trailing.bottom.equalToSuperview().inset(20)
}
이미지 아래부터 아래 여백까지 텍스트와 버튼들이 들어가는 가이드라인 설정
뷰가 아니라 가이드라인이라 화면에 보이지 않지만 정렬 기준으로 유용함
nameLabel.snp.makeConstraints {
$0.top.leading.equalTo(infoLayoutGuide)
}
introLabel.snp.makeConstraints {
$0.top.equalTo(nameLabel.snp.bottom).offset(10)
$0.leading.trailing.equalTo(infoLayoutGuide)
}
nameLabel은 infoLayoutGuide 왼쪽 상단 기준
introLabel은 nameLabel 아래에 10pt 여백으로 위치
introLabel은 좌우 꽉 채움 + 여러 줄 허용 (numberOfLines = 0)
let buttonStackView = UIStackView().then {
$0.axis = .horizontal
$0.spacing = 10
$0.distribution = .fill
}
두 버튼을 수평으로 나열
spacing은 두 버튼 사이 여백
buttonStackView.snp.makeConstraints {
$0.top.equalTo(introLabel.snp.bottom).offset(20)
$0.leading.trailing.bottom.equalTo(infoLayoutGuide)
}
버튼 스택은 introLabel 하단에 위치
좌우는 infoLayoutGuide에 맞춤
bottom도 infoLayoutGuide로 설정해 contentView의 하단이 결정됨
addToPlaylistButton.setContentHuggingPriority(.required, for: .horizontal)
두 버튼 중 addToPlaylistButton이 자신의 콘텐츠 넓이에 딱 맞춰지도록 우선순위 줌 → 버튼 크기 비율 조절에 사용
contentView.snp.makeConstraints {
// 카드 컨테이너 레이아웃
$0.top.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(20)
}
profileImageView.snp.makeConstraints {
// 프로필 이미지 레이아웃
$0.top.leading.trailing.equalToSuperview()
$0.height.equalTo(profileImageView.snp.width).multipliedBy(0.75)
}
nameLabel.snp.makeConstraints {
// 이름 레이아웃 구성 (가능하면 infoLayoutGuide 사용해보기)
$0.top.leading.equalTo(infoLayoutGuide)
}
introLabel.snp.makeConstraints {
// 소개 레이아웃 구성 (가능하면 infoLayoutGuide 사용해보기)
$0.top.equalTo(nameLabel.snp.bottom).offset(10)
$0.leading.trailing.equalTo(infoLayoutGuide)
}
let buttonStackView = UIStackView().then {
$0.axis = .horizontal
$0.spacing = 10
$0.alignment = .fill
$0.distribution = .fill
}
buttonStackView.addArrangedSubview(followButton)
buttonStackView.addArrangedSubview(addToPlaylistButton)
contentView.addSubview(buttonStackView)
buttonStackView.snp.makeConstraints {
$0.top.equalTo(introLabel.snp.bottom).offset(20)
$0.leading.trailing.bottom.equalTo(infoLayoutGuide)
}
addToPlaylistButton
.setContentHuggingPriority(.required, for: .horizontal)
}
원래 모르는 언어를 배울 땐 코드를 뜯어보며 배우라 하지 않았던가.
코드 분석을 하고 더 효율적인 코드를 생각하면서 학습하는 걸 좋아하는 편이라
이것도.. 해보려 함 솔직히 할 거 없는 거 같긴 한데 더 빠른 적응을 위해ㅐㅑㅐㅐㅐㅐㅐ
contentView.snp.makeConstraints {
$0.top.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(20)
}
profileImageView.snp.makeConstraints {
$0.top.leading.trailing.equalToSuperview()
$0.height.equalTo(profileImageView.snp.width).multipliedBy(0.75)
}
nameLabel.snp.makeConstraints {
$0.top.leading.equalTo(infoLayoutGuide)
}
introLabel.snp.makeConstraints {
$0.top.equalTo(nameLabel.snp.bottom).offset(10)
$0.leading.trailing.equalTo(infoLayoutGuide)
}
let buttonStackView = UIStackView().then {
$0.axis = .horizontal
$0.spacing = 10
$0.alignment = .fill
$0.distribution = .fill
}
[followButton, addToPlaylistButton].forEach {
buttonStackView.addArrangedSubview($0)
}
contentView.addSubview(buttonStackView)
buttonStackView.snp.makeConstraints {
$0.top.equalTo(introLabel.snp.bottom).offset(20)
$0.leading.trailing.bottom.equalTo(infoLayoutGuide)
}
addToPlaylistButton.setContentHuggingPriority(.required, for: .horizontal)
뷰 생성은 then 블록으로 통일했고 (초기화랑 설정이 좀 더 깔끔하지 않을까 함)
배열로 addArrangedSubview 반복 제거함
한 줄에 제약 조건 묶기