기어가더라도 제대로

[SwiftUI-기초] Shape 를 복잡한 애니메이션 주기 본문

SwiftUI - 기초

[SwiftUI-기초] Shape 를 복잡한 애니메이션 주기

Damagucci-juice 2022. 11. 22. 18:58

 

checkboard

struct Checkerboard: Shape {
    var rows: Int
    var columns: Int

    func path(in rect: CGRect) -> Path {
        var path = Path()

        let rowSize = rect.height / Double(rows)
        let columnSize = rect.width / Double(columns)

        for row in 0..<rows {
            for column in 0..<columns {
                if (row + column).isMultiple(of: 2) {
                    let startX = columnSize * Double(column)
                    let startY = rowSize * Double(row)

                    let rect = CGRect(x: startX, y: startY, width: columnSize, height: rowSize)
                    path.addRect(rect)
                }
            }
        }

        return path
    }
}
  • 행과 열을 받아서 보드판을 그리는 코드
struct ContentView: View {
    @State private var rows = 4
    @State private var columns = 4

    var body: some View {
        Checkerboard(rows: rows, columns: columns)
            .onTapGesture {
                withAnimation(.linear(duration: 3)) {
                    rows = 8
                    columns = 16
                }
            }
    }
}
  • withAnimation { }: 덕분에 애니메이션이 되길 기대하지만 되지 않음 
  • animatableData를 이용해야할텐데, 이 프로퍼티는 하나만 값을 받음 
  • 이 때 사용 가능한 것이 AnimatablePair
  • 두 Double을 감지 가능함 
var animatableData: AnimatablePair<Double, Double> {
    get {
       AnimatablePair(Double(rows), Double(columns))
    }

    set {
        rows = Int(newValue.first)
        columns = Int(newValue.second)
    }
}

 

두개 이상의 프로퍼티를 추적해야할 경우.

  • 예를 들어 애니메이션을 EdgeInset을 기반으로 주고 싶은 경우 이렇게 선언할 수 있다. 
AnimatablePair<CGFloat, AnimatablePair<CGFloat, AnimatablePair<CGFloat, CGFloat>>>
  • 타고타고 더 깊게 들어가는 것이 가능하다. 
  • newValue.second.second.first : 같이 값에 접근

 

이렇게 까지 하는 이유

  • 뷰를 애니메이션하면 1초에 60번에서 120번까지 바디를 다시 그리는데
  • 변화를 감지해야하는 부분만 animatableData 로 빼주어서 바디를 전부 다시그리는 것이 아닌 변화한 부분만 다시 그리도록 할 수 있다.

 

Comments