Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
SwiftUI/SwiftUI(Intermediate)

11. DragGestrue() 드래그 제스쳐

by Toughie 2023. 5. 25.

⭐️DragGestrue() 드래그 제스쳐⭐️

손가락으로 드래그했을 때 다양한 효과를 주는 법을 알아보자.

상하좌우 이동도 가능하고, 이에 맞춰 크기 변화도 줄 수 있고 여러 애니메이션 효과를 가미할 수 있다.

 

1. 좌우 이동 스케일 효과

//  Created by Toughie on 2023/05/25.
//

import SwiftUI

struct DragGesturePrac: View {
    //초기 오프셋 0에서 시작
    @State var offset: CGSize = .zero
    
    var body: some View {
        ZStack {
            
            VStack {
                Text("\(offset.width)")
                Spacer()
            }
            RoundedRectangle(cornerRadius: 20)
                .fill(Color.blue.opacity(0.3))
                .frame(width: 300, height: 500)
                
                .offset(offset)
                //좌우 드래그 시 스케일을 줄이는 효과
                .scaleEffect(getScaleAmount())
                //좌우 드래그 시 각도를 기울이는 효과
                .rotationEffect(Angle(degrees: getRotationAmount()))
                
                .gesture (
                    DragGesture()
                        .onChanged{ value in
                            withAnimation(.default) {
                            //드래그 한 만큼 오프셋 변경
                                offset = value.translation
                            }
                            
                        }
                        .onEnded { value in
                        // 드래그가 끝났을 때 제자리로 돌아가도록
                            withAnimation(.spring()) {
                                offset = .zero
                            }
                        }
                )
        }
    }
    //드래그 했을 때 얼마나 스케일을 변경할 것인가?
    func getScaleAmount() -> CGFloat {
    //화면 절반 이상 드래그 하는 경우는 드물기에, 절반까지를 최대로 설정
        let max = UIScreen.main.bounds.width / 2
        //좌우 상관없이 스케일을 바꾸기에 절대값 사용
        let currentAmount = abs(offset.width)
        //최대 범위 대비 얼마나 이동했는가?
        let percentage = currentAmount / max
        //최대 75%까지만 작아지도록
        return 1.0 - min(percentage, 0.5) * 0.5
    }
    
    //드래그 했을 때 각도를 얼마나 기울일 것인가?
    func getRotationAmount() -> Double {
    
        let max = UIScreen.main.bounds.width / 2
        let currentAmount = offset.width
        let percentage = currentAmount / max
        let percentageAsDouble = Double(percentage)
        
        let maxAngle: Double = 10
        //최대 10도까지
        return percentageAsDouble * maxAngle
    }
}

 

2. 위로 끌어올리는 화면 구현

//  Created by Toughie on 2023/05/25.
//

import SwiftUI

struct DragGesturePrac2: View {
    
    @State var startingOffsetY: CGFloat = UIScreen.main.bounds.height * 0.85
    @State var currentDragOffsetY: CGFloat = 0
    @State var endingOffsetY: CGFloat = 0
    
    var body: some View {
        ZStack {
        //배경색
            Color.blue.ignoresSafeArea().opacity(0.4)
            //로그인 뷰 예시
            SignUpView()
            
                .offset(y: startingOffsetY)
                
                .offset(y: currentDragOffsetY)
                
                .offset(y: endingOffsetY)
                
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            withAnimation(.spring()) {
                                currentDragOffsetY = value.translation.height
                            }

                        }
                        .onEnded { value in
                            withAnimation(.spring()) {
                            //offset이 -150 미만이면 원래 위치로 돌아가도록
                                if currentDragOffsetY < -150 {
                                    endingOffsetY = -startingOffsetY
							// 위에서 끌어내릴 때, endingOffsetY가 0이 아닌지 확인하고(맨 위에 있을 때 -startingOffsetY임)
							// 일정 범위 이상(150) 끌어내렸을 때 원래 위치로 돌아가도록 endingOffsetY를 0으로
                                } else if endingOffsetY != 0 && currentDragOffsetY > 150 {
                                    endingOffsetY = 0

                                }
                                //다음 드래그가 이전 드래그에 영향을 받지 않도록 초기화
                                    currentDragOffsetY = 0
                            }
                        }
                    )
            Text("\(currentDragOffsetY)")
        }
        .ignoresSafeArea(edges: .bottom)
    }
}

if currentDragOffsetY < -150 조건이 참이면, endingOffsetY를 -startingOffsetY로 설정하여 뷰를 원래 위치로 이동시킨다.
반대로, if currentDragOffsetY > 150 조건이 참이면, endingOffsetY를 0으로 설정하여 뷰를 초기 위치로 되돌린다.

 

currentDragOffsetY = 0 코드는 이후에 currentDragOffsetY 값을 초기화하는 역할을 한다.

-> 다음 드래그 제스처가 시작될 이전 드래그 제스처의 영향을 받지 않고 새로운 드래그를 시작할 있다.