@NameSpace

2025. 10. 25. 16:10·iOS/SwiftUI
반응형

🏁 학습할 내용

  • coordinateSpace
  • @NameSpace
  • 활용

🧭 CoordinateSpace

 

 

🤔 어디서 봤을까?

 

GeometryReader proxy 쪽에서 frame정보를 얻을 때, 어떤 Coordinate로부터 가져올 지

결정하게 되는데, 거기서 처음 접했던 것 같다.

 

🧱 구조

CoordinateSpace

public enum CoordinateSpace {

    // 뷰 계층구조의 최상단을 기준으로하는 global 좌표계   
    case global

    // 현재 뷰를 기준으로한 local 좌표계
    case local

    // Hashable한 값으로 구분된 뷰의 좌표계
    case named(AnyHashable)
}

 

CoordinateSpaceProtocol

  • 특정 좌표계를 갖고 있어야함.
public protocol CoordinateSpaceProtocol {

    /// The resolved coordinate space.
    var coordinateSpace: CoordinateSpace { get }
}

 

NamedCoordinateSpace

  • iOS17부터 사용가능한 객체로
  • CoordinateSpaceProtocl과 Equatable을 채택하고 있음
  • 같음을 이용할 수 있는 형태
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
public struct NamedCoordinateSpace : CoordinateSpaceProtocol, Equatable {

    /// The resolved coordinate space.
    public var coordinateSpace: CoordinateSpace { get }
    public static func == (a: NamedCoordinateSpace, b: NamedCoordinateSpace) -> Bool
}

 

마찬가지로 iOS17부터는 CoordinateSpace를 바로 쓰기보다는,
CoordinateSpaceProtocol을 채택하고 있는 구조체들을 씀

  • GlobalCoordinateSpace,
  • LocalCoordinateSpace,
  • NamedCoordinateSpace

 


🚀 @NameSpace

 

눈치챘겠지만, 이 녀석은 NamedCoordinateSpace와 관려이 있을 것 같다..

쓸 수는 있지만, 실제로는 matchedGeometryEffect 같이 매개변수에 in: NameSpace.ID가 있는 녀석들과 매우 밀접하다.

 

🧱 구조

@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
@frozen @propertyWrapper public struct Namespace : DynamicProperty, Sendable {
    @inlinable public init()

    public var wrappedValue: Namespace.ID { get }

    @frozen public struct ID : Hashable {

        public func hash(into hasher: inout Hasher)
        public static func == (a: Namespace.ID, b: Namespace.ID) -> Bool
        public var hashValue: Int { get }
    }
}

 

  • 영구적인 Identity로 정의된 객체에 접근할 수 있는 namespace
  • propertyWrapper기 때문에, wrappedValue를 자세히보면 ID, 즉 Hashable한 타입
  • DynamicProperty를 채택하고 있는 것을 보면, View Update 사이클과도 관련이 있음

♻️ 활용

iOS17부터, 기본적으로 유용하게 사용되는 NamedCoordinateSpace 제공해주는데 바로 scrollView다.

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension CoordinateSpaceProtocol where Self == NamedCoordinateSpace {
    public static func scrollView(axis: Axis) -> Self
    public static var scrollView: NamedCoordinateSpace { get }
}

 

 

아래와 같이, 원하는 axis을 명시해주면, 스크롤 axis가 일치하는 가장 가까운 조상의
ScrollView의 좌표공간을 얻을 수 있다.

GeometryReader { proxy in
  let frame = proxy.frame(in: .scrollView(axis: .vertical)) // 기준이 되는 건?
  Text("Item \(index)\nY: \(Int(frame.minY))")
        .frame(width: 120, height: 120)
        .background(Color.blue.opacity(0.3))
        .cornerRadius(10)
}

 

 

 

그런데 여기서 중요한점은 iOS17부터 가능하다는거다... 

이 기능을 똑같이 만들려면 @NameSpace + CoordinateSpace의 .named를 이용하면 만들 수 있다.

struct NestedScrollViewExample: View {
  @Namespace var namespace

    var body: some View {
        ScrollView(.vertical) {  // 바깥 스크롤뷰
            VStack(spacing: 40) {
                Text("Outer ScrollView")
                    .font(.headline)

                ScrollView(.horizontal) {  // 안쪽 스크롤뷰
                    HStack {
                        ForEach(0..<5) { index in
                            GeometryReader { proxy in
                              let frame = proxy.frame(in: .named(namespace)) //namespace로 부터 좌표공간 얻기 
                              Text("Item \(index)\nY: \(Int(frame.minY))")
                                    .frame(width: 120, height: 120)
                                    .background(Color.blue.opacity(0.3))
                                    .cornerRadius(10)
                            }
                            .frame(width: 120, height: 120)
                        }
                    }
                    .padding()
                }
                .background(Color.yellow.opacity(0.2))
            }
        }
        .coordinateSpace(name: namespace) // ✅ 얻고싶은 coordinateSpace 표시
    }
}

📘 요약 비교

항목 coordinateSpace @Namespace
역할 좌표 계산 기준 정의 뷰 간 애니메이션 매칭
관련 함수 GeometryReader, .frame(in:) matchedGeometryEffect
주요 용도 위치 추적, 스크롤, 정렬 자연스러운 뷰 전환 애니메이션
범위 좌표계 이름 단위 애니메이션 그룹 단위

출처

반응형

'iOS > SwiftUI' 카테고리의 다른 글

[WWDC2023] Explore SwiftUI animation  (0) 2025.10.29
커스텀 DynamicScrollTabVIew 만들기  (0) 2025.10.26
PreferenceKey  (0) 2025.10.24
.id  (0) 2025.10.23
containerRelativeFrame  (0) 2025.10.23
'iOS/SwiftUI' 카테고리의 다른 글
  • [WWDC2023] Explore SwiftUI animation
  • 커스텀 DynamicScrollTabVIew 만들기
  • PreferenceKey
  • .id
Hamp
Hamp
남들에게 보여주기 부끄러운 잡다한 글을 적어 나가는 자칭 기술 블로그입니다.
  • Hamp
    Hamp의 분리수거함
    Hamp
  • 전체
    오늘
    어제
    • 분류 전체보기 (325) N
      • CS (30)
        • 객체지향 (2)
        • Network (7)
        • OS (6)
        • 자료구조 (1)
        • LiveStreaming (3)
        • 이미지 (1)
        • 잡다한 질문 정리 (0)
        • Hardware (2)
        • 이론 (6)
        • 컴퓨터 그래픽스 (0)
      • Firebase (3)
      • Programing Langauge (41)
        • swift (34)
        • python (6)
        • Kotlin (1)
      • iOS (133) N
        • UIKit (37)
        • Combine (1)
        • SwiftUI (33) N
        • Framework (7)
        • Swift Concurrency (22)
        • Tuist (6)
        • Setting (11)
        • Modularization (1)
        • Instruments (6)
      • PS (59)
        • 프로그래머스 (24)
        • 백준 (13)
        • LeetCode (19)
        • 알고리즘 (3)
      • Git (18)
        • 명령어 (4)
        • 이론 (2)
        • hooks (1)
        • config (2)
        • action (7)
      • Shell Script (2)
      • Linux (6)
        • 명령어 (5)
      • Spring (20)
        • 어노테이션 (6)
        • 튜토리얼 (13)
      • CI-CD (4)
      • Android (0)
        • Jetpack Compose (0)
      • AI (9)
        • 이론 (9)
        • MCP (0)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Swift
    AVFoundation
    boostcamp
    dfs
    protocol
    dispatch
    IOS
    Spring
    property
    프로그래머스
    백준
    CS
    SwiftUI
    lifecycle
    dp
    UIKit
    투포인터
    Tuist
    concurrency
    GIT
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.0
Hamp
@NameSpace
상단으로

티스토리툴바