SwiftUI로 뷰를 그리다보면 frame 때문에 애를 먹는 경험을 종종 하게 된다.
최근 회사 프로젝트의 메인 홈 화면 개편 작업 중에도 동일한 상황을 겪었고,
이를 계기로 frame 모디파이어를 정리하게 되었다.
고정 frame
frame은 뷰의 사이즈와 위치를 결정하는 데 사용된다.
즉, 뷰의 너비, 높이, 최소/최대 크기, 정렬 방식 등을 정의할 수 있다.
func frame(
width: CGFloat? = nil,
height: CGFloat? = nil,
alignment: Alignment = .center
) -> some View
- width, height를 nil로 지정하면 콘텐츠 크기에 따라 자동으로 설정된다.
- alignment의 기본값은 .center이며, .top, .bottom, .leading, .trailing 등 다양한 옵션이 있다.
- 공식 문서에서는 frame을 “지정한 사이즈의 보이지 않는 프레임 영역에 뷰를 배치하는 역할”이라고 설명한다.
frame 예시
우선 기본적으로 frame의 코드가 어떻게 작동 되는 지 확인하고 싶어서 아래 예시 코드를 작성해보았다.
Text("Hello, world!")
.background(.yellow)
.frame(width: 100, height: 100)
.background(.red)
- yellow로 지정된 부분은 text 영역이고, red로 지정한 부분은 frame의 영역이다.
- frame으로 지정한 부분만큼인 width 100, height 100으로 사이즈가 정해져있는 걸 확인할 수 있다.
- alignment를 따로 지정해주지 않았기 때문에 가운데 정렬이 되어 있음을 확인할 수 있다.
그러면 여기서 궁금해질 수가 있다.
width와 heigh은 optional이고, 기본 사이즈로 지정이 된다는데 그게 어떤 사이즈를 의미하는가에 대해서 말이다.
Text("Hello, world!")
.background(.yellow)
// .frame(width: 100, height: 100)
.background(.red)
- 지정해둔 width와 height을 주석처리 했더니 frame 영역으로 설정했던 red 영역이 보이지 않았다.
- 텍스트 영역만이 보이는데, SwiftUI에서 지정한 기본 사이즈는 위 이미지처럼 컨텐츠의 사이즈를 의미한다.

frame 중복 사용
이미 frame으로 한번 뷰의 위치를 잡아주었는데, 프레임을 또 사용해서 뷰 위치를 변경할 수 있을까 궁금해졌다.
예시 코드는 아래와 같다.
Text("Hello, world!")
.background(.yellow)
.frame(width: 100, height: 100)
.background(.red)
.frame(width: 150, height: 150)
.background(.blue)
- 가로세로를 100씩 잡았던 레드영역 바깥으로 150씩 잡은 블루영역이 생기면서 컨텐츠 뷰의 위치라던가 사이즈가 변경된 것을 확인할 수 있다.
- 따라서, 프레임을 연속적으로 추가해도 추가한 값만큼 뷰의 위치와 사이즈를 변경시킬 수 있다.
가변 frame
이 스터디를 진행하게 된 가장 큰 이유이자 목적인 가변 frame이다.
고정 frame을 사용하면 기기 대응이 되지 않을 것 같아서 가변 frame을 자주 사용하다 못해 남발을 한 경험이 있는데, 그동안 어떤 상황에서 사용해야하고 어떻게 뷰에 적용되는지 정확히 이해하고 쓰지 못한 것 같았다. 그래서 미루고 미루던 가변 frame을 제대로 파보았다.
maxWidth / maxHeight
- maxWidth: 최종 프레임의 최대 너비
- maxHeight: 최종 프레임의 최대 높이
- 즉, 정해진 사이즈가 해당 값보다 커지는 것을 방지한다.
예시코드로 프레임을 지정하지 않고 애국가 1절과 2절 가사를 적어보았다.
Text("1. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세 무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세 2. 남산 위에 저 소나무 철갑을 두른 듯 바람 서리 불변함은 우리 기상일세 무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세")
.background(.yellow)
아래 이미지처럼 가사의 길이만큼 사이즈가 정해지는 것을 확인할 수 있다.
여기에 최대 사이즈를 100씩으로 지정해보았다.
Text("1. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세 무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세 2. 남산 위에 저 소나무 철갑을 두른 듯 바람 서리 불변함은 우리 기상일세 무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세")
.background(.yellow)
.frame(maxWidth: 100, maxHeight: 100)
.background(.red)
- maxFrame을 추가해주기 전과 달리 최대 높이와 너비값을 넘지 않게 뷰의 사이즈가 조절된 것을 확인할 수 있다.
- maxFrame은 컨텐츠 사이즈와 상관없이 본인이 지정한 값을 넘기지 않게 사이즈를 지정해주는 것을 알 수 있다.
minWidth/ minHeight
- minWidth: 최종 프레임의 최소 너비
- minHeight: 최종 프레임의 최소 높이
- 반대로, 정해진 사이즈가 해당 값보다 작아지는 것을 방지한다.
maxWidth와 maxHeight의 자리에 minWidth와 minHeight로 대체한 코드를 작성해보았다.
Text("1. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세 무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세 2. 남산 위에 저 소나무 철갑을 두른 듯 바람 서리 불변함은 우리 기상일세 무궁화 삼천리 화려 강산 대한 사람 대한으로 길이 보전하세")
.background(.yellow)
.frame(minWidth: 100, minHeight: 100)
.background(.red)
맨 처음 프레임을 지정해주기 전 콘텐츠 사이즈가 나온다.

그 이유를 확인하기 위해 애국가 내용을 줄여보았다.
Text("1. 동해물")
.background(.yellow)
.frame(minWidth: 100, minHeight: 100)
.background(.red)
- 컨텐츠 사이즈(노란색 영역)이 100보다 작을 때, 뷰의 프레임 사이즈(레드 영역)이 100으로 잡혀있는 것을 확인할 수 있다.
- 즉, 뷰가 100보다 작아도 뷰 사이즈의 최소값으로 지정한 100보다 작아지지 않게 최소 크기를 보장한 채로 프레임을 잡아준다.
- 뷰의 최소 사이즈를 보장하는 해당 프레임을 사용하면 컨텐츠의 사이즈가 100보다 커지면 지정한 최소값보다 커지는 것을 알 수 있다.
추가 학습
infinity
- A size proposal that contains infinity in both dimensions.
- Both dimensions contain infinity in this size proposal. Subviews of a custom layout return their maximum size when you propose this value using the dimensions(in:) method. A custom layout should also return its maximum size from the sizeThatFits(proposal:subviews:cache:) method for this value.
screen 가로/세로 사이즈를 가져오려 할 때 frame에 infinity를 종종 사용할 때가 있는데, 조금 더 정확히 알고 싶어서 공식문서를 확인해보았다. infinity는 type property로 최대 사이즈를 반환하기 때문에, 특히 자신이 하위 뷰일 땐 부모 뷰의 사이즈를 최대값으로 채운다.
대신, infinity로 width를 잡으면 보라색 UI layout 경고가 뜰 때가 있어서 회사에서 SwiftUI로 작업 할 때 위와 같은 함수를 extension으로 만들어서 .infinity값을 UIKit에서 사용하던 방식으로 우회하여 적용하고 있다.
extension View {
/// 화면 너비 가져옴
func getScreenWidth() -> CGFloat {
return UIScreen.main.bounds.width
}
}
요약
- frame 모디파이어를 사용하여 뷰의 너비, 높이, 최대/최소 크기, 정렬 방식 및 위치를 조절할 수 있다.
- frame 모디파이어를 중복 사용하여 뷰의 위치와 사이즈를 연속적으로 변경할 수 있다.
- maxWidth와 maxHeight는 최대 사이즈를 제한하며, minWidth와 minHeight는 최소 사이즈를 보장한다.
- infinity는 최대 사이즈를 나타내며, 화면 너비를 가져올 때 유용하게 활용할 수 있다.
- frame 모디파이어를 활용할 때 .infinity 값을 사용할 때 보라색 UI layout 경고가 발생할 수 있으므로 주의가 필요.
References
- https://developer.apple.com/documentation/swiftui/view/frame(width:height:alignment:)
- https://developer.apple.com/documentation/swiftui/view/frame(minwidth:idealwidth:maxwidth:minheight:idealheight:maxheight:alignment:)
- https://developer.apple.com/documentation/swiftui/proposedviewsize/infinity
frame(width:height:alignment:) | Apple Developer Documentation
Positions this view within an invisible frame with the specified size.
developer.apple.com
'Dev > SwiftUI' 카테고리의 다른 글
[SwiftUI] scrollTargetLayout과 ScrollTargetBehavior (0) | 2024.08.16 |
---|---|
[SwiftUI] Property Wrapper 총정리 (0) | 2024.07.26 |
[SwiftUI] @State (0) | 2024.05.22 |
[SwiftUI] NavigationView, NavigationStack, navigationTitle (2) | 2024.04.15 |
[SwiftUI] Info.plist (0) | 2023.11.20 |