I've been playing with my own custom view and Animatable to make it animate.
I got it going, but do not understand 100% what happens behind the scenes, and this is never good to help understanding something.
Take for example the following simple struct:
struct MyRect: Shape {
var scale: Double
var animatableData: Double {
get { return scale }
set { scale = newValue }
}
func path(in rect: CGRect) -> Path {
var path = Path()
let w = min(rect.width, rect.height)*CGFloat(scale)
let scaledRect = CGRect(origin: rect.origin, size: CGSize(width: w, height: w))
path.addRect(scaledRect)
return path
}
}
animatableData returns a double, and the getter and setter works with scale. It intuitively makes sense that scale is the property being animated but animatableData does not really have anything to do with scale.
Take for example this slight modification where scale is changed from a double to an Int, where 0 represents 0% and 100 represents 100%:
struct MyRect: Shape {
var scale: Int
private var scaleAsDouble: Double
init(scale: Int) {
self.scale = scale
scaleAsDouble = Double(scale)
}
var animatableData: Double {
get { return scaleAsDouble }
set { scaleAsDouble = newValue }
}
func path(in rect: CGRect) -> Path {
var path = Path()
let w = min(rect.width, rect.height)*CGFloat(scaleAsDouble)/100.0
let scaledRect = CGRect(origin: rect.origin, size: CGSize(width: w, height: w))
path.addRect(scaledRect)
return path
}
}
In this case, my Shape as an integer property that cannot be animated, because it cannot have fractional steps. The solution is to store a doulbe that can have a fractional part, and use it as the animatableData.
What I do not get, is how does the framework know to use the scale property? What are the steps that the framework uses when scale is changes from one value to another in order to call the setter on animatableData with the correct values?