티스토리 뷰

iOS

CoreAnimation

malrang-malrang 2022. 6. 22. 01:28

CoreAnimation

시각적 요소(visual elements)를 렌더링, 합성하고 애니메이션화합니다.

Overview

코어 애니메이션은 CPU에 부담을 주거나 앱 속도를 늦추지 않고 높은 프레임률과 부드러운 애니메이션을 제공합니다. 애니메이션의 각 프레임을 그리는 데 필요한 대부분의 작업은 사용자를 위해 수행됩니다. 시작점 및 끝점과 같은 애니메이션 매개 변수를 구성하면 나머지는 코어 애니메이션이 수행하고 대부분의 작업은 전용 그래픽 하드웨어로 넘겨 렌더링 속도를 높일 수 있습니다. 자세한 내용은 애니메이션 프로그래밍 가이드 를 참조하십시오.

위의 애니메이션 프로그래밍 가이드를 요약하자면 Core Animation은 iOS / OS X에서 사용 할 수 있는 그래픽 렌더링 및 애니메이션 인프라다.

CoreAnimation은 드로잉 시스템이아니다 하드웨어에서 앱의 컨텐츠를 합성/조작 하기위한 인프라 이기 때문에 직접 애니메이션을 조작하는게 아니라 실제 드로잉 작업을 하드웨어로 전달한다.

CoreAnimation 인프라의 핵심은 Layer객체(CALayer)다.
요녀석은 컨텐츠를 관리/조작 하는데 사용된다.

CoreAnimation을 사용하면 대부분의 작업이 자동으로 수행된다.
시작과 끝 같은 파라미터를 구성하고 CoreAnimation이 시작하도록 지시하면된다.

CoreAnimation은 실제 드로잉 작업을 온보드 그래픽 하드웨어로 전달해 렌더링 속도를 높인다.(CPU에 부담을 주지않고 앱속도를 늦추지 않고 높은 프레임률과 부드러운 애니메이션을 제공하기위해)

음..그렇다고한다.

이어서 CoreAnimation을 사용하는 녀석들을 알아보자!

CoreAnimation내부에 있는녀석들이다.

위의 상속도? 를 보면 최상단에 CAAnimation이라는 추상클래스 를 상속받는 형태 니까 CAAnimation 요녀석부터 봐보자!

CAAnimation


Core Animation의 애니메이션에 대한 추상 슈퍼클래스입니다.

음.. 그건알고있는데 말이지..

Declaration

class CAAnimation : NSObject

Overview

CA 애니메이션은 CAMedia Timing 및 CA Action 프로토콜에 대한 기본 지원을 제공합니다.
CA Animation 인스턴스를 만들지 않습니다.
Core Animation 도면층 또는 SceneKit 객체를 애니메이션하려면 구체적인 하위 클래스 CABasic Animation, CAKeyframeAnimation, CAAnimationGroup 또는 CATtransition의 인스턴스를 만듭니다.

Animating Core Animation Layers

CALayer 객체에 애니메이션을 첨부하여 iOS 또는 macOS 앱의 사용자 인터페이스 내용을 애니메이션화할 수 있습니다. 자세한 내용은 Core Animation Programming Guide를 참조하십시오.

Animating Scene Kit Content

Scene Kit에서 애니메이션 개체는 속성 기반 애니메이션뿐만 아니라 외부 3D 저작 도구로 만들어 장면 파일에서 로드한 지오메트리 데이터의 애니메이션도 나타냅니다. 지오메트리 애니메이션을 나타내는 CA Animation 개체의 속성을 사용하여 타이밍을 제어하고 진행률을 모니터링하며 애니메이션 중에 Scene Kit가 트리거할 작업을 첨부할 수 있습니다. 노드, 지오메트리 및 재료를 포함하여 SCNA Animatable 프로토콜을 채택하는 Scene Kit 개체에 애니메이션을 첨부할 수 있습니다.

Scene Kit 앱에서 CA Animation 개체는 Scene Kit Animation Timing 제어, SceneKit Animation 간 페이딩 및 SceneKit Animation Event Attaching에 나열된 추가 메서드 및 속성을 지원합니다.

CAAnimation인스턴스를 만들어 사용하는게아니라 용도에 맞게 CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup 또는 CATtransition의 인스턴스를 만들어 사용하라는것 같다.

그러면 기본이되는 CABasicAnimation 부터 하나씩 보자!

CABasicAnimation

레이어 속성에 대한 기본 단일 키프레임 애니메이션 기능을 제공하는 개체입니다.

Declaration

class CABasicAnimation : CAPropertyAnimation

CAPropertyAnimation 이녀석도 CAAnimation과 마찬가지로 추상클래스다!

OverView

렌더링 트리에서 애니메이션화할 속성의 키 경로를 지정하는 상속된 init(keyPath:) 메서드를 사용하여 CABasicAnimation 인스턴스를 만듭니다.

예를 들어 불투명도와 같은 계층의 스칼라(즉, 단일 값 포함) 속성을 애니메이션화할 수 있습니다. 목록 1은 0에서 1로 불투명도를 애니메이션화하여 레이어에서 페이드화됩니다.

//keyPath 에 작성된 값은 Layer의 프로퍼티다.
//opacity 라는 프로퍼티를 fromValue에서 toValue로 변경해달라는 뜻이다.
let animation = CABasicAnimation(keyPath: "opacity") 
animation.fromValue = 0 
animation.toValue = 1

backgroundColor와 같은 비 스칼라 속성도 애니메이션으로 만들 수 있습니다. 코어 애니메이션은 from Value 색상과 to Value 색 사이에 보간합니다. 목록 2에서 만든 애니메이션은 레이어의 배경색을 빨간색에서 파란색으로 바꿉니다.

//위의 예제 코드와 비슷하다 backgroundColor 를  red 에서 blue로 변경하는 애니메이션이란것을 알수있다!
let animation = CABasicAnimation(keyPath: "backgroundColor")
animation.fromValue = NSColor.red.cgColor
animation.toValue = NSColor.blue.cgColor

값이 서로 다른 비스케일 속성의 개별 구성 요소를 애니메이션으로 만들려면 값을 값으로 전달하거나 값에서 배열로 전달합니다. 목록 3에서 만든 애니메이션은 레이어를 (0, 0)에서 (100, 100)으로 이동합니다.

요건 설명한대로 위치를 변경해주는 애니메이션이 겠죠?

let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = [0, 0]
animation.toValue = [100, 100]

Setting Interpolation Values

위에서 사용할때 from 이랑 to 만 사용했는데 by 라는 녀석도 있다.
총 3개를 2개씩 묶어서 조합해서 사용할수있다.

간단요약

  • fromValue and toValue:
    • from 에서 to 까지
  • fromValue and byValue(상대적인 값을 의미한다):
    • fromValue + byValue
  • byValue and toValue:
    • toValue - byValue

Topics

  • var fromValue: Any?
    • 수신기가 보간을 시작하는 데 사용하는 값을 정의합니다.
  • var toValue: Any?
    • 수신기가 보간을 종료하는 데 사용하는 값을 정의합니다.
  • var byValue: Any?
    • 수신기가 상대 보간을 수행하는 데 사용하는 값을 정의합니다.

CAKeyframeAnimation

레이어 개체에 대한 키프레임 애니메이션 기능을 제공하는 개체입니다.

Declaration

class CAKeyframeAnimation : CAPropertyAnimation

요녀석도 위의 CABasicAnimation처럼 CAPropertyAnimation을 상속받는애다.

Overview

계층에서 애니메이션화할 속성의 키 경로를 지정하는 상속된 init(keyPath:) 메서드를 사용하여 CAKeyframeAnimation 개체를 생성합니다. 그런 다음 타이밍 및 애니메이션 동작을 제어하는 데 사용할 키 프레임 값을 지정할 수 있습니다.

대부분의 애니메이션 유형의 경우 값과 keyTimes 속성을 사용하여 키 프레임 값을 지정합니다. 애니메이션 중에 코어 애니메이션은 사용자가 제공한 값 사이를 보간하여 중간 값을 생성합니다. 도면층의 위치와 같은 좌표점인 값을 애니메이션화할 때 개별 값 대신 해당 점이 따를 경로를 지정할 수 있습니다. 애니메이션의 페이싱은 사용자가 제공하는 타이밍 정보에 의해 제어됩니다.

목록 1은 레이어의 배경색을 빨간색에서 녹색에서 파란색으로 2초 동안 애니메이션화하는 키 프레임 애니메이션을 만드는 방법을 보여줍니다.

예제 코드는 2초 동안 빨간색에서 녹색, 파란색으로 레이어의 배경색을 애니메이션으로 만드는 키프레임 애니메이션을 만드는 방법을 보여줍니다.

요녀석도 keyPath를 사용한다.
CABasicAnimation보다 쪼끔더 세밀한 애니메이션을 만들수있다.

예제코드

let colorKeyframeAnimation = CAKeyframeAnimation(keyPath: "backgroundColor")

//values 는 변화될 값을 의미한다.(위의 backgroundColor를 의미)
//backgroundColor가 red->green->blue로 변화할건데 시간을 지정해줄수있다. 
colorKeyframeAnimation.values = [UIColor.red.cgColor,
                                 UIColor.green.cgColor,
                                 UIColor.blue.cgColor]
//시간을 지정해주는 코드
//UIView animate() 메서드 사용할때랑 비슷하다.
//keyTimes 의 최대값은 1이며 전체 애니메이션시간의 퍼센트를 나타낸다고 생각하면 이해가 쉽다.
//아래처럼 배열러 0, 0.5, 1 로 구분지었는데 처음 애니메이션이 시작할때는 red색상,
// 총애니메이션의 50% 지점에서는 green색상,
//  애니메이션이 끝날때 색상은 blue로 변경하도록 한것이다.
colorKeyframeAnimation.keyTimes = [0, 0.5, 1]
//애니메이션이 실행될 시간은 2초라는 뜻이다.
colorKeyframeAnimation.duration = 2

CATransition

레이어 상태 간에 애니메이션 전환을 제공하는 개체입니다.

Declaration

class CATransition : CAAnimation

Overview

레이어가 이전의 상태에서 다음의 상태로 변화하는것을 알아서 처리해준다.

도면층에 CAT 전환 개체를 생성하고 추가하여 도면층의 상태 간에 전환할 수 있습니다. 기본 전환은 교차 페이드이지만 미리 정의된 전환 집합과 다른 효과를 지정할 수 있습니다.

목록 1은 transitioningLayer라는 이름의 CATextLayer의 두 상태 간에 전환할 수 있는 방법을 보여줍니다. 도면층을 처음 만들 때 배경색이 빨간색으로 설정되고 문자열 속성이 빨간색으로 설정됩니다. runTransition() 함수를 호출하면 새 CAT Transition 객체가 생성되어 transitionLayer에 추가되고 레이어의 상태는 배경색이 파란색이고 렌더링된 텍스트가 파란색이 되도록 변경됩니다.

최종 결과는 푸시 전환이 왼쪽에서 오른쪽으로 빨간색 상태를 애니메이션화하고 파란색 상태가 왼쪽에서 씬(scene)으로 들어가는 것입니다.

음... 그러니까 얘는

let transitioningLayer = CATextLayer()

//transition 의 초기값
override func viewDidLoad() {
    super.viewDidLoad()
    transitioningLayer.frame = CGRect(x: 10, y: 10,
                                      width: 320, height: 160)

    view.layer.addSublayer(transitioningLayer)

    // Initial "red" state
    //backgroundColor 는 red 색상이다.
    transitioningLayer.backgroundColor = UIColor.red.cgColor
    transitioningLayer.string = "Red"
}


func runTransition() {
    let transition = CATransition()
    //트랜지션은 2초동안 움직일건데!
    transition.duration = 2

    //트랜지션의 타입은 푸쉬 타입이다! 푸쉬말고도 여러개있다.
    transition.type = kCATransitionPush

    transitioningLayer.add(transition,
                           forKey: "transition")

    // Transition to "blue" state
    transitioningLayer.backgroundColor = UIColor.blue.cgColor
    transitioningLayer.string = "Blue"
}

이부분은 좀더 해봐야 알겠지만 초기값 Red에서 Blue로 변화하는 효과를 가지게 된다는뜻같다. 이때 어떻게 변화할것이냐 를 설정하는것이 트랜지션 타입 같다.
push 방식으로 변화를 주겠다 라는 뜻같다.(아직 실험안해봤슴다 실험해보고 수정할게용)

타입에는 fade, moveIn, push, reveal 이 있다

CAAinmationGroup

여러 애니메이션을 그룹화하고 동시에 실행할 수 있는 개체입니다.

요녀석 여러개의 애니메이션을 묶어서 관리할때 사용된다!

Declaration

class CAAnimationGroup : CAAnimation

Overview

그룹화된 애니메이션은 CAAnimation Group 인스턴스에 의해 지정된 시간 공간에서 실행됩니다.

그룹화된 애니메이션의 지속 시간은 해당 CA 애니메이션 그룹의 지속 시간으로 조정되지 않습니다. 대신 애니메이션은 애니메이션 그룹의 기간으로 잘립니다. 예를 들어 애니메이션 그룹 내에서 5초 동안 그룹화된 10초 애니메이션은 애니메이션의 처음 5초만 표시합니다.

목록 1은 불투명도가 포함된 그룹화된 애니메이션을 만들고 애니메이션 크기를 조정하여 레이어를 확장하는 방법을 보여줍니다. 애니메이션은 모든 축에서 불투명도 1과 스케일 1로 시작합니다. 애니메이션의 크기가 (3, 3, 3)로 증가하면 불투명도는 0으로 떨어지고 애니메이션 레이어는 사라집니다.

예제코드

//keyPath 에 작성된 값은 Layer의 프로퍼티다.
//opacity 라는 프로퍼티를 fromValue에서 toValue로 변경해달라는 뜻이다.
let fadeOut = CABasicAnimation(keyPath: "opacity")
fadeOut.fromValue = 1
fadeOut.toValue = 0
//애니메이션이 몇초간 실행할지 설정하는 코드.
fadeOut.duration = 1

let expandScale = CABasicAnimation()
expandScale.keyPath = "transform"
expandScale.valueFunction = CAValueFunction(name: kCAValueFunctionScale)
expandScale.fromValue = [1, 1, 1]
expandScale.toValue = [3, 3, 3]

let fadeAndScale = CAAnimationGroup()
//fadeAndScale 이라는 AnimationGroup 이있는데 group의 애니메이션은 [fadeOut, expandScale](배열)이다.
fadeAndScale.animations = [fadeOut, expandScale]
//fadeAndScale의 애니메이션들이 실행되는 시간을 1초로 설정한 코드
fadeAndScale.duration = 1

CoreAnimation을 구현해보자!

layer에는 모델레이어와 프레젠트레이어가 존재한다!
쉽게 말하자면 실제값과 보여지는 값이다.

애니메이션 효과가 일어난후 모델레이어 혹은 프레젠트레이어 2개중 하나를 변경하지 않으면
애니메이션 효과가 발생하기전의 위치로 되돌아가게된다!

예를들면 애니메이션에서 View의 위치값 x를 0에서 50만큼 이동했다고 가정하자!

애니메이션효과가 끝나고 View의 x값을 50으로 변경하여 보여주고싶다면 모델레이어, 프레젠트레이어 둘중하나를 변경해주어야한다!

아래의 예제코드를 보자!
아래의 예제 코드는 버튼인데 draw메서드를 사용하여 다음과 같은 이미지를 같는 버튼이다.

class plusButton: UIButton {

  override func draw(_ rect: CGRect) {
    // 그림을 그릴 Context를 가져옴
    guard let context = UIGraphicsGetCurrentContext() else {
      return
    }

    // 그려질 범위를 10% 씩 줄임
    let circleRect = bounds.insetBy(
      dx: bounds.height * 0.1,
      dy: bounds.width * 0.1
    )

    //시작
    context.beginPath()
    //선 굵기
    context.setLineWidth(15)
    //선 색상
    context.setStrokeColor(UIColor.systemGreen.cgColor)
    // 지정된 사각형 안에 타원 추가
    context.addEllipse(in: circleRect)
    //선의 끝점 스타일
    context.setLineCap(.round)
    // 그림을 그릴 시작점으로 move
    context.move(to: CGPoint(x: bounds.width * 0.2, y: bounds.height * 0.5))
    // 원한 지점까지 경로설정
    context.addLine(to: CGPoint(x: bounds.width * 0.8, y: bounds.height * 0.5))
    context.move(to: CGPoint(x: bounds.width * 0.5, y: bounds.height * 0.2))
    context.addLine(to: CGPoint(x: bounds.width * 0.5, y: bounds.height * 0.8))
    // 그리기 모드를 사용하여 현재 경로를 그림
    context.drawPath(using: .stroke)
    //종료
    context.closePath()
  }
}

다음으로 구현할 기능은 버튼을 클릭하게되면 해당버튼의 z축이 40도 회전하는 애니메이션이다.
요녀석도 예제 코드를 보자!

class ViewController: UIViewController {

    @IBOutlet weak var plusButton: plusButton!

    override func viewDidLoad() {
        super.viewDidLoad()
    }


    @IBAction func didTapPlusButton(_ sender: UIButton) {

        let rotation = CABasicAnimation(keyPath: "transform.rotation")

        rotation.fromValue = 0
        // pi = 180도
        rotation.toValue = Double.pi / 18 * 4
        // 1바퀴 도는데 걸리는 시간
        rotation.duration = 1
        rotation.fillMode = .forwards
        rotation.isRemovedOnCompletion = false

        // 프레젠트 레이어 변경하는 코드
        // rotation.fillMode = .forwards
        // rotation.isRemovedOnCompletion = false

        plusButton.layer.add(rotation, forKey: "rotationAnimation")

        // 모델 레이어 변경하는 코드
        plusButton.layer.setAffineTransform(.init(rotationAngle: Double.pi / 18 * 4))
    }
}

위에 작성된 코드처럼 프레젠트 레이어를 변경하던지 모델레이어의 값을 변경하던지 해주어야 애니메이션이끝난후 의 값이 예전으로 되돌아가지 않는다.

이제 버튼을 누르면 요렇게 된다!

'iOS' 카테고리의 다른 글

UIActivityViewController  (0) 2022.06.25
DateFormatter  (0) 2022.06.24
Core Graphics  (0) 2022.06.22
CoreData  (0) 2022.06.19
Diffable Datasource  (0) 2022.06.19
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함