Skip to content

Commit 529a794

Browse files
Merge pull request #611 from C4Framework/RotationShapeImageMovie
Rotation shape image movie
2 parents 42134d7 + 3494d57 commit 529a794

27 files changed

+370
-22
lines changed

Diff for: C4/UI/C4Image.swift

+15
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,21 @@ public class C4Image: C4View, NSCopying {
322322
}
323323
}
324324

325+
/// The current rotation value of the view. Animatable.
326+
/// - returns: A Double value representing the cumulative rotation of the view, measured in Radians.
327+
public override var rotation: Double {
328+
get {
329+
if let number = imageLayer.valueForKeyPath(C4Layer.rotationKey) as? NSNumber {
330+
return number.doubleValue
331+
}
332+
return 0.0
333+
}
334+
set {
335+
imageLayer.setValue(newValue, forKeyPath: C4Layer.rotationKey)
336+
}
337+
}
338+
339+
325340
/// The scale factor of the image. (read-only)
326341
var scale: Double {
327342
return Double(uiimage.scale)

Diff for: C4/UI/C4ImageLayer.swift

+67-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ public class C4ImageLayer: CALayer {
3131
return nil
3232
}
3333

34-
if key != "contents" {
34+
let animatableProperties = ["contents", "rotation"]
35+
if !animatableProperties.contains(key) {
3536
return super.actionForKey(key)
3637
}
3738

@@ -43,8 +44,72 @@ public class C4ImageLayer: CALayer {
4344
}
4445

4546
animation.configureOptions()
46-
animation.fromValue = self.contents
47+
animation.fromValue = valueForKey(key)
48+
49+
if key == C4Layer.rotationKey {
50+
if let layer = presentationLayer() as? C4ShapeLayer {
51+
animation.fromValue = layer.valueForKey(key)
52+
}
53+
}
4754

4855
return animation
4956
}
57+
58+
59+
private var _rotation = 0.0
60+
61+
/// The value of the receiver's current rotation state.
62+
/// This value is cumulative, and can represent values beyong +/- π
63+
public dynamic var rotation: Double {
64+
return _rotation
65+
}
66+
67+
/// Initializes a new C4Layer
68+
public override init() {
69+
super.init()
70+
}
71+
72+
/// Initializes a new C4Layer from a specified layer of any other type.
73+
/// - parameter layer: Another CALayer
74+
public override init(layer: AnyObject) {
75+
super.init(layer: layer)
76+
if let layer = layer as? C4ImageLayer {
77+
_rotation = layer._rotation
78+
}
79+
}
80+
81+
/// Initializes a new C4Layer from data in a given unarchiver.
82+
/// - parameter coder: An unarchiver object.
83+
public required init?(coder: NSCoder) {
84+
super.init(coder: coder)
85+
}
86+
87+
/// Sets a value for a given key.
88+
/// - parameter value: The value for the property identified by key.
89+
/// - parameter key: The name of one of the receiver's properties
90+
public override func setValue(value: AnyObject?, forKey key: String) {
91+
super.setValue(value, forKey: key)
92+
if key == C4Layer.rotationKey {
93+
_rotation = value as? Double ?? 0.0
94+
}
95+
}
96+
97+
/// Returns a Boolean indicating whether changes to the specified key require the layer to be redisplayed.
98+
/// - parameter key: A string that specifies an attribute of the layer.
99+
/// - returns: A Boolean indicating whether changes to the specified key require the layer to be redisplayed.
100+
public override class func needsDisplayForKey(key: String) -> Bool {
101+
if key == C4Layer.rotationKey {
102+
return true
103+
}
104+
return super.needsDisplayForKey(key)
105+
}
106+
107+
/// Reloads the content of this layer.
108+
/// Do not call this method directly.
109+
public override func display() {
110+
guard let presentation = presentationLayer() as? C4ImageLayer else {
111+
return
112+
}
113+
setValue(presentation._rotation, forKeyPath: "transform.rotation.z")
114+
}
50115
}

Diff for: C4/UI/C4Movie.swift

+18-4
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public class C4Movie: C4View {
8787
}
8888
}
8989

90-
var movieLayer: AVPlayerLayer {
90+
var movieLayer: C4PlayerLayer {
9191
get {
9292
return self.movieView.movieLayer
9393
}
@@ -98,12 +98,26 @@ public class C4Movie: C4View {
9898
}
9999

100100
class MovieView: UIView {
101-
var movieLayer: AVPlayerLayer {
102-
return self.layer as! AVPlayerLayer // swiftlint:disable:this force_cast
101+
var movieLayer: C4PlayerLayer {
102+
return self.layer as! C4PlayerLayer // swiftlint:disable:this force_cast
103103
}
104104

105105
override class func layerClass() -> AnyClass {
106-
return AVPlayerLayer.self
106+
return C4PlayerLayer.self
107+
}
108+
}
109+
110+
/// The current rotation value of the view. Animatable.
111+
/// - returns: A Double value representing the cumulative rotation of the view, measured in Radians.
112+
public override var rotation: Double {
113+
get {
114+
if let number = movieLayer.valueForKeyPath(C4Layer.rotationKey) as? NSNumber {
115+
return number.doubleValue
116+
}
117+
return 0.0
118+
}
119+
set {
120+
movieLayer.setValue(newValue, forKeyPath: C4Layer.rotationKey)
107121
}
108122
}
109123

Diff for: C4/UI/C4PlayerLayer.swift

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright © 2015 C4
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to
5+
// deal in the Software without restriction, including without limitation the
6+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7+
// sell copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions: The above copyright
9+
// notice and this permission notice shall be included in all copies or
10+
// substantial portions of the Software.
11+
//
12+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18+
// IN THE SOFTWARE.
19+
20+
import QuartzCore
21+
import AVFoundation
22+
23+
/// Extension for CAShapeLayer that allows overriding the actions for specific properties.
24+
public class C4PlayerLayer: AVPlayerLayer {
25+
/// A boolean value that, when true, prevents the animation of a shape's properties.
26+
///
27+
/// ````
28+
/// C4ShapeLayer.disableActions = true
29+
/// circle.fillColor = red
30+
/// C4ShapeLayer.disableActions = false
31+
///
32+
/// This value can be set globally, after which changes to any shape's properties will be immediate.
33+
public static var disableActions = true
34+
35+
/// This method searches for the given action object of the layer. Actions define dynamic behaviors for a layer. For example, the animatable properties of a layer typically have corresponding action objects to initiate the actual animations. When that property changes, the layer looks for the action object associated with the property name and executes it. You can also associate custom action objects with your layer to implement app-specific actions.
36+
///
37+
/// - parameter key: The identifier of the action.
38+
///
39+
/// - returns: the action object assigned to the specified key.
40+
public override func actionForKey(key: String) -> CAAction? {
41+
if C4ShapeLayer.disableActions == true {
42+
return nil
43+
}
44+
45+
let animatableProperties = [C4Layer.rotationKey]
46+
if !animatableProperties.contains(key) {
47+
return super.actionForKey(key)
48+
}
49+
50+
let animation: CABasicAnimation
51+
if let viewAnimation = C4ViewAnimation.stack.last as? C4ViewAnimation where viewAnimation.spring != nil {
52+
animation = CASpringAnimation(keyPath: key)
53+
} else {
54+
animation = CABasicAnimation(keyPath: key)
55+
}
56+
57+
animation.configureOptions()
58+
animation.fromValue = valueForKey(key)
59+
60+
if key == C4Layer.rotationKey {
61+
if let layer = presentationLayer() as? C4ShapeLayer {
62+
animation.fromValue = layer.valueForKey(key)
63+
}
64+
}
65+
66+
return animation
67+
}
68+
69+
private var _rotation = 0.0
70+
71+
/// The value of the receiver's current rotation state.
72+
/// This value is cumulative, and can represent values beyong +/- π
73+
public dynamic var rotation: Double {
74+
return _rotation
75+
}
76+
77+
/// Initializes a new C4Layer
78+
public override init() {
79+
super.init()
80+
}
81+
82+
/// Initializes a new C4Layer from a specified layer of any other type.
83+
/// - parameter layer: Another CALayer
84+
public override init(layer: AnyObject) {
85+
super.init(layer: layer)
86+
if let layer = layer as? C4PlayerLayer {
87+
_rotation = layer._rotation
88+
}
89+
}
90+
91+
/// Initializes a new C4Layer from data in a given unarchiver.
92+
/// - parameter coder: An unarchiver object.
93+
public required init?(coder: NSCoder) {
94+
super.init(coder: coder)
95+
}
96+
97+
/// Sets a value for a given key.
98+
/// - parameter value: The value for the property identified by key.
99+
/// - parameter key: The name of one of the receiver's properties
100+
public override func setValue(value: AnyObject?, forKey key: String) {
101+
super.setValue(value, forKey: key)
102+
if key == C4Layer.rotationKey {
103+
_rotation = value as? Double ?? 0.0
104+
}
105+
}
106+
107+
/// Returns a Boolean indicating whether changes to the specified key require the layer to be redisplayed.
108+
/// - parameter key: A string that specifies an attribute of the layer.
109+
/// - returns: A Boolean indicating whether changes to the specified key require the layer to be redisplayed.
110+
public override class func needsDisplayForKey(key: String) -> Bool {
111+
if key == C4Layer.rotationKey {
112+
return true
113+
}
114+
return super.needsDisplayForKey(key)
115+
}
116+
117+
/// Reloads the content of this layer.
118+
/// Do not call this method directly.
119+
public override func display() {
120+
guard let presentation = presentationLayer() as? C4PlayerLayer else {
121+
return
122+
}
123+
setValue(presentation._rotation, forKeyPath: "transform.rotation.z")
124+
}
125+
}

Diff for: C4/UI/C4Shape.swift

+14
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,20 @@ public class C4Shape: C4View {
207207
}
208208
}
209209

210+
/// The current rotation value of the view. Animatable.
211+
/// - returns: A Double value representing the cumulative rotation of the view, measured in Radians.
212+
public override var rotation: Double {
213+
get {
214+
if let number = shapeLayer.valueForKeyPath(C4Layer.rotationKey) as? NSNumber {
215+
return number.doubleValue
216+
}
217+
return 0.0
218+
}
219+
set {
220+
shapeLayer.setValue(newValue, forKeyPath: C4Layer.rotationKey)
221+
}
222+
}
223+
210224
/// This value defines the start of the path used to draw the stroked outline. The value must be in the range [0,1]
211225
/// with zero representing the start of the path and one the end. Values in between zero and one are interpolated
212226
/// linearly along the path length. Defaults to zero. Animatable.

Diff for: C4/UI/C4ShapeLayer.swift

+63
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,71 @@ public class C4ShapeLayer: CAShapeLayer {
5656
animation.configureOptions()
5757
animation.fromValue = valueForKey(key)
5858

59+
if key == C4Layer.rotationKey {
60+
if let layer = presentationLayer() as? C4ShapeLayer {
61+
animation.fromValue = layer.valueForKey(key)
62+
}
63+
}
64+
5965
return animation
6066
}
67+
68+
private var _rotation = 0.0
69+
70+
/// The value of the receiver's current rotation state.
71+
/// This value is cumulative, and can represent values beyong +/- π
72+
public dynamic var rotation: Double {
73+
return _rotation
74+
}
75+
76+
/// Initializes a new C4Layer
77+
public override init() {
78+
super.init()
79+
}
80+
81+
/// Initializes a new C4Layer from a specified layer of any other type.
82+
/// - parameter layer: Another CALayer
83+
public override init(layer: AnyObject) {
84+
super.init(layer: layer)
85+
if let layer = layer as? C4ShapeLayer {
86+
_rotation = layer._rotation
87+
}
88+
}
89+
90+
/// Initializes a new C4Layer from data in a given unarchiver.
91+
/// - parameter coder: An unarchiver object.
92+
public required init?(coder: NSCoder) {
93+
super.init(coder: coder)
94+
}
95+
96+
/// Sets a value for a given key.
97+
/// - parameter value: The value for the property identified by key.
98+
/// - parameter key: The name of one of the receiver's properties
99+
public override func setValue(value: AnyObject?, forKey key: String) {
100+
super.setValue(value, forKey: key)
101+
if key == C4Layer.rotationKey {
102+
_rotation = value as? Double ?? 0.0
103+
}
104+
}
105+
106+
/// Returns a Boolean indicating whether changes to the specified key require the layer to be redisplayed.
107+
/// - parameter key: A string that specifies an attribute of the layer.
108+
/// - returns: A Boolean indicating whether changes to the specified key require the layer to be redisplayed.
109+
public override class func needsDisplayForKey(key: String) -> Bool {
110+
if key == C4Layer.rotationKey {
111+
return true
112+
}
113+
return super.needsDisplayForKey(key)
114+
}
115+
116+
/// Reloads the content of this layer.
117+
/// Do not call this method directly.
118+
public override func display() {
119+
guard let presentation = presentationLayer() as? C4ShapeLayer else {
120+
return
121+
}
122+
setValue(presentation._rotation, forKeyPath: "transform.rotation.z")
123+
}
61124
}
62125

63126
extension CABasicAnimation {

Diff for: C4App/Base.lproj/Main.storyboard

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10089" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
33
<dependencies>
4-
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
4+
<deployment identifier="iOS"/>
5+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10072.1"/>
56
</dependencies>
67
<scenes>
78
<!--View Controller-->
89
<scene sceneID="tne-QT-ifu">
910
<objects>
10-
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
11+
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="C4App" customModuleProvider="target" sceneMemberID="viewController">
1112
<layoutGuides>
1213
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
1314
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>

Diff for: C4App/C4Loop.aif

1.62 MB
Binary file not shown.

0 commit comments

Comments
 (0)