iOS/SwiftUI

[SwiftUI] @GestureState, @Namespace, @ScaledMetric

_Rey 2022. 4. 19. 10:59

@GestureState

Gesture와 관련된 Wrapper다.

struct SimpleLongPressGestureView: View {
    @GestureState var isDetectingLongPress = false

    var longPress: some Gesture {
        LongPressGesture(minimumDuration: 3)
            .updating(self.$isDetectingLongPress) { currentState, gestureState, transaction in
                gestureState = currentState
            }
    }

    var body: some View {
        Circle()
            .fill(self.isDetectingLongPress ? Color.red : Color.green)
            .frame(width: 100, height: 100, alignment: .center)
            .gesture(longPress)
    }
}

// Example 2
@GestureState var dragAmount = CGSize.zero
Rectangle()
	.fill(.cyan)
	.frame(width: 100, height: 100)
	.offset(self.dragAmount)
	.gesture(
		DragGesture()
			.updating(self.$dragAmount) { value, state, transaction in
				state = value.translation
			}
	)

State가 붙어있는 것처럼 값 변화에 따라서 View가 업데이트된다. Binding은 Gesture 안에서 하게 된다.

 

@Namespace

애니메이션을 하나의 그룹으로 묶는다고 이해하면 편하다. matchedGeometryEffect 메소드와 함께 쓰인다.

// 부모 뷰
@Namespace var namespace
...
자식뷰(namespace: self.namespace)

// 자식 뷰
let namespace: Namespace.ID
...
	.matchedGeometryEffect(id: "{NAME_SPACE_KEY}", in: namespace)

키값으로 애니메이션이 묶이면서 더 자연스러운 애니메이션이 작동한다.

 

@ScaledMetric

사용자 폰트 크기 등 사용자가 설정 시스템 크기를 반영할 수 있다.

struct ScaledMetricView: View {
    @ScaledMetric(relativeTo: .largeTitle) var fontSize: CGFloat = 20
    @ScaledMetric(relativeTo: .largeTitle) var imageSize: CGFloat = 100
    var body: some View {
        VStack{
            Text("cloud.sun.bolt.fill")
                .font(.system(size: self.fontSize, weight: .regular, design: .default)  )
            Image(systemName: "cloud.sun.bolt.fill")
                .resizable()
                .frame(width: self.imageSize, height: self.imageSize)
        }
    }
}