[SwiftUI] Shape & Animation

Junyoung Park·2022년 8월 21일
0

SwiftUI

목록 보기
35/136
post-thumbnail
post-custom-banner

Animate Custom shapes with AnimateableData in SwiftUI | Advanced Learning #7

Shape & Animation

구현 목표


  • 커스텀 도형을 만든 뒤 애니메이션을 입힌다.
  • 사각형 중 한 모서리의 각만 변화하는 애니메이션
  • 팩맨이 입을 열고 닫는 애니메이션

구현 태스크

  1. 커스텀 도형을 구현한다.
  2. 애니메이션을 줄 위치의 각도를 파라미터로 전달한다.
  3. 커스텀 도형이 애니메이션을 파악할 수 있도록 연산 프로퍼티 animatableData를 설정한다.

핵심 코드

var animatableData: CGFloat {
        get { cornerRadius }
        set { cornerRadius = newValue }
    }
  • animatableData를 설정하지 않으면 해당 커스텀 도형 내의 Path 함수는 현재 값이 바뀌는지 알아차리지 못하기 때문에 필수적

소스 코드

import SwiftUI

struct RectangeWithSingleCornerAnimation: Shape {
    var cornerRadius: CGFloat
    var animatableData: CGFloat {
        get { cornerRadius }
        set { cornerRadius = newValue }
    }
    func path(in rect: CGRect) -> Path {
        Path { path in
            path.move(to: .zero)
            path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
            path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - cornerRadius))
            path.addArc(center: CGPoint(x: rect.maxX - cornerRadius, y: rect.maxY - cornerRadius),
                        radius: cornerRadius,
                        startAngle: Angle(degrees: 0),
                        endAngle: Angle(degrees: 360),
                        clockwise: false)
            path.addLine(to: CGPoint(x: rect.maxX - cornerRadius, y: rect.maxY))
            path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
        }
    }
}

struct Pacman: Shape {
    var offsetAmount: CGFloat
    var animatableData: CGFloat {
        get { offsetAmount }
        set { offsetAmount = newValue }
    }
    func path(in rect: CGRect) -> Path {
        Path { path in
            path.move(to: CGPoint(x: rect.midX, y: rect.minY))
            path.addArc(center: CGPoint(x: rect.midX, y: rect.minY),
                        radius: rect.height / 2,
                        startAngle: Angle(degrees: offsetAmount),
                        endAngle: Angle(degrees: 360 - offsetAmount),
                        clockwise: false)
        }
    }
}

struct CustomShapeAnimationBootCamp: View {
    @State private var animate: Bool = false
    var body: some View {
        VStack {
            Spacer()
            RectangeWithSingleCornerAnimation(cornerRadius: animate ? 60 : 0)
                .frame(width: 250, height: 250)
            Spacer()

            Pacman(offsetAmount: animate ? 20 : 0)
                .frame(width: 250, height: 250)
        }
        .onAppear {
            withAnimation(.easeInOut.repeatForever()) {
                animate.toggle()
            }
        }
    }
}

구현 화면

profile
JUST DO IT
post-custom-banner

0개의 댓글