DEV_Larva

SwiftUI Tutorials - Landmarks(5) 본문

SwiftUI & UIKit/Tutorials

SwiftUI Tutorials - Landmarks(5)

NelchuPapa 2022. 10. 29. 11:12
반응형

이번 시간에는 뷰에 애니메이션 효과를 추가하여 이 앱을 사용하는 동안 사용자가 걷는 행동을 추적하기 위해 그래프를 포함해서 애니메이션을 추가해볼 것이다. 

 


1.  Add Hiking Data to the App

먼저 애니메이션을 추가하기전에 애니메이션을 적용할 대상이 필요하다. 그래서 이번 섹션에서는 먼저 하이킹 데이터를 가져와 모델링을 해주고 이후 해당 데이터를 정적으로 표시하기 위해서 미리 뷰를 추가해보자. 다운로드 파일을 현재 작업 중인 폴더로 드래그해서 작업을 준비하자.


 

준비는 끝났다. 이제 새로운 파일 Hike을 만들어준다. 여기서 Hike 는 앞서 만들었던 Landmark의 구조와 비슷하게 Coadble을 가지게 되고 해당 데이터 파일의 키와 일치하는 속성을 가지게 된다. 

 

import Foundation

struct Hike: Codable, Hashable, Identifiable {
    var id: Int
    var name: String
    var distance: Double
    var difficulty: Int
    var observations: [Observation]

    static var formatter = LengthFormatter()

    var distanceText: String {
        Hike.formatter
            .string(fromValue: distance, unit: .kilometer)
    }

    struct Observation: Codable, Hashable {
        var distanceFromStart: Double

        var elevation: Range<Double>
        var pace: Range<Double>
        var heartRate: Range<Double>
    }
}

 

그리고 ModelData 파일에서 방금 추가한 하이킹 배열을 추가한다. 

var hikes: [Hike] = load("hikeData.json")

여기서 이전에 landmark와 다르게 @Published 속성으로 hike를 추가하지 않은 이유는 하이킹에 대한 데이터는 처음 읽어 온 이후 더 이상 이후에 수정을 하지 않기 때문에 따로 @Published 속성이 필요하지 않다.

 


이후 다운로드한 다른 폴더였던 Hikes를 프로젝트에 드래그하여 파일 내부에서 HikeView의 프리뷰를 실행해보면 그래프를 표시하고 숨기는 작업을 미리 실험해볼 수 있다. 하지만 아직까지는 애니메이션 작업을 추가하지는 않았기 때문에 크게 다른 효과는 없다.

 

 


2. Add Animations to Individual Views

이번 섹션에서는 animation() 수정자를 이용하여 뷰에서 애니메이션 작업이 가능한 속성에 대해서는 모두 애니메이션 작업을 할 수 있게 된다. 예를 들어 뷰의 색상, 불투명도, 회전, 크기, 등 다양하게 적용하여 뷰를 더 생동감 있게 표현할 수 있다. 

 

 


 

먼저 사용하기 전에 여러 가지 애니메이션 효과들을 실험해보고, 가장 자연스러운 것을 찾아보자.

 

  1. HikeView에서 버튼을 클릭할 때 회전을 하게 되는데 이에 대한 애니메이션 표현
  2. 그래프가 표시될 때 버튼을 더 커지게 표현 
             Button {
                    showDetail.toggle()
                } label: {
                    Label("Graph", systemImage: "chevron.right.circle")
                        .labelStyle(.iconOnly)
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0)) 
                        .scaleEffect(showDetail ? 1.5 : 1) //2번 작업에 해당
                        .padding()
                        .animation(.easeInOut, value: showDetail) //1번 작업에 해당
                }
            }

 

 

여기서 변경 사항으로. animation수정자 내부에 있는 속성 easeInOut의 경우 수정이 가능한데, 이때 속성의 종류는 다양하여 직접 공식 문서를 참고하여 여러 가지를 자신의 앱에 바꿔가며 적용해보는 것도 새로운 재미가 있을 것 같다. 

 

https://developer.apple.com/documentation/swiftui/animation

 

Apple Developer Documentation

 

developer.apple.com

 


3. Animate the Effects of State Changes

이제 개별 View에 애니메이션을 적용하는 방법에 대해서는 배웠으니 상태 값을 변경하는 위치에 애니메이션을 추가해보자.

 

 


이전에 작업하던 HikeView에서 withAnimation 함수에 대한 호출로 showDetail.toggle을 래핑 해주자. 이전에 animation 수정자에 전달한 것과 같이 동일한 종류의 애니메이션을 withAnimation 함수에 전달할 수 있다. 

 

        Button {
                    withAnimation {    // withAnimation 함수 추가.
                        showDetail.toggle()
                    }
                } label: {
                    Label("Graph", systemImage: "chevron.right.circle")
                        .labelStyle(.iconOnly)
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                }
            }

 

 


4. Customize View Transitions

여기서는 transition수정자를 이용해볼 건데 기본적으로 뷰는 페이드 인 또는 페이드 아웃을 통해 전환된다. 그래서 수정자를 통해 이 전환을 사용자가 정의할 수 있다.

 


 

작업하는 파일은 동일하다. 먼저 transition수정자를 추가해주자. 이렇게 되면 이제 그래프가 시야에 들어오고 사라지면서 나타났다가? 사라졌다가? 한다. 가장 먼저 추가한 수정자에 속성 값으로. slide를 추가해주면 된다. 

 

if showDetail {
        HikeDetail(hike: hike)
        .transition(.slide)
}

 

방금 추가한 transition을 AnyTransition의 정적 속성으로 추출하고 뷰의 전환 수정자에서 새 속성에 접근한다. 이 작업은 커스텀 transition을 확장할 때 코드를 보다 깨끗하게 유지하기 위해서다. 

 

extension AnyTransition {
    static var moveAndFade: AnyTransition {
        .asymmetric(
            insertion: .move(edge: .trailing).combined(with: .opacity),
            removal: .scale.combined(with: .opacity)
        )
    }
}



//
//
//

if showDetail {
         HikeDetail(hike: hike)
         .transition(.moveAndFade)
}

 

그리고 그 내부에는 asymmetric 수정자를 사용해 뷰가 나타나고 사라질 때 서로 다른 transition을 제공한다. 

여기서 asymmetric 수정자는 무엇일까? asymmetric의 의미는 비대칭으로, 삽입과 제거에 다른 transition을 사용하는 복합 전환을 제공한다고 한다. 

 


5. Compose Animations for Complex Effects

 

막대 아래에 있는 버튼을 클릭하면 그래프가 세 가지의 다른 데이터 세트 사이에서 전환된다. 이 섹션에서는 앞서 구성한 애니메이션을 사용해서 그래프를 구성하는 캡슐에 동적이면서도 다이내믹한 transition을 제공해보자.

 


HikeGraph 파일에서 새로운 리플 애니메이션을 정의하고 생성된 각 그래프 캡슐에 적용한다. 그리고 그 내부에서 애니메이션을 스프링으로 설정하고 댐핑 비율을 낮게 하여 막대가 뛰게 만들어보자. 그리고 애니메이션 속도를 약간 높여 각 막대가 이동하는 시간을 줄여준다. 

그리고 delay값을 추가해주면?? 

 

extension Animation {
    static func ripple(index: Int) -> Animation {
        Animation.spring(dampingFraction: 0.5)
            .speed(2)
            .delay(0.03 * Double(index))
    }
}

 

 

 

 


이번 섹션에서는 다양한 애니메이션 수정자와 transition 수정자를 이용해 기존의 딱딱한 뷰에 생동감을 불어넣어주어 표현 기법의 한계를 한번 더 부수는 작업을 해보았다. 수정자와 그 내부 속성의 값은 공식문서를 보았듯 종류가 매우 많기 때문에 따로 한번 학습해보는 시간을 가져 봐야 할 것 같다. 

반응형

'SwiftUI & UIKit > Tutorials' 카테고리의 다른 글

SwiftUI Tutorials - Landmarks(7)  (0) 2022.11.08
SwiftUI Tutorials - Landmarks(6)  (0) 2022.11.01
SwiftUI Tutorials - Landmarks(4)  (0) 2022.10.19
SwiftUI Tutorials - Landmarks(3)  (0) 2022.10.15
SwiftUI Tutorials - Landmarks(2)  (0) 2022.10.08