Skip to content

Instantly share code, notes, and snippets.

@davidbjames
Created September 14, 2017 14:21
Show Gist options
  • Save davidbjames/d53536746fad1b21bfc39487beae670e to your computer and use it in GitHub Desktop.
Save davidbjames/d53536746fad1b21bfc39487beae670e to your computer and use it in GitHub Desktop.
Transformable
public protocol Transformable : class {
func scaled(x:CGFloat, y:CGFloat, z:CGFloat?)
func rotated(_ radians:CGFloat, x:CGFloat?, y:CGFloat?, z:CGFloat?)
func translated(x:CGFloat, y:CGFloat, z:CGFloat?)
func resetScale()
func resetRotation()
func resetTranslation()
func resetAllTransforms()
}
public extension Transformable where Self:UIView {
func scaled(x:CGFloat, y:CGFloat, z:CGFloat? = nil) {
transform = transform.scaledBy(x: x, y: y)
}
func rotated(_ radians:CGFloat, x:CGFloat? = nil, y:CGFloat? = nil, z:CGFloat? = nil) {
transform = transform.rotated(by: radians)
}
func translated(x:CGFloat, y:CGFloat, z:CGFloat? = nil) {
transform = transform.translatedBy(x: x, y: y)
}
private var scaleDelta:CGAffineTransform {
let t = transform
let xScale = sqrt(t.a * t.a + t.c * t.c)
let yScale = sqrt(t.b * t.b + t.d * t.d)
return CGAffineTransform(scaleX: xScale, y: yScale)
}
private var rotationDelta:CGAffineTransform {
let rotation = CGFloat(atan2f(Float(transform.b), Float(transform.a)))
return CGAffineTransform(rotationAngle: rotation)
}
private var translationDelta:CGAffineTransform {
return CGAffineTransform(translationX: transform.tx, y: transform.ty)
}
func resetScale() {
transform = rotationDelta.concatenating(translationDelta)
}
func resetRotation() {
transform = scaleDelta.concatenating(translationDelta)
}
func resetTranslation() {
transform = scaleDelta.concatenating(rotationDelta)
}
func resetAllTransforms() {
transform = CGAffineTransform.identity
}
}
public extension Transformable where Self:CALayer {
func scaled(x:CGFloat, y:CGFloat, z:CGFloat?) {
transform = CATransform3DScale(transform, x, y, z ?? 0.0)
}
func rotated(_ radians:CGFloat, x:CGFloat?, y:CGFloat?, z:CGFloat?) {
transform = CATransform3DRotate(transform, radians, x ?? 1.0, y ?? 0.0, z ?? 0.0)
}
func translated(x:CGFloat, y:CGFloat, z:CGFloat?) {
transform = CATransform3DTranslate(transform, x, y, z ?? 0.0)
}
private var scaleDelta:CATransform3D? {
guard
let scaleX = value(forKeyPath: "transform.scale.x") as? CGFloat,
let scaleY = value(forKeyPath: "transform.scale.y") as? CGFloat,
let scaleZ = value(forKeyPath: "transform.scale.z") as? CGFloat
else {
return nil
}
return CATransform3DMakeScale(scaleX, scaleY, scaleZ)
}
private var rotationDelta:CATransform3D? {
guard
let angle = value(forKeyPath: "transform.rotation.angle") as? CGFloat,
let x = value(forKeyPath: "transform.rotation.x") as? CGFloat,
let y = value(forKeyPath: "transform.rotation.y") as? CGFloat,
let z = value(forKeyPath: "transform.rotation.z") as? CGFloat
else {
return nil
}
return CATransform3DMakeRotation(angle, x, y, z)
}
private var translationDelta:CATransform3D? {
guard
let x = value(forKeyPath: "transform.translation.x") as? CGFloat,
let y = value(forKeyPath: "transform.translation.y") as? CGFloat,
let z = value(forKeyPath: "transform.translation.z") as? CGFloat
else {
return nil
}
return CATransform3DMakeTranslation(x, y, z)
}
func resetScale() {
guard let rotation = rotationDelta, let translation = translationDelta else {
return
}
transform = CATransform3DConcat(rotation, translation)
}
func resetRotation() {
guard let scale = scaleDelta, let translation = translationDelta else {
return
}
transform = CATransform3DConcat(scale, translation)
}
func resetTranslation() {
guard let scale = scaleDelta, let rotation = rotationDelta else {
return
}
transform = CATransform3DConcat(scale, rotation)
}
func resetAllTransforms() {
transform = CATransform3DIdentity
}
}
extension UIView : Transformable {}
extension CALayer : Transformable {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment