• 티스토리 홈
  • 프로필사진
    2료일
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
2료일
  • 프로필사진
    2료일
    • 분류 전체보기 (118)
      • SWIFT개발 (29)
      • 알고리즘 (25)
      • Design (6)
      • ARkit (1)
      • 면접준비 (32)
      • UIkit (2)
      • Vapor-Server with swift (3)
      • 디자인패턴 (5)
      • 반응형프로그래밍 (12)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • 근본으로 돌아가자(2) - animation & iOS 17에서 바뀐것들
        2023년 12월 14일
        • 2료일
        • 작성자
        • 2023.12.14.:59

        WWDC23에서 애플은 SwiftUI를 개발한 핵심 동기가 바로 앱에 애니메이션을 쉽게 추가할 수 있도록 하는 것이라고 스스로 밝힐 정도로, 애니메이션은 SwiftUI의 핵심 요소입니다. 이 글에서는 WWDC23의 세션 "Explore SwiftUI Animation"을 상세히 분석하고, SwiftUI에서 애니메이션이 어떻게 작동하는지 심층적으로 살펴보겠습니다.

        https://developer.apple.com/videos/play/wwdc2023/10156/

        struct AnimationView: View {
          @State private var selected = false
          var body: some View {
            Image("bell.fill")
             .resizable()
             .frame(width:200)
             .scaleEffect(selected ? 2: 1)
             .onTapGesture {
               selected.toogle()
           	}
          }}

        SwiftUI의 기본 뷰 업데이트 흐름

        이런 코드가 있다고 보자. 당연히 view value로 보면 Image를 기준으로 하나씩 쌓여있다. 그렇다면 tap event발생하면?

        update transition이 열린다. 

        1. 트랜잭션(Transaction) 생성: SwiftUI는 업데이트를 관리하기 위한 트랜잭션을 시작합니다.
        2. 상태 값 변경: selected 상태 값이 변경됩니다.
        3. 종속성 변경 감지: 뷰의 종속 항목 중 하나(여기서는 selected)가 변경되었으므로 전체 뷰가 무효화됩니다.
        4. 뷰 재구성: 트랜잭션이 종료될 때 body가 다시 호출되어 새로운 뷰 값이 생성됩니다.
        5. 새 뷰 렌더링: 새로운 뷰 값이 화면에 렌더링됩니다.

        이 과정에서 중요한 점은, 뷰 계층 구조의 바깥에서부터 안쪽으로 차례대로 재계산과 재렌더링이 이루어진다는 것입니다.

        결국 쌓여있는 반대로 하나씩 단계를 거치면서 재랜더링한다. 이것이 기본적인 뷰가 랜더링업데이트 되는 방식이다!!

        애니메이션이 추가될 때의 뷰 업데이트

        scaleEffect와 같은 일부 속성은 SwiftUI에서 "애니메이션이 가능한 속성(Animatable Attributes)"으로 특별하게 취급됩니다. 이러한 속성들은 값이 변경될 때 애니메이션을 적용할 수 있습니다.

        애니메이션이 있는 업데이트 과정

        1. 탭 이벤트가 발생하고 selected 값이 변경됩니다.
        2. withAnimation 블록이 트랜잭션에 애니메이션 정보를 추가합니다.
        3. SwiftUI는 애니메이션이 적용될 속성 그래프를 파악합니다.
        4. 애니메이션이 가능한 속성(scaleEffect 등)을 식별합니다.
        5. 중요한 차이점: SwiftUI는 이전 값과 새 값 사이를 시간에 따라 보간(interpolation)합니다.
        6. 각 애니메이션 프레임마다 이 보간된 값을 사용하여 뷰를 업데이트합니다.
        7. 메인 스레드에서 이 모든 작업이 수행됩니다.

        그러면 scaleEffect가 있을때는 어떻게 이루어지는지 시간에 따라 보자.

        값이 변화하면 transaction에 animation을 보고 body를 업데이트한다. 
        SwiftUI는 애니메이션이 속성 그래프에 포함되는 시점을 파악해 적절한 애니메이션이 가능한 속성을 호출한뒤 다음 프레임 호출. 메인 쓰레드에서 이 작업 수행. 

        Animatable(적용대상을 결정)

        scaleEffect와 같이 Animatable attributes는 애니메이션 되는 데이터를 결정

        VectorArithmetic 프로토콜의 핵심

        Animatable 프로토콜은 VectorArithmetic 프로토콜을 기반으로 합니다. VectorArithmetic은 다음과 같은 핵심 기능을 제공합니다:

        1. 벡터 연산: 동일한 타입의 두 벡터를 더하거나 빼고, 벡터와 스칼라를 곱하거나 나눌 수 있습니다.
        2. 주요 메서드:
          • scaled(by:): 주어진 값을 일정한 비율로 변경합니다. 주로 값을 확대/축소하는 데 사용됩니다.
          • interpolated(towards:amount:): 보간을 통해 두 값 사이의 완만한 변화를 제공합니다. 시작값과 끝값 사이의 중간값을 계산하여 결정합니다.

        주의 할점! 

        1. 커스텀 animatable은 애니메이션의 모든 프레임에 대해 바디를 실행하기에 내장된 Effect보다 애니메이션 하는데 훨씬 더 많은 리소스 든다. 
        2. 커스텀 자제....해라 애플이 말한다. 앵간해서는 내장된거 써라. 

         

        Animation 

        시간경과에 따라 데이터가 어떻게 변경되는지 결정.

        시간 흐름에 따른 데이터를 보관하는 방법. 

        1.

        타이밍 커브 애니메이션 (Timing Curve Animation)

        속도 및 지속 기간을 정의하는 곡선을 사용합니다:

        • linear: 일정한 속도로 선형 진행
        • easeIn: 천천히 시작하여 점점 빨라짐
        • easeOut: 빠르게 시작하여 점점 느려짐
        • easeInOut: 천천히 시작하여 점점 빨라지다가 다시 점점 느려짐
        • custom: timingCurve 메서드를 사용하여 커스텀 곡선 정의 가능

        2. 스프링 애니메이션 (Spring Animation)

        스프링의 물리적 특성을 시뮬레이션하여 자연스러운 움직임을 구현합니다:

        • smooth: 바운스가 전혀 없음 (iOS 17부터 withAnimation의 기본값)
        • snappy: 바운스가 적고 빠르게 안정화
        • bouncy: 바운스가 많고 활발한 움직임
        • custom: spring 메서드를 이용해 커스텀 설정 가능. iOS 17부터는 duration과 bounce 매개변수만으로도 커스텀 가능

        3. 고차 애니메이션 (Higher Order Animation)

        기존 애니메이션을 변형하는 메서드들:

        • speed: 애니메이션 속도 조절
        • delay: 애니메이션 시작 전 지연 시간 설정
        • repeatCount: 애니메이션 반복 횟수 지정
        • repeatForever: 애니메이션을 무한 반복

        4. 커스텀 애니메이션

        animate 메서드는 애니메이션의 현재 값을 반환하거나, 애니메이션이 끝나면 nil을 반환합니다.

        만약 위의 scaleEffect를 보면 2와 1차이가 난다. 벡터 덧셈과 스칼라 곱연산으로 swiftUI는 이 두벡터를 서로 빼  두 벡터 사이의 델타를 계산한다. 즉 1->2로 변하는게 아닌 0에서 1로 보간. 

        요런식으로 델타 계산

        그런데 만약 애니메이션이 끝나기전에 다시 토글을 하면 어떻게 될까?

        새애니메이션이 나오고 shouldMerge를 호출한다. 두 애니메이션이 합쳐진 결과가 시스템에 의해 결합된다. SwiftUI 애니메이션이 델타 벡터로 처리하는 이유!! 여러 애니메이션이 실행 중일 때 정확한 결합 프레젠테이션값을 쉽게 계산할수 있다. 

        새 애니메이션이 병합할때. velocity로 속도유지 

        Transaction?

        - 현재 업데이트에 대한 모든 컨텍스트, 특히 애니메이션을 암시적으로 전파하는데 사용되는 딕셔너리. 

        Transaction의 역할

        • 뷰 업데이트 과정에서 애니메이션 정보를 전달합니다.
        • 속성이 지정된 경우 트랜잭션의 애니메이션을 재정의할 수 있습니다.
        • body가 호출될 때마다 트랜잭션에 애니메이션 존재 여부를 확인하고, 속성이 있으면 이를 재정의합니다.

        주의사항

        모든 하위 뷰에 대한 애니메이션을 무차별적으로 재정의하면 의도하지 않은 애니메이션이 발생할 수 있습니다. 따라서 애니메이션 적용 범위를 신중하게 관리해야 합니다.

        animation에 접근하여 본문이 호출될때마다 트랜젝션에 애니메이션이 없거나 있어도 속성이 애니메이션을 재정의 한다.

         

        !! 뷰를 업데이트할때마다 모든 하위에 대한 애니메이션을 무차별적으로 재정의하면서 의도하지 않은 애니메이션이나올수 있다.

        Animation Modifier: 애니메이션 범위 제한

        @inlinable public func animation<V>(_ animation: Animation?, value: V) -> some View where V: Equatable

         

        value를 받아 범위를 지정한다. 값이 변할때만 트랜젝션에 기록. 그러면 withAnimation을 지워도된다. 

        요놈도 주의할점 해당 animation modifier는 하위 계층이 사용자의 제어 하에 있는 leaf Components에 적합 

        만약 leaf Components가 아니면 예기치 못한 애니메이션 나올수 있다. 

        만약 저 컨텐트에 다양하게 들어가려고할때 애니메이션이 원하는대로 동작을 안할수 있기에 속성을 저런식으로 좁힐수 있다. wow

        헷갈리는거 정리! 

        WithAinmation

        - 상태 변경에 따른 전체 뷰 업데이트 애니메이션

        - 특정 코드 블록내에서 발생하는 모든 상태변경에 애니메이션적용

        Button("Toggle") {
            withAnimation(.spring()) {
                isExpanded.toggle()  // 이 상태 변경으로 인한 모든 뷰 업데이트에 애니메이션 적용
            }
        }

         

        적합한 상황

        • 여러 상태 값을 동시에 변경하면서 모두 동일한 애니메이션을 적용할 때
        • 버튼 클릭이나 제스처와 같은 사용자 상호작용에 반응하여 애니메이션을 트리거할 때
        • 특정 이벤트에서 전체 뷰 계층에 애니메이션을 적용할 때

        특징

        • 코드 블록 단위로 애니메이션 범위를 정의
        • Transaction에 애니메이션 정보를 포함시켜 전파
        • iOS 17부터 기본값이 .smooth 스프링 애니메이션으로 변경

        Animation 모디파이어

        - 특정 값의 변화에 대해서만 애니메이션 적용

        - 지정된 값이 변경될 때만 애니메이션이 트리거됨

        Circle()
            .frame(width: isLarge ? 100 : 50)
            .animation(.easeInOut, value: isLarge)  // isLarge 값이 변경될 때만 애니메이션 적용

        적합한 상황

        • 특정 상태 값의 변화에만 애니메이션을 적용하고 싶을 때
        • 여러 상태가 변경되지만 일부에만 애니메이션을 적용하고 싶을 때
        • 사용자 제어 하에 있는 최종(leaf) 컴포넌트에 애니메이션을 적용할 때
        • withAnimation 블록 없이 선언적으로 애니메이션을 정의하고 싶을 때

        특징

        • 뷰 수정자 체인에서 선언적으로 사용
        • 지정된 값(value: 매개변수)이 변경될 때만 애니메이션이 트리거됨
        • 해당 수정자가 적용된 뷰와 그 하위 뷰에만 영향을 미침

        transition

        목적

        • 뷰의 출현과 사라짐에 대한 애니메이션
        • 조건부 뷰가 추가되거나 제거될 때 적용되는 시각적 효과
        if isShowing {
            Text("Hello, World!")
                .transition(.slide)  // 뷰가 나타나거나 사라질 때 슬라이드 효과 적용
        }
        
        // 또는
        Text("Hello, World!")
            .opacity(isVisible ? 1 : 0)
            .transition(.opacity)  // 투명도 변화를 통한 전환

        적합한 상황

        • 조건부 뷰의 표시/숨김에 애니메이션을 적용할 때
        • 뷰가 화면에 추가되거나 제거될 때 시각적 효과를 원할 때
        • 뷰 전환 효과(페이드, 슬라이드, 스케일 등)를 구현할 때

        특징

        • 뷰의 추가/제거 시에만 적용됨
        • .slide, .scale, .opacity, .move 등 다양한 내장 전환 효과 제공
        • .combined(with:) 메서드로 여러 전환 효과를 결합 가능
        • withAnimation이나 animation 수정자와 함께 사용해야 실제로 애니메이션이 적용됨

        참고한 감사한 블로그

        https://green1229.tistory.com/375

        'SWIFT개발' 카테고리의 다른 글

        @ViewBuilder & @resultBuilder  (1) 2024.02.26
        근본으로 돌아가자(3)-View Layout  (2) 2024.02.26
        View Modifier  (0) 2023.12.14
        Spritekit with swiftui(1)  (0) 2023.05.01
        CoreMotion - Swift  (1) 2023.04.29
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바