Is it possible to not use UIViews when playing with UIKit Dynamics, and instead bind the physics properties, anchors, forces etc to CALayers all within one UIView?
According to this page by Ash Farrow:
UIDynamicItem is a protocol that defines a centre, a bounds, and a transform (only two-dimensional transforms are used). UIView conforms to this protocol, and is the most common use of UIDynamicBehaviour. You can also use UICollectionViewLayoutAttributes with UIDynamicBehaviours, but we’re not going to cover that today.
Which seems to indicate that anything can be made to conform to the protocol UIDynamicItem, but I can't find anything about others playing around with making CALayers.
Can it be done more directly than this approach:
https://www.invasivecode.com/weblog/uikit-dynamics-layer-constraint/
As the linked article notes, CALayer
has conflicting types for these methods, so it can't directly conform to UIDynamicItem
. What you'd need would be some kind of adapter layer that converted the CALayer
methods into the types and meanings needed by UIDynamicItem
.
Luckily, UIKit offers exactly such an adapter layer. It's called UIView
. Just put each layer in a view and nest the views.
I had long thought of views as very heavyweight, particularly coming from the OS X world. So I always thought "if you want this to be fast, you'd better do it with a layer." But it turns out that views are actually quite thin and there isn't a lot of overhead vs a layer in most cases, particularly for the numbers you're talking about in iOS. See the TearOff demo for an example that does UIKItDynamics with many dozens of views without trouble.
If you really do need layers, then yes, you can definitely still do it. Just create the adapter yourself. It just needs to hold a CALayer
and conform to UIKitDynamics
. It doesn't have to do anything else. Something like this should work:
public class DynamicLayerItem : NSObject, UIDynamicItem {
let layer: CALayer
init(layer: CALayer) { self.layer = layer}
public var center: CGPoint { get {
return layer.position
}
set {
layer.position = center
}
}
public var bounds: CGRect { return layer.bounds }
public var transform: CGAffineTransform {
get {
return layer.affineTransform()
}
set {
layer.transform = CATransform3DMakeAffineTransform(newValue)
}
}
}
You'd just animate this object, and that causes the layer to animate equivalently.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With