ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Ch14. Animations
    Ray Wenderlich/SwiftUI 2021. 2. 14. 18:23

    SwiftUI의 애니메이션은 UIKit보다 훨씬 간단하다.

     

    Animating state changes

    직역해보면 <State변화를 애니메이션 한다>

    물음표 짓게 만들지만 코드를 보면 이해가 된다.

    Adding animation

    Image(systemName: "chevron.up.square")
      .rotationEffect(.degrees(showDetails ? 0 : 180))
      .animation(.default)
    

    1, 2번 라인은 showDetails값에 따라 rotation을 업데이트한다. 즉 3번 라인이 없어도 무방하다.

    .animation(.default) 한 줄로 이미지가 회전하는 애니메이션이 생겼다.

     

    0과 180을 오가는 애니메이션은 정방향 기준으로 시계방향으로 회전할 것이다.

    하지만 180대신 -180을 넣으면 반시계방향으로 회전한다.

     

    Animation types

    Default animation

    .animation(.default)
    

    가장 기본적인 Linear한 애니메이션

    Eased animations

    .animation(.easeOut)
    .animation(.easeIn)
    .animation(.easeInOut)
    .animation(.easeOut(duration: 2)) // duration설정 당연히 가능
    .timingCurve(_:_:_:_) // 베지어 곡선을 사용한 커스텀 커브 사용 가능
    

    Spring animations

    Spring 애니메이션에는 4가지 요소가 있다.

    1. Mass: 스프링에 매달린 추의 무게라고 생각해보자. 무거울수록 더 큰 힘이 작동해서 스프링을 많이 늘릴 것이다.
    2. Spring Resistance: 스프링이 얼마나 쫀쫀한가? 값이 클수록 덜 늘어난다.
    3. Damping: 스프링을 제어하는 외부힘의 요소. 외부 힘이 강할수록 스프링의 튕김이 빨리 끝날 것이다.
    4. Initial Velocity: 스프링에 물체를 매달고 그 물체를 던지는 힘이라고 생각하자.

    Creating spring animations

    animation(.interpolatingSpring(mass: 1, stiffness: 100, damping: 10, initialVelocity: 0))
    

    좀 더 쉽게 사용가능한 스프링도 제공한다.

    .animation(.spring(response: 0.55, dampingFraction: 0.45,
                       blendDuration: 0))
    
    • dampingFraction: 얼마나 빨리 스프링을 멈출 것인지? 0을 입력하면 멈추지 않는다.
    • response: dampingFraction이 0일 때 1번 스프링하는데 걸리는 시간
    • blendDuration: control for blending the length of the transition between different animations

    Removing and combining animations

    Button(action: {
     self.showDetails.toggle()
    }) {
      HStack {
        Text(showDetails ? "Hide Details" : "Show Details")
        Spacer()
        Image(systemName: "chevron.up.square")
          .scaleEffect(showDetails ? 2 : 1)
    // 1  .animation(nil)
    // 2  .animation(.spring(response: 0.55, dampingFraction: 0.45, blendDuration: 0))
          .rotationEffect(.degrees(showDetails ? 0 : 180))
          .animation(.easeInOut)
      }
    }
    

    scaleEffect와 rotationEffect 2개의 state변화가 있다. animation은 하나만 전달되었다.

    실행하면 2개의 effect가 동시에 애니메이션 된다.

    1. scale은 애니메이션 하기 싫다면 1번 주석을 해제하면 된다.
    2. scale과 rotation에 다른 애니메이션을 사용하고 싶다면 2번 주석을 해제하면 된다.

    Animating from state changes

    위에서는 state변화가 생긴 View에 애니메이션을 추가했다. 하지만 state변화를 발생시키는 곳에서 애니메이션을 추가할 수 있다.

    Button(action: {
      withAnimation(.default) {
     self.showDetails.toggle()
      }
    }) {
      HStack {
        Text(showDetails ? "Hide Details" : "Show Details")
        Spacer()
        Image(systemName: "chevron.up.square")
          .scaleEffect(showDetails ? 2 : 1)
          .rotationEffect(.degrees(showDetails ? 0 : 180))
      }
    }
    FlightDetails(flight: flight)
      .offset(x: showDetails ? 0 : -UIScreen.main.bounds.width)
    

    withAnimation함수를 사용하여 상태변화가 발생하는 곳에 애니메이션을 추가했다.

    실행하면 showDetails에 관련된 모든 뷰가 애니메이션을 하며 변경된다.

    여기서도 마찬가지로 scaleEffect만 스프링을 적용하고싶을 경우, scaleEffect에만 스프링 애니메이션을 추가하면 된다.

     

    Adjusting animations

    Delay

    FlightDetails(flight: flight)
      .offset(x: showDetails ? 0 : -UIScreen.main.bounds.width)
      .animation(Animation.spring().delay(1))
    

    Speed

    .animation(Animation.spring().speed(2))
    

    Repeating animations

    .animation(Animation.spring().repeatCount(2, autoreverses: false))
    

     

    Animating view transitions

    View를 보여주거나 숨길 때 사용한다. 트랜지션도 애니메이션이다. 따라서, 트랜지션에 영향을 주는 State변화를 withAnimation으로 감싸주어야 한다.

    Button(action: {
      withAnimation {
        self.showDetails.toggle()
      }
    }) {
    
    if showDetails {
      FlightDetails(flight: flight)
        .transition(.slide)
    }
    

    애니메이션과 트랜지션의 차이점 중 하나는 애니메이션으로 뷰를 숨길 때는, 보이지 않아도 뷰가 존재한다는 것이다. 하지만 트랜지션을 사용하면 뷰를 보여줄 때 생성하기 때문에 리소스 관리에 유리하다.

     

    View transition types

    위 코드에서는 slide라는 타입을 사용했다. 왼쪽에서 뷰가 나타나고 오른쪽으로 사라지는 애니메이션이다.

    다른 타입은 아래 코드를 참고하자.

    if showDetails {
      FlightDetails(flight: flight)
    //    .transition(.slide)
    //    .transition(.opacity)
    //    .transition(.move(edge: .bottom))
    //    .transition(.scale(scale: 0.1, anchor: .topLeading))
        .transition(.offset(x: 100, y: 100))
    }
    

    Extracting transitions from the view

    커스텀한 트랜지션을 사용할 때, 뷰에 길게 나열하는 것보다는 커스텀 트랜지션을 선언하는게 좋다.

    extension AnyTransition {
      static var flightDetailsTransition: AnyTransition {
    		// implement custom transitino here
    		AnyTransition.slide
      }
    }
    
    if showDetails {
      FlightDetails(flight: flight)
        .transition(.flightDetailsTransition)
    }
    

    Async transitions

    뷰를 Add할 때, Hide할 때 다른 트랜지션을 사용할 수 있다. 동시에 여러 트랜지션을 사용하는 것도 가능하다.

    extension AnyTransition {
      static var flightDetailsTransition: AnyTransition {
        let insertion = AnyTransition.move(edge: .trailing)
    														     .combined(with: .opacity)
        let removal = AnyTransition.scale(scale: 0.0)
    													     .combined(with: .opacity)
        return .asymmetric(insertion: insertion, removal: removal)
      }
    }
    

     

    'Ray Wenderlich > SwiftUI' 카테고리의 다른 글

    Ch13. Drawing & Custom Graphics  (0) 2021.02.14
    Ch12. Conditional Views  (0) 2021.02.14
    Ch11. Lists & Navigation  (0) 2021.02.07
    Ch9. State & Data Flow  (0) 2021.02.07
    Ch8. Introducint Stacks & Containers  (0) 2021.02.07
Designed by Tistory.