반응형

SwiftUI에서 많이 하는 실수 - offset을 레이아웃 도구로 사용해서 반응형이 깨지는 실수

 

offset modifier는 뷰의 실제 레이아웃 위치는 그대로 두고, 화면에 보이는 위치만 이동시킵니다.
이걸 “레이아웃 수정 도구”로 사용하면, 터치 영역/레이아웃 계산/정렬이 전부 꼬이게 됩니다.


1. 문제 원인

  • UIKit에서 frame.origin.x/y를 바꾸던 습관
  • padding/alignment/frame으로 해결할 수 있는 문제를 offset으로 해결
  • offset이 “시각적인 이동”이라는 개념을 잘 모름

2. 나타나는 증상

  • 버튼은 오른쪽에 보이는데, 실제 터치 영역은 왼쪽에 있음
  • GeometryReader나 alignment 계산 시, 여전히 원래 자리 좌표로 계산됨
  • 다른 View와 겹치거나, 스크롤/애니메이션이 이상하게 동작

3. 잘못된 코드 예시

struct BadgeView: View {
    var body: some View {
        ZStack {
            Image(systemName: "bell.fill")
                .font(.system(size: 40))

            Text("3")
                .padding(4)
                .background(Color.red)
                .clipShape(Circle())
                // ❌ 빨간 뱃지를 위치시키려고 offset 사용
                .offset(x: 15, y: -15)
        }
    }
}

이 경우, 뱃지의 터치/레이아웃 계산은 여전히 중앙 기준입니다.


4. 올바른 코드 예시

4-1. alignment를 사용

struct BadgeView: View {
    var body: some View {
        ZStack(alignment: .topTrailing) {
            Image(systemName: "bell.fill")
                .font(.system(size: 40))

            Text("3")
                .font(.caption2)
                .padding(4)
                .background(Color.red)
                .clipShape(Circle())
                .offset(x: 4, y: -4)   // ✅ 미세 조정 정도는 OK
        }
    }
}
  • 큰 레이아웃은 alignment로 배치하고,
    offset은 정말 미세한 위치 조정(몇 pt 내) 정도에만 사용하는 게 좋습니다.

4-2. HStack/VStack 조합으로 구조적인 레이아웃

HStack(alignment: .top) {
    Image(systemName: "bell.fill")
    Text("3")
        .padding(4)
        .background(Color.red)
        .clipShape(Circle())
}

5. 정리 및 팁

  • offset은 레이아웃을 바꾸지 않고 화면에 보이는 위치만 이동합니다.
  • 터치 영역/정렬/레이아웃 계산까지 함께 변경하려면
    frame, padding, Spacer, alignment, Stack 을 우선적으로 사용하세요.
  • offset이 많아졌다는 건, 레이아웃 구조를 다시 설계해야 한다는 신호일 가능성이 큽니다.
반응형
Posted by 까칠코더
,