Skip to content

Rotation shape image movie #611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 31, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions C4/UI/C4Image.swift
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,21 @@ public class C4Image: C4View, NSCopying {
}
}

/// The current rotation value of the view. Animatable.
/// - returns: A Double value representing the cumulative rotation of the view, measured in Radians.
public override var rotation: Double {
get {
if let number = imageLayer.valueForKeyPath(C4Layer.rotationKey) as? NSNumber {
return number.doubleValue
}
return 0.0
}
set {
imageLayer.setValue(newValue, forKeyPath: C4Layer.rotationKey)
}
}


/// The scale factor of the image. (read-only)
var scale: Double {
return Double(uiimage.scale)
Expand Down
69 changes: 67 additions & 2 deletions C4/UI/C4ImageLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public class C4ImageLayer: CALayer {
return nil
}

if key != "contents" {
let animatableProperties = ["contents", "rotation"]
if !animatableProperties.contains(key) {
return super.actionForKey(key)
}

Expand All @@ -43,8 +44,72 @@ public class C4ImageLayer: CALayer {
}

animation.configureOptions()
animation.fromValue = self.contents
animation.fromValue = valueForKey(key)

if key == C4Layer.rotationKey {
if let layer = presentationLayer() as? C4ShapeLayer {
animation.fromValue = layer.valueForKey(key)
}
}

return animation
}


private var _rotation = 0.0

/// The value of the receiver's current rotation state.
/// This value is cumulative, and can represent values beyong +/- π
public dynamic var rotation: Double {
return _rotation
}

/// Initializes a new C4Layer
public override init() {
super.init()
}

/// Initializes a new C4Layer from a specified layer of any other type.
/// - parameter layer: Another CALayer
public override init(layer: AnyObject) {
super.init(layer: layer)
if let layer = layer as? C4ImageLayer {
_rotation = layer._rotation
}
}

/// Initializes a new C4Layer from data in a given unarchiver.
/// - parameter coder: An unarchiver object.
public required init?(coder: NSCoder) {
super.init(coder: coder)
}

/// Sets a value for a given key.
/// - parameter value: The value for the property identified by key.
/// - parameter key: The name of one of the receiver's properties
public override func setValue(value: AnyObject?, forKey key: String) {
super.setValue(value, forKey: key)
if key == C4Layer.rotationKey {
_rotation = value as? Double ?? 0.0
}
}

/// Returns a Boolean indicating whether changes to the specified key require the layer to be redisplayed.
/// - parameter key: A string that specifies an attribute of the layer.
/// - returns: A Boolean indicating whether changes to the specified key require the layer to be redisplayed.
public override class func needsDisplayForKey(key: String) -> Bool {
if key == C4Layer.rotationKey {
return true
}
return super.needsDisplayForKey(key)
}

/// Reloads the content of this layer.
/// Do not call this method directly.
public override func display() {
guard let presentation = presentationLayer() as? C4ImageLayer else {
return
}
setValue(presentation._rotation, forKeyPath: "transform.rotation.z")
}
}
22 changes: 18 additions & 4 deletions C4/UI/C4Movie.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public class C4Movie: C4View {
}
}

var movieLayer: AVPlayerLayer {
var movieLayer: C4PlayerLayer {
get {
return self.movieView.movieLayer
}
Expand All @@ -98,12 +98,26 @@ public class C4Movie: C4View {
}

class MovieView: UIView {
var movieLayer: AVPlayerLayer {
return self.layer as! AVPlayerLayer // swiftlint:disable:this force_cast
var movieLayer: C4PlayerLayer {
return self.layer as! C4PlayerLayer // swiftlint:disable:this force_cast
}

override class func layerClass() -> AnyClass {
return AVPlayerLayer.self
return C4PlayerLayer.self
}
}

/// The current rotation value of the view. Animatable.
/// - returns: A Double value representing the cumulative rotation of the view, measured in Radians.
public override var rotation: Double {
get {
if let number = movieLayer.valueForKeyPath(C4Layer.rotationKey) as? NSNumber {
return number.doubleValue
}
return 0.0
}
set {
movieLayer.setValue(newValue, forKeyPath: C4Layer.rotationKey)
}
}

Expand Down
125 changes: 125 additions & 0 deletions C4/UI/C4PlayerLayer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright © 2015 C4
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: The above copyright
// notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

import QuartzCore
import AVFoundation

/// Extension for CAShapeLayer that allows overriding the actions for specific properties.
public class C4PlayerLayer: AVPlayerLayer {
/// A boolean value that, when true, prevents the animation of a shape's properties.
///
/// ````
/// C4ShapeLayer.disableActions = true
/// circle.fillColor = red
/// C4ShapeLayer.disableActions = false
///
/// This value can be set globally, after which changes to any shape's properties will be immediate.
public static var disableActions = true

/// 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.
///
/// - parameter key: The identifier of the action.
///
/// - returns: the action object assigned to the specified key.
public override func actionForKey(key: String) -> CAAction? {
if C4ShapeLayer.disableActions == true {
return nil
}

let animatableProperties = [C4Layer.rotationKey]
if !animatableProperties.contains(key) {
return super.actionForKey(key)
}

let animation: CABasicAnimation
if let viewAnimation = C4ViewAnimation.stack.last as? C4ViewAnimation where viewAnimation.spring != nil {
animation = CASpringAnimation(keyPath: key)
} else {
animation = CABasicAnimation(keyPath: key)
}

animation.configureOptions()
animation.fromValue = valueForKey(key)

if key == C4Layer.rotationKey {
if let layer = presentationLayer() as? C4ShapeLayer {
animation.fromValue = layer.valueForKey(key)
}
}

return animation
}

private var _rotation = 0.0

/// The value of the receiver's current rotation state.
/// This value is cumulative, and can represent values beyong +/- π
public dynamic var rotation: Double {
return _rotation
}

/// Initializes a new C4Layer
public override init() {
super.init()
}

/// Initializes a new C4Layer from a specified layer of any other type.
/// - parameter layer: Another CALayer
public override init(layer: AnyObject) {
super.init(layer: layer)
if let layer = layer as? C4PlayerLayer {
_rotation = layer._rotation
}
}

/// Initializes a new C4Layer from data in a given unarchiver.
/// - parameter coder: An unarchiver object.
public required init?(coder: NSCoder) {
super.init(coder: coder)
}

/// Sets a value for a given key.
/// - parameter value: The value for the property identified by key.
/// - parameter key: The name of one of the receiver's properties
public override func setValue(value: AnyObject?, forKey key: String) {
super.setValue(value, forKey: key)
if key == C4Layer.rotationKey {
_rotation = value as? Double ?? 0.0
}
}

/// Returns a Boolean indicating whether changes to the specified key require the layer to be redisplayed.
/// - parameter key: A string that specifies an attribute of the layer.
/// - returns: A Boolean indicating whether changes to the specified key require the layer to be redisplayed.
public override class func needsDisplayForKey(key: String) -> Bool {
if key == C4Layer.rotationKey {
return true
}
return super.needsDisplayForKey(key)
}

/// Reloads the content of this layer.
/// Do not call this method directly.
public override func display() {
guard let presentation = presentationLayer() as? C4PlayerLayer else {
return
}
setValue(presentation._rotation, forKeyPath: "transform.rotation.z")
}
}
14 changes: 14 additions & 0 deletions C4/UI/C4Shape.swift
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,20 @@ public class C4Shape: C4View {
}
}

/// The current rotation value of the view. Animatable.
/// - returns: A Double value representing the cumulative rotation of the view, measured in Radians.
public override var rotation: Double {
get {
if let number = shapeLayer.valueForKeyPath(C4Layer.rotationKey) as? NSNumber {
return number.doubleValue
}
return 0.0
}
set {
shapeLayer.setValue(newValue, forKeyPath: C4Layer.rotationKey)
}
}

/// This value defines the start of the path used to draw the stroked outline. The value must be in the range [0,1]
/// with zero representing the start of the path and one the end. Values in between zero and one are interpolated
/// linearly along the path length. Defaults to zero. Animatable.
Expand Down
63 changes: 63 additions & 0 deletions C4/UI/C4ShapeLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,71 @@ public class C4ShapeLayer: CAShapeLayer {
animation.configureOptions()
animation.fromValue = valueForKey(key)

if key == C4Layer.rotationKey {
if let layer = presentationLayer() as? C4ShapeLayer {
animation.fromValue = layer.valueForKey(key)
}
}

return animation
}

private var _rotation = 0.0

/// The value of the receiver's current rotation state.
/// This value is cumulative, and can represent values beyong +/- π
public dynamic var rotation: Double {
return _rotation
}

/// Initializes a new C4Layer
public override init() {
super.init()
}

/// Initializes a new C4Layer from a specified layer of any other type.
/// - parameter layer: Another CALayer
public override init(layer: AnyObject) {
super.init(layer: layer)
if let layer = layer as? C4ShapeLayer {
_rotation = layer._rotation
}
}

/// Initializes a new C4Layer from data in a given unarchiver.
/// - parameter coder: An unarchiver object.
public required init?(coder: NSCoder) {
super.init(coder: coder)
}

/// Sets a value for a given key.
/// - parameter value: The value for the property identified by key.
/// - parameter key: The name of one of the receiver's properties
public override func setValue(value: AnyObject?, forKey key: String) {
super.setValue(value, forKey: key)
if key == C4Layer.rotationKey {
_rotation = value as? Double ?? 0.0
}
}

/// Returns a Boolean indicating whether changes to the specified key require the layer to be redisplayed.
/// - parameter key: A string that specifies an attribute of the layer.
/// - returns: A Boolean indicating whether changes to the specified key require the layer to be redisplayed.
public override class func needsDisplayForKey(key: String) -> Bool {
if key == C4Layer.rotationKey {
return true
}
return super.needsDisplayForKey(key)
}

/// Reloads the content of this layer.
/// Do not call this method directly.
public override func display() {
guard let presentation = presentationLayer() as? C4ShapeLayer else {
return
}
setValue(presentation._rotation, forKeyPath: "transform.rotation.z")
}
}

extension CABasicAnimation {
Expand Down
7 changes: 4 additions & 3 deletions C4App/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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">
<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">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10072.1"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="C4App" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
Expand Down
Binary file added C4App/C4Loop.aif
Binary file not shown.
Loading