├── .gitignore ├── Examples └── TweenApp │ ├── Podfile │ ├── Podfile.lock │ ├── Pods │ ├── Local Podspecs │ │ └── Ubergang.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ │ └── project.pbxproj │ ├── Target Support Files │ │ ├── Pods-TweenApp │ │ │ ├── Info.plist │ │ │ ├── Pods-TweenApp-Info.plist │ │ │ ├── Pods-TweenApp-acknowledgements.markdown │ │ │ ├── Pods-TweenApp-acknowledgements.plist │ │ │ ├── Pods-TweenApp-dummy.m │ │ │ ├── Pods-TweenApp-frameworks.sh │ │ │ ├── Pods-TweenApp-resources.sh │ │ │ ├── Pods-TweenApp-umbrella.h │ │ │ ├── Pods-TweenApp.debug.xcconfig │ │ │ ├── Pods-TweenApp.modulemap │ │ │ └── Pods-TweenApp.release.xcconfig │ │ └── Ubergang │ │ │ ├── Info.plist │ │ │ ├── Ubergang-Info.plist │ │ │ ├── Ubergang-dummy.m │ │ │ ├── Ubergang-prefix.pch │ │ │ ├── Ubergang-umbrella.h │ │ │ ├── Ubergang.modulemap │ │ │ └── Ubergang.xcconfig │ └── Ubergang │ │ ├── LICENSE │ │ ├── README.md │ │ └── Ubergang │ │ ├── Core │ │ ├── Engine.swift │ │ ├── Timer.swift │ │ └── UTweenSetup.swift │ │ ├── Data │ │ ├── TweenDirection.swift │ │ ├── TweenMemoryReference.swift │ │ └── TweenOptions.swift │ │ ├── Ease │ │ ├── Back.swift │ │ ├── Bounce.swift │ │ ├── Circ.swift │ │ ├── Cubic.swift │ │ ├── Ease.swift │ │ ├── Elastic.swift │ │ ├── Expo.swift │ │ ├── Linear.swift │ │ ├── Quad.swift │ │ ├── Quart.swift │ │ ├── Quint.swift │ │ └── Sine.swift │ │ ├── Extension │ │ ├── CGPath.swift │ │ ├── CGPointExtension.h │ │ ├── CGPointExtension.m │ │ ├── UIBezierPath+Interpolation.h │ │ └── UIBezierPath+Interpolation.m │ │ ├── Protocols │ │ ├── Numeric.swift │ │ ├── Tweenable.swift │ │ ├── TypeTweenable.swift │ │ ├── UTweenLoggable.swift │ │ └── WeaklyLoopable.swift │ │ ├── Tween │ │ ├── BezierPathTween.swift │ │ ├── CGPointTween.swift │ │ ├── ColorTween.swift │ │ ├── NumericTween.swift │ │ ├── TransformTween.swift │ │ ├── UTimeline.swift │ │ ├── UTween.h │ │ ├── UTween.swift │ │ └── UTweenBase.swift │ │ ├── UTweenBuilder.swift │ │ └── Util │ │ ├── Bezier.swift │ │ └── Math.swift │ ├── TweenApp.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── TweenApp.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings │ └── TweenApp │ ├── AdditiveAnimationViewController.swift │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-40.png │ │ ├── Icon-40@2x.png │ │ ├── Icon-40@3x.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-72.png │ │ ├── Icon-72@2x.png │ │ ├── Icon-76.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-83.5@2x.png │ │ ├── Icon-Small-50.png │ │ ├── Icon-Small-50@2x.png │ │ ├── Icon-Small.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Icon.png │ │ └── Icon@2x.png │ ├── CircleBG.imageset │ │ ├── Contents.json │ │ └── circleBG.png │ ├── CircleOutline.imageset │ │ ├── CircleOutline.png │ │ └── Contents.json │ ├── Contents.json │ ├── Dot.imageset │ │ ├── Contents.json │ │ └── dot.png │ ├── PauseIcon.imageset │ │ ├── Contents.json │ │ └── PauseIcon.png │ ├── PlayIcon.imageset │ │ ├── Contents.json │ │ └── PlayIcon.png │ ├── ReverseIcon.imageset │ │ ├── Contents.json │ │ └── ReverseIcon.png │ ├── SliderThumb.imageset │ │ ├── Contents.json │ │ └── SliderThumb.png │ └── StopIcon.imageset │ │ ├── Contents.json │ │ └── StopIcon.png │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── BezierPathViewController.swift │ ├── ColorViewController.swift │ ├── ConstraintViewController.swift │ ├── CurveThroughViewController.swift │ ├── DynamicViewController.swift │ ├── ExampleViewController.swift │ ├── Info.plist │ ├── InsertTimelineViewController.swift │ ├── MainTableViewController.swift │ ├── NumericViewController.swift │ ├── ParticleViewController.swift │ ├── ProgressViewController.swift │ ├── TimelinesViewController.swift │ ├── TransformViewController.swift │ ├── Ubergang-Bridging-Header.h │ └── Views │ ├── CircularProgressBar.swift │ ├── ReverseButton.swift │ ├── TitleIconTableViewCell.swift │ ├── TweenControlButton.swift │ ├── TweenControls.xib │ ├── TweenControlsView.swift │ └── TweenStatusView.swift ├── Framework └── Ubergang.framework │ ├── Headers │ └── Ubergang-Swift.h │ ├── Info.plist │ ├── Modules │ ├── Ubergang.swiftmodule │ │ ├── x86_64.swiftdoc │ │ └── x86_64.swiftmodule │ └── module.modulemap │ └── Ubergang ├── LICENSE ├── Movies ├── exampleConstraints.gif ├── exampleConstraints.mov ├── exampleDynamic.mov ├── examplePath.gif ├── examplePath.mov ├── exampleTimeline.gif └── exampleTimeline.mov ├── README.md ├── Ubergang-Bridging-Header.h ├── Ubergang.png ├── Ubergang.podspec ├── Ubergang.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Ubergang.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── WorkspaceSettings.xcsettings └── Ubergang ├── Core ├── Engine.swift ├── Timer.swift └── UTweenSetup.swift ├── Data ├── TweenDirection.swift ├── TweenMemoryReference.swift └── TweenOptions.swift ├── Ease ├── Back.swift ├── Bounce.swift ├── Circ.swift ├── Cubic.swift ├── Ease.swift ├── Elastic.swift ├── Expo.swift ├── Linear.swift ├── Quad.swift ├── Quart.swift ├── Quint.swift └── Sine.swift ├── Extension ├── CGPath.swift ├── CGPointExtension.h ├── CGPointExtension.m ├── UIBezierPath+Interpolation.h └── UIBezierPath+Interpolation.m ├── Info.plist ├── Protocols ├── Numeric.swift ├── Tweenable.swift ├── TypeTweenable.swift ├── UTweenLoggable.swift └── WeaklyLoopable.swift ├── Tween ├── BezierPathTween.swift ├── CGPointTween.swift ├── ColorTween.swift ├── NumericTween.swift ├── TransformTween.swift ├── UTimeline.swift ├── UTween.h ├── UTween.swift └── UTweenBase.swift ├── UTweenBuilder.swift └── Util ├── Bezier.swift └── Math.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/screenshots 64 | Output 65 | -------------------------------------------------------------------------------- /Examples/TweenApp/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '8.2' 3 | # Uncomment this line if you're using Swift 4 | use_frameworks! 5 | 6 | #pod 'Ubergang' 7 | pod 'Ubergang', :path => '~/Workspace/mobile/Ubergang' 8 | 9 | target 'TweenApp' do 10 | 11 | end 12 | -------------------------------------------------------------------------------- /Examples/TweenApp/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Ubergang (1.2.0) 3 | 4 | DEPENDENCIES: 5 | - Ubergang (from `~/Workspace/mobile/Ubergang`) 6 | 7 | EXTERNAL SOURCES: 8 | Ubergang: 9 | :path: "~/Workspace/mobile/Ubergang" 10 | 11 | SPEC CHECKSUMS: 12 | Ubergang: b5db74966f6fabcab09c4fbc207d316aa9469b06 13 | 14 | PODFILE CHECKSUM: f0dbfb25a7fe3142bfc0573ae587a9b44a3f0491 15 | 16 | COCOAPODS: 1.7.2 17 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Local Podspecs/Ubergang.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Ubergang", 3 | "version": "1.2.0", 4 | "summary": "A tweening engine written in Swift.", 5 | "homepage": "https://github.com/RobinFalko/Ubergang", 6 | "license": { 7 | "type": "Apache", 8 | "file": "LICENSE" 9 | }, 10 | "authors": { 11 | "Robin Frielingsdorf": "mail@robinfalko.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/RobinFalko/Ubergang.git", 15 | "tag": "1.2.0" 16 | }, 17 | "source_files": "Ubergang/**/*.{h,m,swift}", 18 | "module_name": "Ubergang", 19 | "swift_versions": "5.0", 20 | "platforms": { 21 | "ios": "8.0" 22 | }, 23 | "swift_version": "5.0" 24 | } 25 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Ubergang (1.2.0) 3 | 4 | DEPENDENCIES: 5 | - Ubergang (from `~/Workspace/mobile/Ubergang`) 6 | 7 | EXTERNAL SOURCES: 8 | Ubergang: 9 | :path: "~/Workspace/mobile/Ubergang" 10 | 11 | SPEC CHECKSUMS: 12 | Ubergang: b5db74966f6fabcab09c4fbc207d316aa9469b06 13 | 14 | PODFILE CHECKSUM: f0dbfb25a7fe3142bfc0573ae587a9b44a3f0491 15 | 16 | COCOAPODS: 1.7.2 17 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Pods-TweenApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Pods-TweenApp/Pods-TweenApp-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Pods-TweenApp/Pods-TweenApp-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_TweenApp : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_TweenApp 5 | @end 6 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Pods-TweenApp/Pods-TweenApp-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_TweenAppVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_TweenAppVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Pods-TweenApp/Pods-TweenApp.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Ubergang" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Ubergang/Ubergang.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "Ubergang" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Pods-TweenApp/Pods-TweenApp.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_TweenApp { 2 | umbrella header "Pods-TweenApp-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Pods-TweenApp/Pods-TweenApp.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Ubergang" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Ubergang/Ubergang.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "Ubergang" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Ubergang/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Ubergang/Ubergang-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Ubergang/Ubergang-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Ubergang : NSObject 3 | @end 4 | @implementation PodsDummy_Ubergang 5 | @end 6 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Ubergang/Ubergang-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Ubergang/Ubergang-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "CGPointExtension.h" 14 | #import "UIBezierPath+Interpolation.h" 15 | #import "UTween.h" 16 | 17 | FOUNDATION_EXPORT double UbergangVersionNumber; 18 | FOUNDATION_EXPORT const unsigned char UbergangVersionString[]; 19 | 20 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Ubergang/Ubergang.modulemap: -------------------------------------------------------------------------------- 1 | framework module Ubergang { 2 | umbrella header "Ubergang-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Target Support Files/Ubergang/Ubergang.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Ubergang 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Core/Engine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Engine.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 09/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class Engine: NSObject { 13 | public typealias Closure = () -> Void 14 | 15 | fileprivate var displayLink: CADisplayLink? 16 | 17 | var closures = [String : Closure]() 18 | 19 | var mapTable = NSMapTable(keyOptions: NSPointerFunctions.Options.strongMemory, valueOptions: NSPointerFunctions.Options.weakMemory) 20 | 21 | open static var instance: Engine = { 22 | let engine = Engine() 23 | engine.start() 24 | return engine 25 | }() 26 | 27 | func start() { 28 | if displayLink == nil { 29 | displayLink = CADisplayLink(target: self, selector: #selector(Engine.update)) 30 | displayLink!.add(to: RunLoop.current, forMode: RunLoopMode.commonModes) 31 | } 32 | } 33 | 34 | func stop() { 35 | displayLink?.remove(from: RunLoop.current, forMode: RunLoopMode.commonModes) 36 | displayLink = nil 37 | } 38 | 39 | @objc func update() { 40 | let enumerator = mapTable.objectEnumerator() 41 | while let any: AnyObject = enumerator?.nextObject() as AnyObject! { 42 | if let loopable = any as? WeaklyLoopable { 43 | loopable.loopWeakly() 44 | } 45 | } 46 | 47 | for (_, closure) in closures { 48 | closure() 49 | } 50 | } 51 | 52 | 53 | func register(_ closure: @escaping Closure, forKey key: String) { 54 | closures[key] = closure 55 | 56 | start() 57 | } 58 | 59 | 60 | func register(_ loopable: WeaklyLoopable, forKey key: String) { 61 | mapTable.setObject(loopable as AnyObject?, forKey: key as AnyObject?) 62 | 63 | start() 64 | } 65 | 66 | 67 | func unregister(_ key: String) { 68 | mapTable.removeObject(forKey: key as AnyObject?) 69 | 70 | closures.removeValue(forKey: key) 71 | 72 | if mapTable.count == 0 && closures.isEmpty { 73 | stop() 74 | } 75 | } 76 | 77 | 78 | func contains(_ key: String) -> Bool { 79 | return mapTable.object(forKey: key as AnyObject?) != nil || closures[key] != nil 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Core/Timer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Timer.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Timer { 12 | open static let instance = Timer() 13 | 14 | fileprivate let id = "\(#file)_update" 15 | 16 | open static var delta:TimeInterval = TimeInterval(0) 17 | open static var time:TimeInterval = TimeInterval(0) 18 | fileprivate var lastUpdateTime:TimeInterval = TimeInterval(0) 19 | 20 | fileprivate init() {} 21 | 22 | func start() { 23 | self.lastUpdateTime = Date().timeIntervalSince1970 24 | 25 | Engine.instance.register(update, forKey: id) 26 | } 27 | 28 | 29 | func stop() { 30 | Engine.instance.unregister(id) 31 | } 32 | 33 | 34 | func update() { 35 | tick(Date().timeIntervalSince1970) 36 | } 37 | 38 | 39 | func tick(_ currentTime: TimeInterval) { 40 | if lastUpdateTime == 0.0 { 41 | Timer.delta = 0 42 | } else { 43 | Timer.delta = currentTime - self.lastUpdateTime 44 | } 45 | 46 | self.lastUpdateTime = Date().timeIntervalSince1970 47 | 48 | Timer.time += Timer.delta 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Core/UTweenSetup.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTweenSetup.swift 3 | // Ubergang 4 | // 5 | // Created by RF on 11/07/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class UTweenSetup { 12 | open static let instance = UTweenSetup() 13 | 14 | fileprivate var isLoggingEnabled = false 15 | 16 | internal lazy var logger: UTweenLoggable? = { 17 | guard UTweenSetup.instance.isLoggingEnabled else { return nil } 18 | return UTweenLogger() 19 | }() 20 | 21 | fileprivate init() {} 22 | 23 | open func enableLogging(_ enabled: Bool) { 24 | isLoggingEnabled = enabled 25 | } 26 | 27 | open func enableLogging(_ enabled: Bool, withLogger logger: UTweenLoggable) { 28 | enableLogging(enabled) 29 | self.logger = logger 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Data/TweenDirection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TweenDirection.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 10/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public enum TweenDirection { 10 | case forward, reverse 11 | } 12 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Data/TweenMemoryReference.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TweenMemoryReference.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/02/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public enum TweenMemoryReference { 10 | case weak, strong 11 | } 12 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Data/TweenOptions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TweenOptions.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 20/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public func ==(a: TweenOptions, b: TweenOptions) -> Bool { 10 | switch (a, b) { 11 | case (.yoyo, .yoyo): return true 12 | case (.repeat(let l), .repeat(let r)) where l == r: return true 13 | default: return false 14 | } 15 | } 16 | 17 | internal extension Sequence where Iterator.Element == TweenOptions { 18 | func repeatCount() -> Int { 19 | var repeatCount = 0 20 | self.forEach { 21 | if case .repeat(let count) = $0 { 22 | repeatCount = count 23 | } 24 | } 25 | 26 | return repeatCount 27 | } 28 | 29 | func containsRepeat() -> Bool { 30 | return repeatCount() > 0 31 | } 32 | 33 | func containsYoyo() -> Bool { 34 | return self.contains(.yoyo) 35 | } 36 | } 37 | 38 | public enum TweenOptions: Equatable { 39 | case yoyo 40 | case `repeat`(Int) 41 | } 42 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Back.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Back.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Back: Ease { 12 | /** 13 | Back ease in. 14 | 15 | - Parameter t: The value to be mapped going from 0 to `d` 16 | - Parameter b: The mapped start value 17 | - Parameter c: The mapped end value 18 | - Parameter d: The end value 19 | - Returns: The mapped result 20 | */ 21 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 22 | var t = t 23 | let s = 1.70158 24 | t/=d 25 | let postFix = t 26 | return c*(postFix)*t*((s+1)*t - s) + b 27 | } 28 | 29 | /** 30 | Back ease out. 31 | 32 | - Parameter t: The value to be mapped going from 0 to `d` 33 | - Parameter b: The mapped start value 34 | - Parameter c: The mapped end value 35 | - Parameter d: The end value 36 | - Returns: The mapped result 37 | */ 38 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 39 | var t = t 40 | let s = 1.70158 41 | t=t/d-1 42 | let f = (s+1)*t + s 43 | return c*(t*t*f + 1) + b 44 | } 45 | 46 | /** 47 | Back ease in out. 48 | 49 | - Parameter t: The value to be mapped going from 0 to `d` 50 | - Parameter b: The mapped start value 51 | - Parameter c: The mapped end value 52 | - Parameter d: The end value 53 | - Returns: The mapped result 54 | */ 55 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 56 | var t = t 57 | var s = 1.70158 58 | t/=d/2 59 | if (t < 1) { s*=(1.525); return c/2*(t*t*(((s)+1)*t - s)) + b } 60 | t-=2 61 | let postFix = t 62 | s*=(1.525) 63 | let f = (s+1)*t + s 64 | return c/2*(postFix*t*f + 2) + b 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Bounce.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bounce.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Bounce: Ease { 12 | 13 | /** 14 | Bounce ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | return c - easeOut (t: d-t, b: 0, c: c, d: d) + b 24 | } 25 | 26 | /** 27 | Bounce ease out. 28 | 29 | - Parameter t: The value to be mapped going from 0 to `d` 30 | - Parameter b: The mapped start value 31 | - Parameter c: The mapped end value 32 | - Parameter d: The end value 33 | - Returns: The mapped result 34 | */ 35 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 36 | var t = t 37 | t/=d 38 | if t < (1/2.75) { 39 | return c*(7.5625*t*t) + b 40 | } else if (t < (2/2.75)) { 41 | t-=(1.5/2.75) 42 | let postFix = t 43 | return c*(7.5625*(postFix)*t + 0.75) + b 44 | } else if (t < (2.5/2.75)) { 45 | t-=(2.25/2.75) 46 | let postFix = t 47 | return c*(7.5625*(postFix)*t + 0.9375) + b 48 | } else { 49 | t-=(2.625/2.75) 50 | let postFix = t 51 | return c*(7.5625*(postFix)*t + 0.984375) + b 52 | } 53 | } 54 | 55 | /** 56 | Bounce ease in out. 57 | 58 | - Parameter t: The value to be mapped going from 0 to `d` 59 | - Parameter b: The mapped start value 60 | - Parameter c: The mapped end value 61 | - Parameter d: The end value 62 | - Returns: The mapped result 63 | */ 64 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 65 | if (t < d/2) { return easeIn (t: t*2, b: 0, c: c, d: d) * 0.5 + b } 66 | else { return easeOut (t: t*2-d, b: 0, c: c, d: d) * 0.5 + c*0.5 + b } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Circ.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Circ.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Circ: Ease { 12 | 13 | /** 14 | Circ ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t/=d 25 | return -c * (sqrt(1 - (t)*t) - 1) + b 26 | } 27 | 28 | /** 29 | Circ ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t=t/d-1 40 | return c * sqrt(1 - (t)*t) + b 41 | } 42 | 43 | /** 44 | Circ ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t/=d/2 55 | if ((t) < 1) { return -c/2 * (sqrt(1 - t*t) - 1) + b } 56 | t-=2 57 | return c/2 * (sqrt(1 - t*(t)) + 1) + b 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Cubic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Cubic.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Cubic: Ease { 12 | 13 | /** 14 | Cubic ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t = t/d 25 | return c*t*t*t + b 26 | } 27 | 28 | /** 29 | Cubic ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t = t/d-1 40 | return c*(t*t*t + 1) + b 41 | } 42 | 43 | /** 44 | Cubic ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t = t/(d/2) 55 | if t < 1 { 56 | return c/2*t*t*t + b 57 | } 58 | 59 | t = t-2 60 | return c/2*(t*t*t + 2) + b; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Ease.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Ease.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public typealias Easing = (_ t: Double, _ b: Double, _ c: Double, _ d: Double) -> Double 10 | 11 | open class Ease {} 12 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Elastic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Elastic.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 10/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Elastic: Ease { 12 | 13 | /** 14 | Elastic ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | if t == 0 { 25 | return b 26 | } 27 | 28 | t = t / d 29 | if t == 1 { 30 | return b+c 31 | } 32 | 33 | let p = d * 0.3 34 | let a = c 35 | let s = p / 4 36 | t = t - 1 37 | 38 | let postFix = a * pow(2.0, 10.0 * t) // this is a fix, again, with post-increment operators 39 | 40 | return -(postFix * sin((t*d-s) * (2 * .pi)/p )) + b 41 | } 42 | 43 | /** 44 | Elastic ease out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | if t == 0 { 55 | return b 56 | } 57 | 58 | t = t / d 59 | if t == 1 { 60 | return b+c 61 | } 62 | 63 | let p = d * 0.3 64 | let a = c 65 | let s = p / 4 66 | 67 | return (a * pow(2, -10 * t) * sin( (t*d-s) * (2 * .pi)/p ) + c + b) 68 | } 69 | 70 | /** 71 | Elastic ease in out. 72 | 73 | - Parameter t: The value to be mapped going from 0 to `d` 74 | - Parameter b: The mapped start value 75 | - Parameter c: The mapped end value 76 | - Parameter d: The end value 77 | - Returns: The mapped result 78 | */ 79 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 80 | var t = t 81 | if t == 0 { 82 | return b 83 | } 84 | 85 | t = t / (d / 2) 86 | if t == 2 { 87 | return b+c 88 | } 89 | 90 | let p = d * (0.3*1.5) 91 | let a = c 92 | let s = p / 4 93 | 94 | t = t - 1 95 | 96 | if (t < 1) { 97 | let postFix = a * pow(2.0, 10.0 * t) // postIncrement is evil 98 | return -0.5 * (postFix * sin((t*d-s) * (2 * .pi)/p)) + b 99 | } 100 | 101 | let postFix = a * pow(2.0, -10.0 * t) // postIncrement is evil 102 | return postFix * sin((t*d-s) * (2 * .pi) / p) * 0.5 + c + b 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Expo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Expo.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Expo: Ease { 12 | 13 | /** 14 | Expo ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | return (t==0) ? b : c * pow(2, 10 * (t/d - 1)) + b 24 | } 25 | 26 | /** 27 | Circ ease out. 28 | 29 | - Parameter t: The value to be mapped going from 0 to `d` 30 | - Parameter b: The mapped start value 31 | - Parameter c: The mapped end value 32 | - Parameter d: The end value 33 | - Returns: The mapped result 34 | */ 35 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 36 | return (t==d) ? b+c : c * (-pow(2, -10 * t/d) + 1) + b 37 | } 38 | 39 | /** 40 | Circ ease in out. 41 | 42 | - Parameter t: The value to be mapped going from 0 to `d` 43 | - Parameter b: The mapped start value 44 | - Parameter c: The mapped end value 45 | - Parameter d: The end value 46 | - Returns: The mapped result 47 | */ 48 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 49 | var t = t 50 | if (t==0) { return b } 51 | if (t==d) { return b+c } 52 | t/=d/2 53 | if ((t) < 1) { return c/2 * pow(2, 10 * (t - 1)) + b } 54 | t-=1 55 | return c/2 * (-pow(2, -10 * t) + 2) + b 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Linear.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Linear.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Linear: Ease { 12 | 13 | /** 14 | Linear ease. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func ease(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | return c * t / d + b 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Quad.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quad.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Quad: Ease { 12 | 13 | /** 14 | Quad ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t/=d 25 | return c*(t)*t + b 26 | } 27 | 28 | /** 29 | Quad ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t/=d 40 | return -c*(t)*(t-2) + b 41 | } 42 | 43 | /** 44 | Quad ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t/=d/2 55 | if ((t) < 1) { return ((c/2)*(t*t)) + b } 56 | let t2 = t-1 57 | return -c/2 * (((t-2)*(t2)) - 1) + b 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Quart.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quart.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Quart: Ease { 12 | 13 | /** 14 | Quart ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t/=d 25 | return c*(t)*t*t*t + b 26 | } 27 | 28 | /** 29 | Quart ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t=t/d-1 40 | return -c * ((t)*t*t*t - 1) + b 41 | } 42 | 43 | /** 44 | Quart ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t/=d/2 55 | if ((t) < 1) { return c/2*t*t*t*t + b } 56 | t-=2 57 | return -c/2 * ((t)*t*t*t - 2) + b 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Quint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quint.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Quint: Ease { 12 | 13 | /** 14 | Quint ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t/=d 25 | return c*(t)*t*t*t*t + b 26 | } 27 | 28 | /** 29 | Quint ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t=t/d-1 40 | return c*((t)*t*t*t*t + 1) + b 41 | } 42 | 43 | /** 44 | Quint ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t/=d/2 55 | if ((t) < 1) { return c/2*t*t*t*t*t + b } 56 | t-=2 57 | return c/2*((t)*t*t*t*t + 2) + b 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Ease/Sine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sine.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Sine: Ease { 12 | 13 | /** 14 | Sine ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | return -c * cos(t/d * (.pi/2)) + c + b 24 | } 25 | 26 | /** 27 | Sine ease out. 28 | 29 | - Parameter t: The value to be mapped going from 0 to `d` 30 | - Parameter b: The mapped start value 31 | - Parameter c: The mapped end value 32 | - Parameter d: The end value 33 | - Returns: The mapped result 34 | */ 35 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 36 | return c * sin(t/d * (.pi/2)) + b 37 | } 38 | 39 | /** 40 | Sine ease in out. 41 | 42 | - Parameter t: The value to be mapped going from 0 to `d` 43 | - Parameter b: The mapped start value 44 | - Parameter c: The mapped end value 45 | - Parameter d: The end value 46 | - Returns: The mapped result 47 | */ 48 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 49 | return -c/2 * (cos(.pi*t/d) - 1) + b 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Extension/CGPath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPath.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 19/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension CGPath { 12 | func forEach(_ body: @convention(block) (CGPathElement) -> Void) { 13 | typealias Body = @convention(block) (CGPathElement) -> Void 14 | func callback(_ info: UnsafeMutableRawPointer, element: UnsafePointer) { 15 | let body = unsafeBitCast(info, to: Body.self) 16 | body(element.pointee) 17 | } 18 | let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self) 19 | self.apply(info: unsafeBody, function: callback as! CGPathApplierFunction) 20 | } 21 | 22 | func getElements() -> [(type: CGPathElementType, points: [CGPoint])] { 23 | var result = [(type: CGPathElementType, points: [CGPoint])]() 24 | var elementType: CGPathElementType! 25 | var points: [CGPoint]! 26 | var firstPoint: CGPoint! 27 | var previousLastPoint: CGPoint! 28 | forEach { element in 29 | switch (element.type) { 30 | case CGPathElementType.moveToPoint: 31 | firstPoint = element.points[0] 32 | previousLastPoint = firstPoint 33 | case .addLineToPoint: 34 | points = [CGPoint]() 35 | elementType = element.type 36 | points.append(previousLastPoint) 37 | points.append(element.points[0]) 38 | result.append((elementType, points)) 39 | 40 | previousLastPoint = element.points[0] 41 | case .addQuadCurveToPoint: 42 | points = [CGPoint]() 43 | elementType = element.type 44 | points.append(previousLastPoint) 45 | points.append(element.points[0]) 46 | points.append(element.points[1]) 47 | result.append((elementType, points)) 48 | 49 | previousLastPoint = element.points[1] 50 | case .addCurveToPoint: 51 | points = [CGPoint]() 52 | elementType = element.type 53 | points.append(previousLastPoint) 54 | points.append(element.points[0]) 55 | points.append(element.points[1]) 56 | points.append(element.points[2]) 57 | result.append((elementType, points)) 58 | 59 | previousLastPoint = element.points[2] 60 | case .closeSubpath: 61 | points = [CGPoint]() 62 | elementType = element.type 63 | points.append(previousLastPoint) 64 | points.append(firstPoint) 65 | result.append((elementType, points)) 66 | } 67 | } 68 | 69 | return result 70 | } 71 | 72 | func getElement(_ index: Int) -> (type: CGPathElementType, points: [CGPoint])? { 73 | let elements = getElements() 74 | if index >= elements.count { 75 | return nil 76 | } 77 | return elements[index] 78 | } 79 | 80 | func elementCount() -> Int { 81 | var count = 0 82 | self.forEach { element in 83 | if element.type != .moveToPoint && element.type != .closeSubpath { 84 | count += 1 85 | } 86 | } 87 | return count 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Extension/UIBezierPath+Interpolation.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIBezierPath+Interpolation.h 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | // Source: https://github.com/jnfisher/ios-curve-interpolation 9 | 10 | #import 11 | 12 | @interface UIBezierPath (Interpolation) 13 | 14 | // pointsAsNSValues must be NSValue objects containing CGPoints. 15 | // 16 | // ex: 17 | // const char *encoding = @encode(CGPoint); 18 | // NSValue *pointAsValue = [NSValue valueWithBytes:&cgPoint objCType:encoding]; 19 | 20 | // 0.0 <= alpha <= 1.0 21 | +(UIBezierPath *)interpolateCGPointsWithCatmullRom:(NSArray *)pointsAsNSValues closed:(BOOL)closed alpha:(float)alpha; 22 | +(UIBezierPath *)interpolateCGPointsWithHermite:(NSArray *)pointsAsNSValues closed:(BOOL)closed; 23 | @end -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Extension/UIBezierPath+Interpolation.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIBezierPath+Interpolation.m 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | // Source: https://github.com/jnfisher/ios-curve-interpolation 9 | 10 | #import "UIBezierPath+Interpolation.h" 11 | #import "CGPointExtension.h" 12 | 13 | #define kEPSILON 1.0e-5 14 | 15 | @implementation UIBezierPath (Interpolation) 16 | 17 | +(UIBezierPath *)interpolateCGPointsWithCatmullRom:(NSArray *)pointsAsNSValues closed:(BOOL)closed alpha:(float)alpha { 18 | if ([pointsAsNSValues count] < 4) 19 | return nil; 20 | 21 | NSInteger endIndex = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-2); 22 | NSAssert(alpha >= 0.0 && alpha <= 1.0, @"alpha value is between 0.0 and 1.0, inclusive"); 23 | 24 | UIBezierPath *path = [UIBezierPath bezierPath]; 25 | NSInteger startIndex = (closed ? 0 : 1); 26 | for (NSInteger ii=startIndex; ii < endIndex; ++ii) { 27 | CGPoint p0, p1, p2, p3; 28 | NSInteger nextii = (ii+1)%[pointsAsNSValues count]; 29 | NSInteger nextnextii = (nextii+1)%[pointsAsNSValues count]; 30 | NSInteger previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1); 31 | 32 | [pointsAsNSValues[ii] getValue:&p1]; 33 | [pointsAsNSValues[previi] getValue:&p0]; 34 | [pointsAsNSValues[nextii] getValue:&p2]; 35 | [pointsAsNSValues[nextnextii] getValue:&p3]; 36 | 37 | CGFloat d1 = ccpLength(ccpSub(p1, p0)); 38 | CGFloat d2 = ccpLength(ccpSub(p2, p1)); 39 | CGFloat d3 = ccpLength(ccpSub(p3, p2)); 40 | 41 | CGPoint b1, b2; 42 | if (fabs(d1) < kEPSILON) { 43 | b1 = p1; 44 | } 45 | else { 46 | b1 = ccpMult(p2, powf(d1, 2*alpha)); 47 | b1 = ccpSub(b1, ccpMult(p0, powf(d2, 2*alpha))); 48 | b1 = ccpAdd(b1, ccpMult(p1,(2*powf(d1, 2*alpha) + 3*powf(d1, alpha)*powf(d2, alpha) + powf(d2, 2*alpha)))); 49 | b1 = ccpMult(b1, 1.0 / (3*powf(d1, alpha)*(powf(d1, alpha)+powf(d2, alpha)))); 50 | } 51 | 52 | if (fabs(d3) < kEPSILON) { 53 | b2 = p2; 54 | } 55 | else { 56 | b2 = ccpMult(p1, powf(d3, 2*alpha)); 57 | b2 = ccpSub(b2, ccpMult(p3, powf(d2, 2*alpha))); 58 | b2 = ccpAdd(b2, ccpMult(p2,(2*powf(d3, 2*alpha) + 3*powf(d3, alpha)*powf(d2, alpha) + powf(d2, 2*alpha)))); 59 | b2 = ccpMult(b2, 1.0 / (3*powf(d3, alpha)*(powf(d3, alpha)+powf(d2, alpha)))); 60 | } 61 | 62 | if (ii==startIndex) 63 | [path moveToPoint:p1]; 64 | 65 | [path addCurveToPoint:p2 controlPoint1:b1 controlPoint2:b2]; 66 | } 67 | 68 | if (closed) 69 | [path closePath]; 70 | 71 | return path; 72 | } 73 | 74 | +(UIBezierPath *)interpolateCGPointsWithHermite:(NSArray *)pointsAsNSValues closed:(BOOL)closed { 75 | if ([pointsAsNSValues count] < 2) 76 | return nil; 77 | 78 | NSInteger nCurves = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-1); 79 | 80 | UIBezierPath *path = [UIBezierPath bezierPath]; 81 | for (NSInteger ii=0; ii < nCurves; ++ii) { 82 | NSValue *value = pointsAsNSValues[ii]; 83 | 84 | CGPoint curPt, prevPt, nextPt, endPt; 85 | [value getValue:&curPt]; 86 | if (ii==0) 87 | [path moveToPoint:curPt]; 88 | 89 | NSInteger nextii = (ii+1)%[pointsAsNSValues count]; 90 | NSInteger previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1); 91 | 92 | [pointsAsNSValues[previi] getValue:&prevPt]; 93 | [pointsAsNSValues[nextii] getValue:&nextPt]; 94 | endPt = nextPt; 95 | 96 | CGFloat mx, my; 97 | if (closed || ii > 0) { 98 | mx = (nextPt.x - curPt.x)*0.5 + (curPt.x - prevPt.x)*0.5; 99 | my = (nextPt.y - curPt.y)*0.5 + (curPt.y - prevPt.y)*0.5; 100 | } 101 | else { 102 | mx = (nextPt.x - curPt.x)*0.5; 103 | my = (nextPt.y - curPt.y)*0.5; 104 | } 105 | 106 | CGPoint ctrlPt1; 107 | ctrlPt1.x = curPt.x + mx / 3.0; 108 | ctrlPt1.y = curPt.y + my / 3.0; 109 | 110 | [pointsAsNSValues[nextii] getValue:&curPt]; 111 | 112 | nextii = (nextii+1)%[pointsAsNSValues count]; 113 | previi = ii; 114 | 115 | [pointsAsNSValues[previi] getValue:&prevPt]; 116 | [pointsAsNSValues[nextii] getValue:&nextPt]; 117 | 118 | if (closed || ii < nCurves-1) { 119 | mx = (nextPt.x - curPt.x)*0.5 + (curPt.x - prevPt.x)*0.5; 120 | my = (nextPt.y - curPt.y)*0.5 + (curPt.y - prevPt.y)*0.5; 121 | } 122 | else { 123 | mx = (curPt.x - prevPt.x)*0.5; 124 | my = (curPt.y - prevPt.y)*0.5; 125 | } 126 | 127 | CGPoint ctrlPt2; 128 | ctrlPt2.x = curPt.x - mx / 3.0; 129 | ctrlPt2.y = curPt.y - my / 3.0; 130 | 131 | [path addCurveToPoint:endPt controlPoint1:ctrlPt1 controlPoint2:ctrlPt2]; 132 | } 133 | 134 | if (closed) 135 | [path closePath]; 136 | 137 | return path; 138 | } 139 | 140 | 141 | @end -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Protocols/Numeric.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Computable.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol Numeric { 12 | init() 13 | init(_ value: Int) 14 | init(_ value: Double) 15 | init(_ value: Float) 16 | 17 | static func + (lhs: Self, rhs: Self) -> Self 18 | static func - (lhs: Self, rhs: Self) -> Self 19 | static func * (lhs: Self, rhs: Self) -> Self 20 | static func / (lhs: Self, rhs: Self) -> Self 21 | } 22 | 23 | extension Double : Numeric { 24 | public init?(_ value: T) { 25 | switch (value) { 26 | case is Int: 27 | self.init(Double(value as! Int)) 28 | break 29 | case is Int8: 30 | self.init(Double(value as! Int8)) 31 | break 32 | case is Int16: 33 | self.init(Double(value as! Int16)) 34 | break 35 | case is Int32: 36 | self.init(Double(value as! Int32)) 37 | break 38 | case is Int64: 39 | self.init(Double(value as! Int64)) 40 | break 41 | case is Float: 42 | self.init(Double(value as! Float)) 43 | break 44 | case is CGFloat: 45 | self.init(Double(value as! CGFloat)) 46 | break 47 | case is Double: 48 | fallthrough 49 | default: 50 | return nil 51 | } 52 | } 53 | } 54 | extension Float : Numeric {} 55 | extension Int : Numeric {} 56 | extension Int8 : Numeric {} 57 | extension Int16 : Numeric {} 58 | extension Int32 : Numeric {} 59 | extension Int64 : Numeric {} 60 | extension UInt : Numeric {} 61 | extension UInt8 : Numeric {} 62 | extension UInt16 : Numeric {} 63 | extension UInt32 : Numeric {} 64 | extension UInt64 : Numeric {} 65 | extension CGFloat: Numeric {} 66 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Protocols/Tweenable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tweenable.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 05/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public protocol Tweenable { 10 | var id: String { get } 11 | var duration: Double { get set } 12 | var progress: Double { get set } 13 | 14 | func start() -> Self 15 | func stop() 16 | func pause() 17 | func resume() 18 | func kill() 19 | } -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Protocols/TypeTweenable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tween.swift 3 | // Ubergang 4 | // 5 | // Created by RF on 06.08.17. 6 | // Copyright © 2017 Robin Falko. All rights reserved. 7 | // 8 | 9 | // Not sure why this won't work. 10 | // Use repetitive code in extensions instead 11 | //public protocol GenericTweenable { 12 | // associatedtype TweenType: UTween 13 | // func tween(to: Self) -> TweenType 14 | //} 15 | // 16 | //public extension GenericTweenable { 17 | // func tween(to: Self) -> TweenType { 18 | // return TweenType().tween(from: self, to: to) 19 | // } 20 | //} 21 | //extension CGPoint: GenericTweenable {typealias TweenType = CGPointTween} 22 | //extension UIColor: GenericTweenable {typealias TweenType = ColorTween} 23 | //extension CGAffineTransform: Generic     Tweenable {typealias TweenType = TransformTween} 24 | 25 | public extension CGPoint { 26 | func tween(to: CGPoint) -> CGPointTween { 27 | return CGPointTween().from(self, to: to) 28 | } 29 | } 30 | 31 | public extension UIColor { 32 | func tween(to: UIColor) -> ColorTween { 33 | return ColorTween().from(self, to: to) 34 | } 35 | } 36 | 37 | public extension CGAffineTransform { 38 | func tween(to: CGAffineTransform) -> TransformTween { 39 | return TransformTween().from(self, to: to) 40 | } 41 | } 42 | 43 | public protocol NumericTweenable: Numeric { 44 | func tween(to: Self) -> NumericTween 45 | } 46 | 47 | public extension NumericTweenable { 48 | func tween(to: Self) -> NumericTween { 49 | return NumericTween().from(self, to: to) 50 | } 51 | } 52 | 53 | extension Double : NumericTweenable {} 54 | extension Float : NumericTweenable {} 55 | extension Int : NumericTweenable {} 56 | extension Int8 : NumericTweenable {} 57 | extension Int16 : NumericTweenable {} 58 | extension Int32 : NumericTweenable {} 59 | extension Int64 : NumericTweenable {} 60 | extension UInt : NumericTweenable {} 61 | extension UInt8 : NumericTweenable {} 62 | extension UInt16 : NumericTweenable {} 63 | extension UInt32 : NumericTweenable {} 64 | extension UInt64 : NumericTweenable {} 65 | extension CGFloat: NumericTweenable {} 66 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Protocols/UTweenLoggable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTweenLoggable.swift 3 | // Ubergang 4 | // 5 | // Created by RF on 18/07/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public protocol UTweenLoggable { 10 | func verbose(_ msg: String, function: String, file: String, line: Int) 11 | func debug(_ msg: String, function: String, file: String, line: Int) 12 | func info(_ msg: String, function: String, file: String, line: Int) 13 | func warning(_ msg: String, function: String, file: String, line: Int) 14 | func error(_ msg: String, function: String, file: String, line: Int) 15 | } 16 | 17 | 18 | extension UTweenLoggable { 19 | func verbose(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 20 | print("[\(file) - \(function)->\(line)]:\(msg)") 21 | } 22 | 23 | func debug(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 24 | print("[\(file) - \(function)->\(line)]:\(msg)") 25 | } 26 | 27 | func info(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 28 | print("[\(file) - \(function)->\(line)]:\(msg)") 29 | } 30 | 31 | func warning(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 32 | print("[\(file) - \(function)->\(line)]:\(msg)") 33 | } 34 | 35 | func error(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 36 | print("[\(file) - \(function)->\(line)]:\(msg)") 37 | } 38 | } 39 | 40 | 41 | class UTweenLogger: UTweenLoggable {} 42 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Protocols/WeaklyLoopable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeaklyLoopable.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 10/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | protocol WeaklyLoopable { 10 | func loopWeakly() 11 | } -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Tween/CGPointTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPointTween.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class CGPointTween: UTween { 12 | 13 | var currentValue = CGPoint() 14 | 15 | override func compute(_ value: Double) -> CGPoint { 16 | _ = super.compute(value) 17 | 18 | let from = self.fromC() 19 | let to = self.toC() 20 | 21 | currentValue.x = from.x + (to.x - from.x) * CGFloat(value) 22 | currentValue.y = from.y + (to.y - from.y) * CGFloat(value) 23 | 24 | return currentValue 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Tween/ColorTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ColorTween.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class ColorTween: UTween { 13 | override func compute(_ value: Double) -> UIColor { 14 | _ = super.compute(value) 15 | 16 | let from = self.fromC() 17 | let to = self.toC() 18 | 19 | var rFrom: CGFloat = 0 20 | var gFrom: CGFloat = 0 21 | var bFrom: CGFloat = 0 22 | var aFrom: CGFloat = 0 23 | 24 | var rTo: CGFloat = 0 25 | var gTo: CGFloat = 0 26 | var bTo: CGFloat = 0 27 | var aTo: CGFloat = 0 28 | 29 | from.getRed(&rFrom, green: &gFrom, blue: &bFrom, alpha: &aFrom) 30 | to.getRed(&rTo, green: &gTo, blue: &bTo, alpha: &aTo) 31 | 32 | let r = rFrom + (rTo - rFrom) * CGFloat(value) 33 | let g = gFrom + (gTo - gFrom) * CGFloat(value) 34 | let b = bFrom + (bTo - bFrom) * CGFloat(value) 35 | let a = aFrom + (aTo - aFrom) * CGFloat(value) 36 | 37 | return UIColor(red: r, green: g, blue: b, alpha: a) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Tween/NumericTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NumericTween.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class NumericTween: UTween { 12 | override func compute(_ value: Double) -> T { 13 | _ = super.compute(value) 14 | 15 | let from = self.fromC() 16 | let to = self.toC() 17 | 18 | let distance = to - from 19 | var parsedDistance: Double 20 | if distance is Double { 21 | parsedDistance = distance as! Double 22 | } 23 | else { 24 | parsedDistance = Double(distance)! 25 | } 26 | 27 | let total = T( parsedDistance * value ) 28 | 29 | return from + total 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Tween/TransformTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransformTween.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class TransformTween: UTween { 13 | override func compute(_ value: Double) -> CGAffineTransform { 14 | _ = super.compute(value) 15 | 16 | let from = self.fromC() 17 | let to = self.toC() 18 | 19 | var currentValue = CGAffineTransform.identity 20 | currentValue.tx = from.tx + (to.tx - from.tx) * CGFloat(value) 21 | currentValue.ty = from.ty + (to.ty - from.ty) * CGFloat(value) 22 | 23 | currentValue.a = from.a + (to.a - from.a) * CGFloat(value) 24 | currentValue.b = from.b + (to.b - from.b) * CGFloat(value) 25 | currentValue.c = from.c + (to.c - from.c) * CGFloat(value) 26 | currentValue.d = from.d + (to.d - from.d) * CGFloat(value) 27 | 28 | return currentValue 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Tween/UTimeline.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTimeline.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 05/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class UTimeline: UTweenBase { 12 | var tweens: [UTweenBase] = [] 13 | var startTimeForTweenId: [String : Double] = [:] 14 | 15 | open var count: Int { return tweens.count } 16 | 17 | /** 18 | Initialize a `UTimeline` with a random id. 19 | 20 | Tweens all containing elements from start to end. 21 | */ 22 | public convenience init() { 23 | let id = "\(#file)_\(arc4random())_update" 24 | self.init(id: id) 25 | } 26 | 27 | /** 28 | Initialize a `UTimeline`. 29 | 30 | Tweens all containing elements from start to end. 31 | 32 | - Parameter id: The unique id of the Tween 33 | */ 34 | public override init(id: String) { 35 | super.init(id: id) 36 | 37 | initialDuration = 0 38 | duration = 0 39 | durationTotal = 0 40 | } 41 | 42 | open func append(_ tween: UTweenBase) { 43 | // tween.computeConfigs() 44 | // 45 | // tweens.append(tween) 46 | // 47 | // startTimeForTweenId[tween.id] = initialDuration 48 | // 49 | // initialDuration += tween.durationTotal 50 | // 51 | // computeConfigs() 52 | 53 | insert(tween, at: durationTotal) 54 | } 55 | 56 | open func insert(_ tween: UTweenBase, at time: Double) { 57 | tween.computeConfigs() 58 | 59 | tweens.append(tween) 60 | 61 | startTimeForTweenId[tween.id] = time 62 | duration = max(duration, time + tween.durationTotal) 63 | initialDuration = duration 64 | 65 | tweens.sort(by: { 66 | startTimeForTweenId[$0.id] ?? 0 < startTimeForTweenId[$1.id] ?? 0 67 | }) 68 | computeConfigs() 69 | } 70 | 71 | override open var progress: Double { 72 | set { 73 | time = newValue * duration 74 | 75 | for (i, tween) in tweens.enumerated() { 76 | let repeatCount = tweenOptions.repeatCount() 77 | var cycles = Double(repeatCount + 1) 78 | 79 | if tweenOptions.contains(.yoyo) && !tweenOptions.containsRepeat() { 80 | cycles *= 2.0 81 | } 82 | 83 | let startTime = startTimeForTweenId[tween.id]! / cycles 84 | 85 | let mapped = Math.mapValueInRange(time, 86 | fromLower: startTime, fromUpper: startTime + tween.durationTotal / cycles, 87 | toLower: 0.0, toUpper: 1.0) 88 | 89 | let value = tween.direction == .forward ? mapped : 1 - mapped 90 | 91 | let clamped = Math.clamp(value, lower: 0.0, upper: 1.0) 92 | if i == 0 || clamped > 0 { 93 | tween.progressTotal = clamped 94 | } 95 | } 96 | 97 | super.progress = newValue 98 | } 99 | get { 100 | return time / duration 101 | } 102 | } 103 | 104 | 105 | @discardableResult 106 | override open func reference(_ value: TweenMemoryReference) -> Self { 107 | reference = value 108 | 109 | return self 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Tween/UTween.h: -------------------------------------------------------------------------------- 1 | // 2 | // UTween.h 3 | // UTween 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | //! Project version number for Tween. 13 | FOUNDATION_EXPORT double TweenVersionNumber; 14 | 15 | //! Project version string for Tween. 16 | FOUNDATION_EXPORT const unsigned char TweenVersionString[]; 17 | 18 | // In this header, you should import all the public headers of your framework using statements like #import 19 | 20 | 21 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Tween/UTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTween.swift 3 | // UTween 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class UTween: UTweenBase { 13 | 14 | var start: T! 15 | var end: T! 16 | 17 | internal var fromC: (() -> T)! 18 | internal var toC: (() -> T)! 19 | 20 | var updateValue: ((_ value: T) -> Void)! 21 | var updateValueAndProgress: ((_ value: T, _ progress: Double) -> Void)! 22 | 23 | var offset: Double? 24 | 25 | /** 26 | Initialize a generic `UTween` with a random id. 27 | 28 | Tweens any value with type T from start to end. 29 | 30 | This object needs to know how to compute interpolations from start to end, that for 31 | `func compute(value: Double) -> T` must be overriden. 32 | */ 33 | public convenience init() { 34 | let id = "\(#file)_\(arc4random())_update" 35 | self.init(id: id) 36 | } 37 | 38 | /** 39 | Initialize a generic `UTween`. 40 | 41 | Tweens any value with type T from start to end. 42 | 43 | This object needs to know how to compute interpolations from start to end, that for 44 | `func compute(value: Double) -> T` must be overriden. 45 | 46 | - Parameter id: The unique id of the Tween 47 | */ 48 | public override init(id: String) { 49 | super.init(id: id) 50 | } 51 | 52 | override open var progress: Double { 53 | set { 54 | time = newValue * duration 55 | 56 | easeValue = ease(time, 0.0, 1.0, duration) 57 | 58 | if let offset = offset { 59 | easeValue = fmod(easeValue + offset, 1.0) 60 | } 61 | 62 | let computedValue = compute(easeValue) 63 | 64 | updateValue?( computedValue) 65 | updateValueAndProgress?( computedValue, newValue ) 66 | 67 | super.progress = newValue 68 | } 69 | get { 70 | return time / duration 71 | } 72 | } 73 | 74 | func compute(_ value: Double) -> T { 75 | //should be overriden 76 | 77 | return fromC() 78 | } 79 | 80 | //override Tweenable methods 81 | override open func kill() { 82 | super.kill() 83 | 84 | fromC = nil 85 | updateValue = nil 86 | updateValueAndProgress = nil 87 | complete = nil 88 | } 89 | 90 | @discardableResult 91 | override open func reference(_ value: TweenMemoryReference) -> Self { 92 | reference = value 93 | 94 | return self 95 | } 96 | } 97 | 98 | 99 | extension UTween { 100 | // - 101 | public func from(_ from: T, to: T) -> Self { 102 | self.fromC = {from} 103 | self.toC = {to} 104 | 105 | return self.duration(duration) 106 | } 107 | 108 | public func from(_ from: @escaping () -> T, to: @escaping () -> T) -> Self { 109 | self.fromC = from 110 | self.toC = to 111 | 112 | return self.duration(duration) 113 | } 114 | 115 | public func from(_ from: @escaping () -> T, to: T) -> Self { 116 | self.fromC = from 117 | self.toC = {to} 118 | 119 | return self.duration(duration) 120 | } 121 | 122 | public func from(_ from: T, to: @escaping () -> T) -> Self { 123 | self.fromC = {from} 124 | self.toC = to 125 | 126 | return self.duration(duration) 127 | } 128 | 129 | 130 | @discardableResult 131 | public func update(_ value: @escaping (T) -> Void) -> Self { 132 | updateValue = value 133 | 134 | return self 135 | } 136 | 137 | 138 | @discardableResult 139 | public func update(_ value: @escaping (T, Double) -> Void) -> Self { 140 | updateValueAndProgress = value 141 | 142 | return self 143 | } 144 | 145 | @discardableResult 146 | public func ease(_ ease: @escaping Easing) -> Self { 147 | self.ease = ease 148 | return self 149 | } 150 | 151 | @discardableResult 152 | public func offset(_ value: Double) -> Self { 153 | self.offset = value 154 | return self 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Util/Bezier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bezier.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 17/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GLKit 11 | 12 | //see https://en.wikipedia.org/wiki/B%C3%A9zier_curve 13 | 14 | class Bezier { 15 | static func linear(t _t: CGFloat, p0: CGPoint, p1: CGPoint) -> CGPoint { 16 | 17 | let v0 = GLKVector2(v: (Float(p0.x), Float(p0.y))) 18 | let v1 = GLKVector2(v: (Float(p1.x), Float(p1.y))) 19 | 20 | let t = Float(_t) 21 | 22 | let v0r = GLKVector2MultiplyScalar(v0, 1-t) 23 | let v1r = GLKVector2MultiplyScalar(v1, t) 24 | 25 | let vResult = GLKVector2Add(v0r, v1r) 26 | 27 | return CGPoint(x: CGFloat(vResult.x), y: CGFloat(vResult.y)) 28 | } 29 | 30 | static func quad(t _t: CGFloat, p0: CGPoint, p1: CGPoint, p2: CGPoint) -> CGPoint { 31 | 32 | let v0 = GLKVector2(v: (Float(p0.x), Float(p0.y))) 33 | let v1 = GLKVector2(v: (Float(p1.x), Float(p1.y))) 34 | let v2 = GLKVector2(v: (Float(p2.x), Float(p2.y))) 35 | 36 | let t = Float(_t) 37 | 38 | let v0r = GLKVector2MultiplyScalar(v0, pow(1-t, 2)) 39 | let v1r = GLKVector2MultiplyScalar(v1, 2*t*(1-t)) 40 | let v2r = GLKVector2MultiplyScalar(v2, t*t) 41 | 42 | var vResult = GLKVector2Add(v0r, v1r) 43 | vResult = GLKVector2Add(vResult, v2r) 44 | 45 | return CGPoint(x: CGFloat(vResult.x), y: CGFloat(vResult.y)) 46 | } 47 | 48 | static func cubic(t _t: CGFloat, p0: CGPoint, p1: CGPoint, p2: CGPoint, p3: CGPoint) -> CGPoint { 49 | let v0 = GLKVector2(v: (Float(p0.x), Float(p0.y))) 50 | let v1 = GLKVector2(v: (Float(p1.x), Float(p1.y))) 51 | let v2 = GLKVector2(v: (Float(p2.x), Float(p2.y))) 52 | let v3 = GLKVector2(v: (Float(p3.x), Float(p3.y))) 53 | 54 | let t = Float(_t) 55 | 56 | let v0r = GLKVector2MultiplyScalar(v0, pow(1-t, 3)) 57 | let v1r = GLKVector2MultiplyScalar(v1, 3 * t * pow(1-t, 2)) 58 | let v2r = GLKVector2MultiplyScalar(v2, 3 * pow(t, 2) * (1-t)) 59 | let v3r = GLKVector2MultiplyScalar(v3, pow(t, 3)) 60 | 61 | var vResult = GLKVector2Add(v0r, v1r) 62 | vResult = GLKVector2Add(vResult, v2r) 63 | vResult = GLKVector2Add(vResult, v3r) 64 | 65 | return CGPoint(x: CGFloat(vResult.x), y: CGFloat(vResult.y)) 66 | } 67 | } -------------------------------------------------------------------------------- /Examples/TweenApp/Pods/Ubergang/Ubergang/Util/Math.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Math.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 15/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Math { 12 | class func clamp(_ value: T, lower: T, upper: T) -> T { 13 | return max(lower, min(value, upper)) 14 | } 15 | 16 | class func mapValueInRange(_ value: Double, fromLower: Double, fromUpper: Double, toLower: Double, toUpper: Double) -> Double { 17 | let fromRangeSize = fromUpper - fromLower 18 | let toRangeSize = toUpper - toLower 19 | let valueScale = (value - fromLower) / fromRangeSize 20 | return toLower + (valueScale * toRangeSize) 21 | } 22 | 23 | class func zigZag(_ x: Double) -> Double { 24 | return 1 / .pi * asin(cos(Double.pi * (x + 1))) + 0.5 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/AdditiveAnimationViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | import Ubergang 12 | 13 | class AdditiveAnimationViewController: ExampleViewController { 14 | 15 | 16 | @IBOutlet var views: [UIImageView]! 17 | 18 | @IBOutlet var targetView: UIImageView! 19 | 20 | var tween: CGPointTween! 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | 25 | views.forEach { 26 | $0.image = $0.image!.withRenderingMode(UIImage.RenderingMode.alwaysTemplate); 27 | $0.translatesAutoresizingMaskIntoConstraints = true 28 | } 29 | } 30 | 31 | override func setupTween() -> UTweenBase { 32 | return CGPointTween(id: "pointTween") 33 | .from({ [unowned self] in 34 | self.views[0].center 35 | }, to:{ [unowned self] in 36 | self.views[1].center 37 | }) 38 | .update { [unowned self] (value:CGPoint, progress: Double) in 39 | self.targetView.center = value 40 | } 41 | .updateTotal { [unowned self] progressTotal in 42 | self.tweenControls.progress(progressTotal) 43 | } 44 | .complete { [unowned self] in 45 | self.tweenControls.stop() 46 | } 47 | .duration(5) 48 | .ease(.cubic(.out)) 49 | } 50 | 51 | var selectedView: UIView? 52 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 53 | let touch = touches.first! 54 | let position = touch.location(in: view) 55 | 56 | selectedView = view.hitTest(position, with: nil) 57 | if selectedView == view { 58 | selectedView = nil 59 | } 60 | if selectedView != nil { 61 | view.bringSubviewToFront(selectedView!) 62 | } 63 | } 64 | 65 | 66 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 67 | let touch = touches.first! 68 | let position = touch.location(in: view) 69 | 70 | selectedView?.center.x = position.x 71 | selectedView?.center.y = position.y 72 | } 73 | 74 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 75 | selectedView = nil 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | 18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 19 | 20 | UserDefaults.standard.setValue(false, forKey: "_UIConstraintBasedLayoutLogUnsatisfiable") 21 | 22 | UTweenSetup.instance.enableLogging(true) 23 | 24 | return true 25 | } 26 | 27 | func applicationWillResignActive(_ application: UIApplication) { 28 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 29 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 30 | } 31 | 32 | func applicationDidEnterBackground(_ application: UIApplication) { 33 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | func applicationWillEnterForeground(_ application: UIApplication) { 38 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 39 | } 40 | 41 | func applicationDidBecomeActive(_ application: UIApplication) { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | func applicationWillTerminate(_ application: UIApplication) { 46 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 47 | } 48 | 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "Icon-Small.png", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "iphone", 22 | "filename" : "Icon-Small@2x.png", 23 | "scale" : "2x" 24 | }, 25 | { 26 | "size" : "29x29", 27 | "idiom" : "iphone", 28 | "filename" : "Icon-Small@3x.png", 29 | "scale" : "3x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "iphone", 34 | "filename" : "Icon-40@2x.png", 35 | "scale" : "2x" 36 | }, 37 | { 38 | "size" : "40x40", 39 | "idiom" : "iphone", 40 | "filename" : "Icon-40@3x.png", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "size" : "57x57", 45 | "idiom" : "iphone", 46 | "filename" : "Icon.png", 47 | "scale" : "1x" 48 | }, 49 | { 50 | "size" : "57x57", 51 | "idiom" : "iphone", 52 | "filename" : "Icon@2x.png", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "size" : "60x60", 57 | "idiom" : "iphone", 58 | "filename" : "Icon-60@2x.png", 59 | "scale" : "2x" 60 | }, 61 | { 62 | "size" : "60x60", 63 | "idiom" : "iphone", 64 | "filename" : "Icon-60@3x.png", 65 | "scale" : "3x" 66 | }, 67 | { 68 | "idiom" : "ipad", 69 | "size" : "20x20", 70 | "scale" : "1x" 71 | }, 72 | { 73 | "idiom" : "ipad", 74 | "size" : "20x20", 75 | "scale" : "2x" 76 | }, 77 | { 78 | "size" : "29x29", 79 | "idiom" : "ipad", 80 | "filename" : "Icon-Small.png", 81 | "scale" : "1x" 82 | }, 83 | { 84 | "size" : "29x29", 85 | "idiom" : "ipad", 86 | "filename" : "Icon-Small@2x.png", 87 | "scale" : "2x" 88 | }, 89 | { 90 | "size" : "40x40", 91 | "idiom" : "ipad", 92 | "filename" : "Icon-40.png", 93 | "scale" : "1x" 94 | }, 95 | { 96 | "size" : "40x40", 97 | "idiom" : "ipad", 98 | "filename" : "Icon-40@2x.png", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "size" : "50x50", 103 | "idiom" : "ipad", 104 | "filename" : "Icon-Small-50.png", 105 | "scale" : "1x" 106 | }, 107 | { 108 | "size" : "50x50", 109 | "idiom" : "ipad", 110 | "filename" : "Icon-Small-50@2x.png", 111 | "scale" : "2x" 112 | }, 113 | { 114 | "size" : "72x72", 115 | "idiom" : "ipad", 116 | "filename" : "Icon-72.png", 117 | "scale" : "1x" 118 | }, 119 | { 120 | "size" : "72x72", 121 | "idiom" : "ipad", 122 | "filename" : "Icon-72@2x.png", 123 | "scale" : "2x" 124 | }, 125 | { 126 | "size" : "76x76", 127 | "idiom" : "ipad", 128 | "filename" : "Icon-76.png", 129 | "scale" : "1x" 130 | }, 131 | { 132 | "size" : "76x76", 133 | "idiom" : "ipad", 134 | "filename" : "Icon-76@2x.png", 135 | "scale" : "2x" 136 | }, 137 | { 138 | "size" : "83.5x83.5", 139 | "idiom" : "ipad", 140 | "filename" : "Icon-83.5@2x.png", 141 | "scale" : "2x" 142 | }, 143 | { 144 | "idiom" : "ios-marketing", 145 | "size" : "1024x1024", 146 | "scale" : "1x" 147 | } 148 | ], 149 | "info" : { 150 | "version" : 1, 151 | "author" : "xcode" 152 | } 153 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-72.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/AppIcon.appiconset/Icon@2x.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/CircleBG.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "circleBG.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/CircleBG.imageset/circleBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/CircleBG.imageset/circleBG.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/CircleOutline.imageset/CircleOutline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/CircleOutline.imageset/CircleOutline.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/CircleOutline.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "CircleOutline.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/Dot.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "dot.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/Dot.imageset/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/Dot.imageset/dot.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/PauseIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "PauseIcon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/PauseIcon.imageset/PauseIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/PauseIcon.imageset/PauseIcon.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/PlayIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "PlayIcon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/PlayIcon.imageset/PlayIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/PlayIcon.imageset/PlayIcon.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/ReverseIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "ReverseIcon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | }, 21 | "properties" : { 22 | "template-rendering-intent" : "template" 23 | } 24 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/ReverseIcon.imageset/ReverseIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/ReverseIcon.imageset/ReverseIcon.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/SliderThumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "SliderThumb.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/SliderThumb.imageset/SliderThumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/SliderThumb.imageset/SliderThumb.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/StopIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "StopIcon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Assets.xcassets/StopIcon.imageset/StopIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Examples/TweenApp/TweenApp/Assets.xcassets/StopIcon.imageset/StopIcon.png -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/BezierPathViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | import Ubergang 12 | 13 | class BezierPathViewController: ExampleViewController { 14 | 15 | var targetView: UIImageView! 16 | 17 | var random: CGFloat { 18 | return CGFloat(Double(arc4random_uniform(255)) / 255.0) 19 | } 20 | 21 | override func loadView() { 22 | super.loadView() 23 | 24 | targetView = UIImageView(image: UIImage(named: "SliderThumb")) 25 | view.addSubview(targetView) 26 | } 27 | 28 | override func setupTween() -> UTweenBase { 29 | let rectWidth = CGFloat(130) 30 | let centerX = (UIScreen.main.bounds.width - rectWidth) * 0.5 31 | let path = heartInRect(CGRect(x: centerX, y: 100, width: rectWidth, height: 260)) 32 | // let path = randomPath() 33 | 34 | drawPath(path) 35 | 36 | return BezierPathTween(id: "bezierTween") 37 | .along(path) 38 | .update { [weak self] in 39 | self?.targetView.center = $0 40 | } 41 | .duration(15) 42 | .ease(.linear) 43 | .options(.repeat(1)) 44 | .updateTotal { [weak self] value in 45 | self?.tweenControls.progress(value) 46 | } 47 | .complete { [weak self] in 48 | self?.tweenControls.stop() 49 | } 50 | } 51 | 52 | func drawPath(_ path: UIBezierPath) { 53 | let shape = CAShapeLayer() 54 | shape.path = path.cgPath 55 | shape.strokeColor = UIColor.red.cgColor 56 | shape.lineWidth = 5 57 | shape.fillColor = UIColor.clear.cgColor 58 | view.layer.addSublayer(shape) 59 | } 60 | 61 | func heartInRect(_ rect:CGRect) -> UIBezierPath { 62 | let path = UIBezierPath() 63 | 64 | let center = rect.minX + rect.width * 0.5 65 | let bottom = rect.maxY 66 | 67 | let startPoint = CGPoint(x: center, y: bottom) 68 | self.targetView.center = startPoint 69 | path.move(to: startPoint) 70 | 71 | var p1 = CGPoint(x: center, y: bottom - 60) 72 | var p2 = CGPoint(x: center - 160, y: bottom - 116) 73 | var p3 = CGPoint(x: center - 130, y: bottom - 200) 74 | path.addCurve(to: p3, controlPoint1: p1, controlPoint2: p2) 75 | 76 | p1 = CGPoint(x: center - 100, y: bottom - 280) 77 | p2 = CGPoint(x: center - 15, y: bottom - 255) 78 | p3 = CGPoint(x: center, y: bottom - 225) 79 | path.addCurve(to: p3, controlPoint1: p1, controlPoint2: p2) 80 | 81 | p1 = CGPoint(x: center + 15, y: bottom - 255) 82 | p2 = CGPoint(x: center + 100, y: bottom - 280) 83 | p3 = CGPoint(x: center + 130, y: bottom - 200) 84 | path.addCurve(to: p3, controlPoint1: p1, controlPoint2: p2) 85 | 86 | p1 = CGPoint(x: center + 160, y: bottom - 116) 87 | p2 = CGPoint(x: center, y: bottom - 60) 88 | p3 = CGPoint(x: center, y: bottom) 89 | path.addCurve(to: p3, controlPoint1: p1, controlPoint2: p2) 90 | 91 | return path 92 | } 93 | 94 | func randomPath() -> UIBezierPath { 95 | let path = UIBezierPath() 96 | 97 | let startPoint = CGPoint(x: 20, y: 100) 98 | self.targetView.center = startPoint 99 | path.move(to: startPoint) 100 | 101 | for _ in 0...3 { 102 | print("\(arc4random_uniform(2))") 103 | let rnd = arc4random_uniform(3) 104 | switch rnd { 105 | case 0: 106 | path.addLine(to: getRndPointOnScreen()) 107 | case 1: 108 | let p1 = getRndPointOnScreen() 109 | let p2 = getRndPointOnScreen() 110 | path.addQuadCurve(to: p2, controlPoint: p1) 111 | default: 112 | let p1 = getRndPointOnScreen() 113 | let p2 = getRndPointOnScreen() 114 | let p3 = getRndPointOnScreen() 115 | path.addCurve(to: p3, controlPoint1: p1, controlPoint2: p2) 116 | } 117 | } 118 | 119 | path.close() 120 | 121 | let shape = CAShapeLayer() 122 | shape.path = path.cgPath 123 | shape.strokeColor = UIColor.red.cgColor 124 | shape.fillColor = UIColor.clear.cgColor 125 | view.layer.addSublayer(shape) 126 | 127 | return path 128 | } 129 | 130 | func getRndPointOnScreen() -> CGPoint { 131 | let width = UInt32(UIScreen.main.bounds.width - 40) 132 | let height = UInt32(UIScreen.main.bounds.height - 200) 133 | 134 | let rndWidth = CGFloat(arc4random_uniform(width)) 135 | let rndHeight = CGFloat(arc4random_uniform(height)) 136 | 137 | return CGPoint(x: rndWidth + 20, y: rndHeight + 100) 138 | } 139 | } 140 | 141 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/ColorViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | import Ubergang 12 | 13 | class ColorViewController: ExampleViewController { 14 | 15 | @IBOutlet var targetView: UIView! 16 | 17 | var random: CGFloat { 18 | return CGFloat(Double(arc4random_uniform(255)) / 255.0) 19 | } 20 | 21 | override func setupTween() -> UTweenBase { 22 | let colorTo = UIColor(red: random, green: random, blue: random, alpha: 1.0) 23 | let colorFrom = UIColor(red: random, green: random, blue: random, alpha: 1.0) 24 | 25 | self.targetView.backgroundColor = colorFrom 26 | 27 | return colorFrom.tween(to: colorTo) 28 | .duration(1) 29 | .update { [unowned self] (value:UIColor, progress: Double) in 30 | self.targetView.backgroundColor = value 31 | self.tweenControls.progress(progress) 32 | } 33 | .complete { [unowned self] in 34 | self.tweenControls.stop() 35 | } 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/ConstraintViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConstraintViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class ConstraintViewController: ExampleViewController { 13 | @IBOutlet var redViewHeight: NSLayoutConstraint! 14 | @IBOutlet var grayViewWidth: NSLayoutConstraint! 15 | @IBOutlet var greenViewBottom: NSLayoutConstraint! 16 | 17 | var defaultRedViewHeight: CGFloat! 18 | var defaultGrayViewWidth: CGFloat! 19 | var defaultGreenViewBottom: CGFloat! 20 | 21 | override func loadView() { 22 | super.loadView() 23 | 24 | defaultRedViewHeight = redViewHeight.constant 25 | defaultGrayViewWidth = grayViewWidth.constant 26 | defaultGreenViewBottom = greenViewBottom.constant 27 | } 28 | 29 | override func setupTween() -> UTweenBase { 30 | let timeline = UTimeline() 31 | .reference(.weak) 32 | .updateTotal { [unowned self] (progressTotal) in 33 | self.tweenControls.progress(progressTotal) 34 | } 35 | .complete { [unowned self] in 36 | self.tweenControls.stop() 37 | } 38 | 39 | let tween1 = defaultRedViewHeight!.tween(to: 50) 40 | .update { [unowned self] in 41 | self.redViewHeight.constant = $0 42 | } 43 | .duration(1) 44 | .ease(.quint(.inOut)) 45 | 46 | let tween2 = defaultGrayViewWidth!.tween(to: 150) 47 | .update { [unowned self] in 48 | self.grayViewWidth.constant = $0 49 | } 50 | .duration(2) 51 | .ease(.bounce(.out)) 52 | 53 | let tween3 = defaultGreenViewBottom!.tween(to: 100) 54 | .update { [unowned self] in 55 | self.greenViewBottom.constant = $0 56 | } 57 | .duration(3) 58 | .options(.repeat(1), .yoyo) 59 | .ease(.expo(.inOut)) 60 | 61 | timeline.append(tween1) 62 | timeline.append(tween2) 63 | timeline.append(tween3) 64 | 65 | return timeline 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/CurveThroughViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | import Ubergang 12 | 13 | class CurveThroughViewController: ExampleViewController { 14 | 15 | var targetView: UIImageView! 16 | 17 | override func loadView() { 18 | super.loadView() 19 | 20 | targetView = UIImageView(image: UIImage(named: "PlayIcon")?.withRenderingMode(.alwaysTemplate)) 21 | targetView.tintColor = UIColor(red: 73 / 255, green: 205 / 255, blue: 6 / 255, alpha: 0.75) 22 | view.addSubview(targetView) 23 | } 24 | 25 | override func setupTween() -> UTweenBase { 26 | let rectWidth = CGFloat(130) 27 | let centerX = (UIScreen.main.bounds.width - rectWidth) * 0.5 28 | let points = raceTrack(CGRect(x: centerX, y: 100, width: rectWidth, height: 260)) 29 | 30 | let numbers = points.map { NSValue(cgPoint: $0) } 31 | let path = UIBezierPath.interpolateCGPoints(withCatmullRom: numbers, closed: true, alpha: 1.0) 32 | 33 | drawPath(path!) 34 | 35 | return BezierPathTween(id: "bezierTween") 36 | .along(points, closed: true) 37 | .update { [weak self] (value:CGPoint, progress: Double, orientation: CGPoint) in 38 | self?.targetView.center = value 39 | 40 | let angle = atan2(orientation.y, orientation.x) 41 | let transform = CGAffineTransform.identity.rotated(by: angle) 42 | self?.targetView.transform = transform 43 | } 44 | .duration(10) 45 | .ease(.linear) 46 | .options(.repeat(1)) 47 | .updateTotal { [weak self] value in 48 | self?.tweenControls.progress(value) 49 | } 50 | .complete { [weak self] in 51 | self?.tweenControls.stop() 52 | } 53 | } 54 | 55 | func drawPath(_ path: UIBezierPath) { 56 | let shape = CAShapeLayer() 57 | shape.path = path.cgPath 58 | shape.strokeColor = UIColor.red.cgColor 59 | shape.fillColor = UIColor.clear.cgColor 60 | view.layer.addSublayer(shape) 61 | } 62 | 63 | func raceTrack(_ rect:CGRect) -> [CGPoint] { 64 | 65 | let startPoint = CGPoint(x: rect.minX, y: rect.minY) 66 | self.targetView.center = startPoint 67 | 68 | var points = [CGPoint]() 69 | points.append(startPoint) 70 | points.append(CGPoint(x: rect.midX, y: rect.midY)) 71 | points.append(CGPoint(x: rect.minX, y: rect.maxY)) 72 | points.append(CGPoint(x: rect.maxX, y: rect.maxY)) 73 | points.append(CGPoint(x: rect.maxX, y: rect.minY)) 74 | 75 | return points 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/ExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 15/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class ExampleViewController: UIViewController { 13 | 14 | var tweenControls: TweenControlsView! 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | addTweenControls(setupTween()) 20 | } 21 | 22 | deinit { 23 | print("deinit \(type(of: self))") 24 | } 25 | 26 | func setupTween() -> UTweenBase { 27 | //override 28 | return UTween() 29 | } 30 | 31 | func addTweenControls(_ tween: UTweenBase) { 32 | tweenControls = TweenControlsView.instanceFromNib() 33 | tweenControls.progress(0.0) 34 | tweenControls.onPlay = { 35 | tween.start() 36 | } 37 | tweenControls.onStop = { 38 | tween.stop() 39 | } 40 | tweenControls.onPause = { 41 | tween.pause() 42 | } 43 | tweenControls.onResume = { 44 | tween.resume() 45 | } 46 | tweenControls.onDirection = { value in 47 | tween.direction(value) 48 | } 49 | tweenControls.onProgress = { value in 50 | tween.progressTotal = value 51 | } 52 | view.addSubview(tweenControls) 53 | 54 | tween.progressTotal = 0 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/InsertTimelineViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InsertTimelineViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 05.08.17. 6 | // Copyright © 2017 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class InsertTimelineViewController: ExampleViewController { 13 | 14 | @IBOutlet var viewCenterY: NSLayoutConstraint! 15 | @IBOutlet var viewCenterX: NSLayoutConstraint! 16 | 17 | override func setupTween() -> UTweenBase { 18 | let timeline = UTimeline() 19 | .reference(.weak) 20 | .options(.repeat(1)) 21 | .updateTotal { [unowned self] in 22 | self.tweenControls.progress($0) 23 | } 24 | .complete { [unowned self] in 25 | self.tweenControls.stop() 26 | } 27 | 28 | //time 0 to 0.5 29 | timeline.append(CGFloat(0).tween(to: 100).update({ [unowned self] (value: CGFloat) in 30 | self.viewCenterY.constant = value 31 | }) 32 | ) 33 | 34 | //time 4 to 4.5 35 | timeline.insert(CGFloat(0).tween(to: 100).update({ [unowned self] in 36 | self.viewCenterX.constant = $0 37 | }), at: 4) 38 | 39 | //time 5 to 7 40 | timeline.insert(CGFloat(100).tween(to: -100).update({ [unowned self] (value: CGFloat) in 41 | self.viewCenterX.constant = value 42 | self.viewCenterY.constant = value 43 | }) 44 | .duration(2) 45 | , at: 5) 46 | 47 | //time 7 to 9 48 | timeline.insert(CGFloat(-100).tween(to: 0).update({ [unowned self] (value: CGFloat) in 49 | self.viewCenterX.constant = value 50 | }) 51 | .duration(2) 52 | , at: 7) 53 | 54 | //time 9.5 to 10 55 | timeline.insert(CGFloat(-100).tween(to: 0).update({ [unowned self] in 56 | self.viewCenterY.constant = $0 57 | }), at: 9.5) 58 | 59 | return timeline 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/MainTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainTableViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 08/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MainTableViewController: UITableViewController { 12 | override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { 13 | if let cell = cell as? TitleIconTableViewCell { 14 | cell.animateIn() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/NumericViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class NumericViewController: ExampleViewController { 13 | @IBOutlet var numberLabel: UILabel! 14 | 15 | override func setupTween() -> UTweenBase { 16 | return 0.tween(to:100) 17 | .update { [unowned self] (value:Int, progress: Double) in 18 | self.numberLabel.text = "\(value)" 19 | self.tweenControls.progress(progress) 20 | } 21 | .complete { [unowned self] in 22 | self.tweenControls.stop() 23 | } 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/ParticleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ParticleViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class ParticleViewController: ExampleViewController { 13 | var numTweens: UInt32 = 500 14 | 15 | var particles = [UIView]() 16 | 17 | override func loadView() { 18 | super.loadView() 19 | 20 | createViews() 21 | } 22 | 23 | func createViews() { 24 | let bounds = UIScreen.main.bounds 25 | 26 | for _: UInt32 in 0.. UTweenBase { 39 | let timeline = UTimeline(id: "particleTimeline") 40 | .reference(.weak) 41 | .updateTotal { [unowned self] (progressTotal) in 42 | self.tweenControls.progress(progressTotal) 43 | } 44 | .complete { [unowned self] in 45 | self.tweenControls.stop() 46 | } 47 | 48 | for i in 0.. UTweenBase { 21 | return 0.0.tween(to: 10) 22 | .id("progressTween") 23 | .duration(5) 24 | .ease(.cubic(.out)) 25 | .options(.repeat(1), .yoyo) 26 | .reference(.weak) 27 | .update { [unowned self] (value, progress) in 28 | self.progressBar.progress = Float(progress) 29 | self.tweenLabel.text = "\(round(value * 10.0) / 10.0)" 30 | } 31 | .updateTotal { [unowned self] (progressTotal) in 32 | self.tweenControls.progress(progressTotal) 33 | self.progressBarTotal.progress = Float(progressTotal) 34 | } 35 | .repeatCycleChange { [unowned self] cycle in 36 | self.repeatCycleLabel.text = "\(cycle)" 37 | } 38 | .complete { [unowned self] in 39 | self.tweenControls.stop() 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/TimelinesViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class TimelinesViewController: ExampleViewController { 13 | @IBOutlet weak var tweenStatusView0: TweenStatusView! 14 | @IBOutlet weak var tweenStatusView1: TweenStatusView! 15 | @IBOutlet weak var tweenStatusView2: TweenStatusView! 16 | @IBOutlet weak var tweenStatusView3: TweenStatusView! 17 | @IBOutlet var numberLabel: UILabel! 18 | @IBOutlet var progressBar: CircularProgressBar! 19 | 20 | override func setupTween() -> UTweenBase { 21 | let timeline = UTimeline(id: "timeline") 22 | .options(.repeat(9)) 23 | .repeatCycleChange { [unowned self] repeatCycle in 24 | self.tweenStatusView2.repeatCount = repeatCycle 25 | } 26 | .update { [unowned self] progress in 27 | self.tweenStatusView2.progress = Float(progress) 28 | } 29 | .updateTotal { [unowned self] progressTotal in 30 | self.tweenStatusView2.progressTotal = Float(progressTotal) 31 | self.tweenControls.progress(progressTotal) 32 | } 33 | 34 | //closing arc 35 | let tween0 = NumericTween(id: "arcIncreaseTween") 36 | .from(-360.0, to: -0.1) 37 | .duration(5) 38 | .ease(.cubic(.inOut)) 39 | .update { [unowned self] (value: CGFloat, progress: Double) in 40 | self.tweenStatusView0.progress = Float(progress) 41 | self.progressBar.endAngle = value 42 | } 43 | .updateTotal { [unowned self] progress in 44 | self.tweenStatusView0.progressTotal = Float(progress) 45 | } 46 | timeline.append(tween0) 47 | 48 | let tween1 = NumericTween(id: "arcDecreaseTween") 49 | .from(-360, to: -0.1) 50 | .duration(5) 51 | .ease(.cubic(.inOut)) 52 | .update { [unowned self] (value: CGFloat, progress: Double) in 53 | self.tweenStatusView1.progress = Float(progress) 54 | self.progressBar.startAngle = value 55 | } 56 | .updateTotal { [unowned self] progress in 57 | self.tweenStatusView1.progressTotal = Float(progress) 58 | } 59 | //opening arc 60 | timeline.append(tween1) 61 | 62 | 63 | let timelineContainer = UTimeline(id: "timelineContainer") 64 | .reference(.weak) 65 | .repeatCycleChange { [unowned self] repeatCycle in 66 | self.tweenStatusView3.repeatCount = repeatCycle 67 | } 68 | .update { [unowned self] progress in 69 | self.tweenStatusView3.progress = Float(progress) 70 | } 71 | .updateTotal { [unowned self] progressTotal in 72 | self.tweenStatusView3.progressTotal = Float(progressTotal) 73 | } 74 | .complete { [unowned self] in 75 | self.tweenControls.stop() 76 | } 77 | 78 | //timeline arcs 79 | timelineContainer.insert(timeline, at: 0) 80 | 81 | //countdown 82 | timelineContainer.insert( 10.tween(to: 0) 83 | .id("countTween") 84 | .duration(10) 85 | .ease(.linear) 86 | .reference(.weak) 87 | .update { [unowned self] (value: Int) in 88 | self.numberLabel.text = String(value) 89 | }, at: 0) 90 | 91 | self.tweenStatusView0.title = "\(tween0.id)" 92 | self.tweenStatusView1.title = "\(tween1.id)" 93 | self.tweenStatusView2.title = "\(timeline.id)" 94 | self.tweenStatusView3.title = "\(timelineContainer.id)" 95 | 96 | return timelineContainer 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/TransformViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransformViewController.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class TransformViewController: ExampleViewController { 13 | @IBOutlet var testView: UIView! 14 | @IBOutlet var slider: UISlider! 15 | 16 | override func setupTween() -> UTweenBase { 17 | testView.transform = CGAffineTransform.identity 18 | 19 | var to = CGAffineTransform(scaleX: 2, y: 2) 20 | to = to.rotated(by: CGFloat(Double.pi / 2)) 21 | 22 | return TransformTween(id: "transformTween") 23 | .from(testView.transform, to: to) 24 | .update { [unowned self] (value, progress) in 25 | self.testView.transform = value 26 | } 27 | .duration(4) 28 | .ease(.elastic(.out)) 29 | .reference(.weak) 30 | .updateTotal { [unowned self] (progressTotal) in 31 | self.tweenControls.progress(progressTotal) 32 | } 33 | .complete { [unowned self] in 34 | self.tweenControls.stop() 35 | } 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Ubergang-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Ubergang-Bridging-Header.h 3 | // Ubergang 4 | // 5 | // Created by RF on 23/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | #ifndef Ubergang_Bridging_Header_h 10 | #define Ubergang_Bridging_Header_h 11 | 12 | #import "UIBezierPath+Interpolation.h" 13 | 14 | #endif /* Ubergang_Bridging_Header_h */ 15 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Views/CircularProgressBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CircularProgressBar.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 09/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CircularProgressBar: UIView { 12 | let degToRad = CGFloat(.pi / 180.0) 13 | 14 | var shapeLayer:CAShapeLayer! 15 | 16 | var _startAngle: CGFloat = -90.0 17 | var startAngle: CGFloat { 18 | get { 19 | return _startAngle 20 | } 21 | set { 22 | _startAngle = newValue - 90 23 | update() 24 | } 25 | } 26 | var _endAngle: CGFloat = -90.0 27 | var endAngle: CGFloat { 28 | get { 29 | return _endAngle 30 | } 31 | set { 32 | _endAngle = newValue - 90 33 | update() 34 | } 35 | } 36 | 37 | override init(frame: CGRect) { 38 | super.init(frame: frame) 39 | setup() 40 | } 41 | 42 | required init?(coder aDecoder: NSCoder) { 43 | super.init(coder: aDecoder) 44 | setup() 45 | } 46 | 47 | func setup() { 48 | shapeLayer = CAShapeLayer() 49 | 50 | update() 51 | 52 | shapeLayer.strokeColor = UIColor.black.cgColor 53 | shapeLayer.fillColor = UIColor.clear.cgColor 54 | shapeLayer.lineWidth = 10.0 55 | 56 | self.layer.addSublayer(shapeLayer) 57 | } 58 | 59 | func update() { 60 | shapeLayer.path = arcPath().cgPath 61 | } 62 | 63 | func arcPath() -> UIBezierPath { 64 | let radius = frame.size.width * 0.5 65 | let path = UIBezierPath(arcCenter: CGPoint(x: radius, y: radius), 66 | radius: radius, 67 | startAngle: startAngle * degToRad, 68 | endAngle: endAngle * degToRad, 69 | clockwise: true) 70 | 71 | return path 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Views/ReverseButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReverseButton.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 16/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class ReverseButtton: TweenControlButton { 13 | 14 | var numericTween: NumericTween! 15 | 16 | override var isSelected: Bool { 17 | get { 18 | return super.isSelected 19 | } 20 | set { 21 | if newValue { 22 | numericTween.direction(.forward).start() 23 | } else { 24 | numericTween.direction(.reverse).start() 25 | } 26 | super.isSelected = newValue 27 | } 28 | } 29 | 30 | 31 | override func setupTween() { 32 | super.setupTween() 33 | 34 | let degToRad = .pi / 180.0 35 | 36 | numericTween = NumericTween(id: "transform_\(arc4random())") 37 | .from(0, to: CGFloat(180 * degToRad)) 38 | .update { [unowned self] value in 39 | self.imageView!.layer.transform = CATransform3DRotate(CATransform3DIdentity, value, 0.0, 1.0, 0.0) 40 | } 41 | .duration(0.5) 42 | .ease(.cubic(.inOut)) 43 | .reference(.weak) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Views/TitleIconTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TitleIconTableViewCell.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 08/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class TitleIconTableViewCell: UITableViewCell { 13 | 14 | @IBOutlet var titleLabelConstraints: NSLayoutConstraint! 15 | @IBOutlet var iconViewConstraints: NSLayoutConstraint! 16 | 17 | @IBOutlet var iconView: UIImageView! 18 | 19 | var timeline: UTimeline! 20 | 21 | override func awakeFromNib() { 22 | iconView.image = iconView.image?.withRenderingMode(.alwaysTemplate) 23 | 24 | var color: UIColor? 25 | if isUserInteractionEnabled { 26 | color = UIColor(red: 77.0 / 255.0, green: 209.0 / 255.0, blue: 0.0, alpha: 0.75) 27 | } else { 28 | color = UIColor(red: 0.0, green: 148.0 / 255.0, blue: 209.0 / 255.0, alpha: 0.75) 29 | } 30 | iconView.tintColor = color 31 | 32 | setup() 33 | } 34 | 35 | 36 | func animateIn() { 37 | _ = timeline.start() 38 | } 39 | 40 | func setup() { 41 | timeline = UTimeline(id: "timeline \(arc4random())") 42 | 43 | let from = CGFloat(120) 44 | var to = titleLabelConstraints.constant 45 | let duration = 0.4 46 | 47 | let labelTween = NumericTween(id: "titleLabelTween") 48 | .from(from, to: to) 49 | .update { [unowned self] value in 50 | self.titleLabelConstraints.constant = value 51 | } 52 | .duration(duration) 53 | .ease(.cubic(.out)) 54 | 55 | to = titleLabelConstraints.constant 56 | let dotTween = NumericTween(id: "iconViewTween") 57 | .from(from, to: to) 58 | .update { [unowned self] value in 59 | self.iconViewConstraints.constant = value 60 | } 61 | .duration(duration) 62 | .ease(.cubic(.out)) 63 | 64 | timeline.insert(labelTween, at: 0) 65 | timeline.insert(dotTween, at: 0) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Views/TweenControlButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TweenControlButton.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 16/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class TweenControlButton: UIButton { 13 | var timeline: UTimeline! 14 | 15 | var tintNormal: UIColor! 16 | var tintSelected: UIColor? 17 | 18 | override func awakeFromNib() { 19 | super.awakeFromNib() 20 | 21 | addTarget(self, action: #selector(touchDown), for: .touchDown) 22 | addTarget(self, action: #selector(touchUp), for: .touchDragExit) 23 | addTarget(self, action: #selector(touchUp), for: .touchUpInside) 24 | 25 | 26 | var image = self.image(for: UIControl.State())?.withRenderingMode(.alwaysTemplate) 27 | setImage(image, for: UIControl.State()) 28 | 29 | image = self.image(for: .selected)?.withRenderingMode(.alwaysTemplate) 30 | setImage(image, for: .selected) 31 | 32 | tintColor = tintNormal 33 | 34 | setupTween() 35 | } 36 | 37 | override var isSelected: Bool { 38 | get { 39 | return super.isSelected 40 | } 41 | set { 42 | tintColor = !newValue ? tintNormal : tintSelected 43 | super.isSelected = newValue 44 | } 45 | } 46 | 47 | 48 | func setupTween() { 49 | let tween = NumericTween(id: "alpha_\(arc4random())") 50 | .from(1.0, to: 0.5) 51 | .update { [unowned self] (value) in 52 | self.alpha = value 53 | } 54 | .duration(0.2) 55 | .ease(.cubic(.out)) 56 | 57 | let transform = CGAffineTransform(scaleX: 0.9, y: 0.9) 58 | let transformTween = TransformTween(id: "transform_\(arc4random())") 59 | .from(CGAffineTransform.identity, to: transform) 60 | .update { [unowned self] value in 61 | self.transform = value 62 | } 63 | .duration(0.2) 64 | 65 | _ = transformTween.ease(.cubic(.out)) 66 | 67 | timeline = UTimeline(id: "timeline_\(arc4random())") 68 | _ = timeline.reference(.weak) 69 | timeline.insert(tween, at: 0) 70 | timeline.insert(transformTween, at: 0) 71 | } 72 | 73 | @objc func touchDown() { 74 | timeline.direction(.forward).start() 75 | 76 | tweenOutline() 77 | } 78 | 79 | @objc func touchUp() { 80 | timeline.direction(.reverse).start() 81 | } 82 | 83 | func tweenOutline() { 84 | let imageView = UIImageView(image: UIImage(named: "CircleOutline")!.withRenderingMode(.alwaysTemplate)) 85 | imageView.tintColor = tintColor 86 | imageView.frame = frame 87 | superview!.addSubview(imageView) 88 | 89 | let transform = CGAffineTransform(scaleX: 1.3, y: 1.3) 90 | TransformTween(id: "outline_\(arc4random())") 91 | .from(CGAffineTransform(scaleX: 1.0, y: 1.0), to: transform) 92 | .update { (value, progress) in 93 | imageView.alpha = 1 - CGFloat(progress) 94 | imageView.transform = value 95 | } 96 | .duration(0.5) 97 | .ease(.cubic(.out)) 98 | .complete { 99 | imageView.removeFromSuperview() 100 | } 101 | .start() 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Views/TweenControlsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TweenControlsView.swift 3 | // TweenApp 4 | // 5 | // Created by RF on 10/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Ubergang 11 | 12 | class TweenControlsView: UIView { 13 | enum PlayState { 14 | case stopped 15 | case playing 16 | case pausing 17 | } 18 | 19 | class func instanceFromNib() -> TweenControlsView { 20 | return UINib(nibName: "TweenControls", bundle: nil).instantiate(withOwner: self, options: nil)[0] as! TweenControlsView 21 | } 22 | @IBOutlet var playPauseButton: UIButton! 23 | 24 | @IBOutlet var stopButton: UIButton! 25 | 26 | @IBOutlet var directionButton: UIButton! 27 | 28 | @IBOutlet var progressSlider: UISlider! 29 | 30 | var onPlay: (() -> Void)? 31 | var onStop: (() -> Void)? 32 | var onPause: (() -> Void)? 33 | var onResume: (() -> Void)? 34 | var onDirection: ((_ direction: TweenDirection) -> Void)? 35 | var onProgress: ((_ value: Double) -> Void)? 36 | 37 | var playState: PlayState = .stopped 38 | 39 | var currentDerection: TweenDirection = .forward 40 | 41 | override func awakeFromNib() { 42 | setup() 43 | } 44 | 45 | func setup() { 46 | playPauseButton.addTarget(self, action: #selector(TweenControlsView.playPauseResume), for: .touchUpInside) 47 | stopButton.addTarget(self, action: #selector(TweenControlsView.stop), for: .touchUpInside) 48 | directionButton.addTarget(self, action: #selector(TweenControlsView.toggleDirection), for: .touchUpInside) 49 | 50 | progressSlider.addTarget(self, action: #selector(TweenControlsView.sliderValueChanged(_:)), for: .valueChanged) 51 | 52 | progressSlider.setThumbImage(UIImage(named: "SliderThumb"), for: UIControl.State()) 53 | progressSlider.setThumbImage(UIImage(named: "SliderThumb"), for: .highlighted) 54 | 55 | progress(0) 56 | } 57 | 58 | override func didMoveToSuperview() { 59 | guard let _ = superview else { 60 | return 61 | } 62 | 63 | translatesAutoresizingMaskIntoConstraints = false 64 | var constraints = [NSLayoutConstraint]() 65 | 66 | let views = ["v": self] 67 | 68 | let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[v]-0-|", options: [], metrics: nil, views: views) 69 | constraints.append(contentsOf: horizontalConstraints) 70 | 71 | let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[v(64)]-16-|", options: [], metrics: nil, views: views) 72 | constraints.append(contentsOf: verticalConstraints) 73 | 74 | NSLayoutConstraint.activate(constraints) 75 | } 76 | 77 | @objc func playPauseResume() { 78 | switch playState { 79 | case .stopped: 80 | playState = .playing 81 | playPauseButton.isSelected = true 82 | 83 | onPlay?() 84 | break 85 | case .playing: 86 | playState = .pausing 87 | playPauseButton.isSelected = false 88 | 89 | onPause?() 90 | break 91 | case .pausing: 92 | playState = .playing 93 | playPauseButton.isSelected = true 94 | 95 | onResume?() 96 | break 97 | } 98 | } 99 | 100 | @objc func stop() { 101 | playState = .stopped 102 | playPauseButton.isSelected = false 103 | 104 | onStop?() 105 | } 106 | 107 | func pause() { 108 | onPause?() 109 | } 110 | 111 | func resume() { 112 | onResume?() 113 | } 114 | 115 | @objc func toggleDirection() { 116 | switch currentDerection { 117 | case .forward: 118 | currentDerection = .reverse 119 | directionButton.isSelected = true 120 | case .reverse: 121 | currentDerection = .forward 122 | directionButton.isSelected = false 123 | default: break 124 | } 125 | 126 | onDirection?(currentDerection) 127 | } 128 | 129 | @objc func sliderValueChanged(_ sender: UISlider?) { 130 | onProgress?(Double(sender!.value)) 131 | } 132 | 133 | func progress(_ value: Double) { 134 | progressSlider.value = Float(value) 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Examples/TweenApp/TweenApp/Views/TweenStatusView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TweenStatusView.swift 3 | // TweenApp 4 | // 5 | // Created by Robin Frielingsdorf on 17/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TweenStatusView: UIView { 12 | 13 | @IBOutlet var titleLabel: UILabel! 14 | @IBOutlet var progressBar: UIProgressView! 15 | @IBOutlet var progressBarTotal: UIProgressView! 16 | @IBOutlet var repeatCountLabel: UILabel! 17 | 18 | var title: String = "Tween" { 19 | didSet { 20 | titleLabel.text = title 21 | } 22 | } 23 | 24 | var progress: Float = 0 { 25 | didSet { 26 | progressBar.progress = progress 27 | } 28 | } 29 | 30 | var progressTotal: Float = 0 { 31 | didSet { 32 | progressBarTotal.progress = progressTotal 33 | } 34 | } 35 | 36 | var repeatCount: Int = 0 { 37 | didSet { 38 | repeatCountLabel.text = "\(repeatCount)" 39 | } 40 | } 41 | 42 | 43 | init() { 44 | super.init(frame: CGRect.zero) 45 | setup() 46 | } 47 | 48 | required init?(coder aDecoder: NSCoder) { 49 | super.init(coder: aDecoder) 50 | setup() 51 | } 52 | 53 | fileprivate func setup() { 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Framework/Ubergang.framework/Headers/Ubergang-Swift.h: -------------------------------------------------------------------------------- 1 | // Generated by Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29) 2 | #pragma clang diagnostic push 3 | 4 | #if defined(__has_include) && __has_include() 5 | # include 6 | #endif 7 | 8 | #pragma clang diagnostic ignored "-Wauto-import" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #if !defined(SWIFT_TYPEDEFS) 15 | # define SWIFT_TYPEDEFS 1 16 | # if defined(__has_include) && __has_include() 17 | # include 18 | # elif !defined(__cplusplus) || __cplusplus < 201103L 19 | typedef uint_least16_t char16_t; 20 | typedef uint_least32_t char32_t; 21 | # endif 22 | typedef float swift_float2 __attribute__((__ext_vector_type__(2))); 23 | typedef float swift_float3 __attribute__((__ext_vector_type__(3))); 24 | typedef float swift_float4 __attribute__((__ext_vector_type__(4))); 25 | typedef double swift_double2 __attribute__((__ext_vector_type__(2))); 26 | typedef double swift_double3 __attribute__((__ext_vector_type__(3))); 27 | typedef double swift_double4 __attribute__((__ext_vector_type__(4))); 28 | typedef int swift_int2 __attribute__((__ext_vector_type__(2))); 29 | typedef int swift_int3 __attribute__((__ext_vector_type__(3))); 30 | typedef int swift_int4 __attribute__((__ext_vector_type__(4))); 31 | #endif 32 | 33 | #if !defined(SWIFT_PASTE) 34 | # define SWIFT_PASTE_HELPER(x, y) x##y 35 | # define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) 36 | #endif 37 | #if !defined(SWIFT_METATYPE) 38 | # define SWIFT_METATYPE(X) Class 39 | #endif 40 | 41 | #if defined(__has_attribute) && __has_attribute(objc_runtime_name) 42 | # define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) 43 | #else 44 | # define SWIFT_RUNTIME_NAME(X) 45 | #endif 46 | #if defined(__has_attribute) && __has_attribute(swift_name) 47 | # define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) 48 | #else 49 | # define SWIFT_COMPILE_NAME(X) 50 | #endif 51 | #if !defined(SWIFT_CLASS_EXTRA) 52 | # define SWIFT_CLASS_EXTRA 53 | #endif 54 | #if !defined(SWIFT_PROTOCOL_EXTRA) 55 | # define SWIFT_PROTOCOL_EXTRA 56 | #endif 57 | #if !defined(SWIFT_ENUM_EXTRA) 58 | # define SWIFT_ENUM_EXTRA 59 | #endif 60 | #if !defined(SWIFT_CLASS) 61 | # if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted) 62 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA 63 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 64 | # else 65 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 66 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 67 | # endif 68 | #endif 69 | 70 | #if !defined(SWIFT_PROTOCOL) 71 | # define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 72 | # define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 73 | #endif 74 | 75 | #if !defined(SWIFT_EXTENSION) 76 | # define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) 77 | #endif 78 | 79 | #if !defined(OBJC_DESIGNATED_INITIALIZER) 80 | # if defined(__has_attribute) && __has_attribute(objc_designated_initializer) 81 | # define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) 82 | # else 83 | # define OBJC_DESIGNATED_INITIALIZER 84 | # endif 85 | #endif 86 | #if !defined(SWIFT_ENUM) 87 | # define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_EXTRA _name : _type 88 | # if defined(__has_feature) && __has_feature(generalized_swift_name) 89 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type 90 | # else 91 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name) 92 | # endif 93 | #endif 94 | #if defined(__has_feature) && __has_feature(modules) 95 | @import ObjectiveC; 96 | #endif 97 | 98 | #pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" 99 | #pragma clang diagnostic ignored "-Wduplicate-method-arg" 100 | 101 | SWIFT_CLASS("_TtC8Ubergang6Engine") 102 | @interface Engine : NSObject 103 | + (Engine * _Nonnull)instance; 104 | + (void)setInstance:(Engine * _Nonnull)value; 105 | - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; 106 | @end 107 | 108 | #pragma clang diagnostic pop 109 | -------------------------------------------------------------------------------- /Framework/Ubergang.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Framework/Ubergang.framework/Info.plist -------------------------------------------------------------------------------- /Framework/Ubergang.framework/Modules/Ubergang.swiftmodule/x86_64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Framework/Ubergang.framework/Modules/Ubergang.swiftmodule/x86_64.swiftdoc -------------------------------------------------------------------------------- /Framework/Ubergang.framework/Modules/Ubergang.swiftmodule/x86_64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Framework/Ubergang.framework/Modules/Ubergang.swiftmodule/x86_64.swiftmodule -------------------------------------------------------------------------------- /Framework/Ubergang.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module Ubergang { 2 | header "Ubergang-Swift.h" 3 | } 4 | -------------------------------------------------------------------------------- /Framework/Ubergang.framework/Ubergang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Framework/Ubergang.framework/Ubergang -------------------------------------------------------------------------------- /Movies/exampleConstraints.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Movies/exampleConstraints.gif -------------------------------------------------------------------------------- /Movies/exampleConstraints.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Movies/exampleConstraints.mov -------------------------------------------------------------------------------- /Movies/exampleDynamic.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Movies/exampleDynamic.mov -------------------------------------------------------------------------------- /Movies/examplePath.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Movies/examplePath.gif -------------------------------------------------------------------------------- /Movies/examplePath.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Movies/examplePath.mov -------------------------------------------------------------------------------- /Movies/exampleTimeline.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Movies/exampleTimeline.gif -------------------------------------------------------------------------------- /Movies/exampleTimeline.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Movies/exampleTimeline.mov -------------------------------------------------------------------------------- /Ubergang-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Ubergang-Bridging-Header.h 3 | // Ubergang 4 | // 5 | // Created by RF on 23/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | #ifndef Ubergang_Bridging_Header_h 10 | #define Ubergang_Bridging_Header_h 11 | 12 | #import "UIBezierPath+Interpolation.h" 13 | 14 | #endif /* Ubergang_Bridging_Header_h */ 15 | -------------------------------------------------------------------------------- /Ubergang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinFalko/Ubergang/4f61d0677e96dcd724f06f5765816bbfc2732ece/Ubergang.png -------------------------------------------------------------------------------- /Ubergang.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'Ubergang' 3 | s.version = '1.2.0' 4 | s.summary = 'A tweening engine written in Swift.' 5 | s.homepage = 'https://github.com/RobinFalko/Ubergang' 6 | s.license = { type: 'Apache', file: 'LICENSE' } 7 | s.authors = { 'Robin Frielingsdorf' => 'mail@robinfalko.com' } 8 | 9 | s.source = { :git => 'https://github.com/RobinFalko/Ubergang.git', :tag => s.version.to_s } 10 | s.source_files = 'Ubergang/**/*.{h,m,swift}' 11 | s.module_name = 'Ubergang' 12 | 13 | s.swift_version = '5.0' 14 | s.platform = :ios, '8.0' 15 | s.ios.deployment_target = '8.0' 16 | end 17 | -------------------------------------------------------------------------------- /Ubergang.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Ubergang.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Ubergang.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Ubergang.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Ubergang.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Ubergang/Core/Engine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Engine.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 09/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class Engine: NSObject { 13 | public typealias Closure = () -> Void 14 | 15 | fileprivate var displayLink: CADisplayLink? 16 | 17 | var closures = [String : Closure]() 18 | 19 | var mapTable = NSMapTable(keyOptions: NSPointerFunctions.Options.strongMemory, valueOptions: NSPointerFunctions.Options.weakMemory) 20 | 21 | public static var instance: Engine = { 22 | let engine = Engine() 23 | engine.start() 24 | return engine 25 | }() 26 | 27 | func start() { 28 | if displayLink == nil { 29 | displayLink = CADisplayLink(target: self, selector: #selector(Engine.update)) 30 | displayLink!.add(to: .current, forMode: .common) 31 | } 32 | } 33 | 34 | func stop() { 35 | displayLink?.remove(from: .current, forMode: .common) 36 | displayLink = nil 37 | } 38 | 39 | @objc func update() { 40 | let enumerator = mapTable.objectEnumerator() 41 | while let any: AnyObject = enumerator?.nextObject() as AnyObject? { 42 | if let loopable = any as? WeaklyLoopable { 43 | loopable.loopWeakly() 44 | } 45 | } 46 | 47 | for (_, closure) in closures { 48 | closure() 49 | } 50 | } 51 | 52 | 53 | func register(_ closure: @escaping Closure, forKey key: String) { 54 | closures[key] = closure 55 | 56 | start() 57 | } 58 | 59 | 60 | func register(_ loopable: WeaklyLoopable, forKey key: String) { 61 | mapTable.setObject(loopable as AnyObject?, forKey: key as AnyObject?) 62 | 63 | start() 64 | } 65 | 66 | 67 | func unregister(_ key: String) { 68 | mapTable.removeObject(forKey: key as AnyObject?) 69 | 70 | closures.removeValue(forKey: key) 71 | 72 | if mapTable.count == 0 && closures.isEmpty { 73 | stop() 74 | } 75 | } 76 | 77 | 78 | func contains(_ key: String) -> Bool { 79 | return mapTable.object(forKey: key as AnyObject?) != nil || closures[key] != nil 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Ubergang/Core/Timer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Timer.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Timer { 12 | public static let instance = Timer() 13 | 14 | fileprivate let id = "\(#file)_update" 15 | 16 | public static var delta:TimeInterval = TimeInterval(0) 17 | public static var time:TimeInterval = TimeInterval(0) 18 | fileprivate var lastUpdateTime:TimeInterval = TimeInterval(0) 19 | 20 | fileprivate init() {} 21 | 22 | func start() { 23 | self.lastUpdateTime = Date().timeIntervalSince1970 24 | 25 | Engine.instance.register(update, forKey: id) 26 | } 27 | 28 | 29 | func stop() { 30 | Engine.instance.unregister(id) 31 | } 32 | 33 | 34 | func update() { 35 | tick(Date().timeIntervalSince1970) 36 | } 37 | 38 | 39 | func tick(_ currentTime: TimeInterval) { 40 | if lastUpdateTime == 0.0 { 41 | Timer.delta = 0 42 | } else { 43 | Timer.delta = currentTime - self.lastUpdateTime 44 | } 45 | 46 | self.lastUpdateTime = Date().timeIntervalSince1970 47 | 48 | Timer.time += Timer.delta 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Ubergang/Core/UTweenSetup.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTweenSetup.swift 3 | // Ubergang 4 | // 5 | // Created by RF on 11/07/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class UTweenSetup { 12 | public static let instance = UTweenSetup() 13 | 14 | fileprivate var isLoggingEnabled = false 15 | 16 | internal lazy var logger: UTweenLoggable? = { 17 | guard UTweenSetup.instance.isLoggingEnabled else { return nil } 18 | return UTweenLogger() 19 | }() 20 | 21 | fileprivate init() {} 22 | 23 | open func enableLogging(_ enabled: Bool) { 24 | isLoggingEnabled = enabled 25 | } 26 | 27 | open func enableLogging(_ enabled: Bool, withLogger logger: UTweenLoggable) { 28 | enableLogging(enabled) 29 | self.logger = logger 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Ubergang/Data/TweenDirection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TweenDirection.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 10/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | // Picture: Timeline containing 3 tweens 10 | /* 11 | forward --> 12 | t0: |-----------------------| 13 | t1: |----------------------| 14 | t2: |--------| 15 | */ 16 | 17 | /* 18 | <-- reverse 19 | t0: |-----------------------| 20 | t1: |----------------------| 21 | t2: |--------| 22 | */ 23 | 24 | /* 25 | <-- backward 26 | t0: |-----------------------| 27 | t1: |----------------------| 28 | t2: |--------| 29 | */ 30 | 31 | public enum TweenDirection { 32 | case forward //play the tween from 0 to 1 33 | case reverse //play the tween from 1 to 0 without adjustments 34 | case backward //play the tween from 1 to 0, inverse easings, and tween start times 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /Ubergang/Data/TweenMemoryReference.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TweenMemoryReference.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/02/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public enum TweenMemoryReference { 10 | case weak, strong 11 | } 12 | -------------------------------------------------------------------------------- /Ubergang/Data/TweenOptions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TweenOptions.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 20/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public func ==(a: TweenOptions, b: TweenOptions) -> Bool { 10 | switch (a, b) { 11 | case (.yoyo, .yoyo): return true 12 | case (.repeat(let l), .repeat(let r)) where l == r: return true 13 | default: return false 14 | } 15 | } 16 | 17 | internal extension Sequence where Iterator.Element == TweenOptions { 18 | func repeatCount() -> Int { 19 | var repeatCount = 0 20 | self.forEach { 21 | if case .repeat(let count) = $0 { 22 | repeatCount = count 23 | } 24 | } 25 | 26 | return repeatCount 27 | } 28 | 29 | func containsRepeat() -> Bool { 30 | return repeatCount() > 0 31 | } 32 | 33 | func containsYoyo() -> Bool { 34 | return self.contains(.yoyo) 35 | } 36 | } 37 | 38 | public enum TweenOptions: Equatable { 39 | case yoyo 40 | case `repeat`(Int) 41 | } 42 | -------------------------------------------------------------------------------- /Ubergang/Ease/Back.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Back.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Back: Easing, CurveEasing { 12 | /** 13 | Back ease in. 14 | 15 | - Parameter t: The value to be mapped going from 0 to `d` 16 | - Parameter b: The mapped start value 17 | - Parameter c: The mapped end value 18 | - Parameter d: The end value 19 | - Returns: The mapped result 20 | */ 21 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 22 | var t = t 23 | let s = 1.70158 24 | t/=d 25 | let postFix = t 26 | return c*(postFix)*t*((s+1)*t - s) + b 27 | } 28 | 29 | /** 30 | Back ease out. 31 | 32 | - Parameter t: The value to be mapped going from 0 to `d` 33 | - Parameter b: The mapped start value 34 | - Parameter c: The mapped end value 35 | - Parameter d: The end value 36 | - Returns: The mapped result 37 | */ 38 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 39 | var t = t 40 | let s = 1.70158 41 | t=t/d-1 42 | let f = (s+1)*t + s 43 | return c*(t*t*f + 1) + b 44 | } 45 | 46 | /** 47 | Back ease in out. 48 | 49 | - Parameter t: The value to be mapped going from 0 to `d` 50 | - Parameter b: The mapped start value 51 | - Parameter c: The mapped end value 52 | - Parameter d: The end value 53 | - Returns: The mapped result 54 | */ 55 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 56 | var t = t 57 | var s = 1.70158 58 | t/=d/2 59 | if (t < 1) { s*=(1.525); return c/2*(t*t*(((s)+1)*t - s)) + b } 60 | t-=2 61 | let postFix = t 62 | s*=(1.525) 63 | let f = (s+1)*t + s 64 | return c/2*(postFix*t*f + 2) + b 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Ubergang/Ease/Bounce.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bounce.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Bounce: Easing, CurveEasing { 12 | 13 | /** 14 | Bounce ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | return c - easeOut (t: d-t, b: 0, c: c, d: d) + b 24 | } 25 | 26 | /** 27 | Bounce ease out. 28 | 29 | - Parameter t: The value to be mapped going from 0 to `d` 30 | - Parameter b: The mapped start value 31 | - Parameter c: The mapped end value 32 | - Parameter d: The end value 33 | - Returns: The mapped result 34 | */ 35 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 36 | var t = t 37 | t/=d 38 | if t < (1/2.75) { 39 | return c*(7.5625*t*t) + b 40 | } else if (t < (2/2.75)) { 41 | t-=(1.5/2.75) 42 | let postFix = t 43 | return c*(7.5625*(postFix)*t + 0.75) + b 44 | } else if (t < (2.5/2.75)) { 45 | t-=(2.25/2.75) 46 | let postFix = t 47 | return c*(7.5625*(postFix)*t + 0.9375) + b 48 | } else { 49 | t-=(2.625/2.75) 50 | let postFix = t 51 | return c*(7.5625*(postFix)*t + 0.984375) + b 52 | } 53 | } 54 | 55 | /** 56 | Bounce ease in out. 57 | 58 | - Parameter t: The value to be mapped going from 0 to `d` 59 | - Parameter b: The mapped start value 60 | - Parameter c: The mapped end value 61 | - Parameter d: The end value 62 | - Returns: The mapped result 63 | */ 64 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 65 | if (t < d/2) { return easeIn (t: t*2, b: 0, c: c, d: d) * 0.5 + b } 66 | else { return easeOut (t: t*2-d, b: 0, c: c, d: d) * 0.5 + c*0.5 + b } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Ubergang/Ease/Circ.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Circ.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Circ: Easing, CurveEasing { 12 | 13 | /** 14 | Circ ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t/=d 25 | return -c * (sqrt(1 - (t)*t) - 1) + b 26 | } 27 | 28 | /** 29 | Circ ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t=t/d-1 40 | return c * sqrt(1 - (t)*t) + b 41 | } 42 | 43 | /** 44 | Circ ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t/=d/2 55 | if ((t) < 1) { return -c/2 * (sqrt(1 - t*t) - 1) + b } 56 | t-=2 57 | return c/2 * (sqrt(1 - t*(t)) + 1) + b 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Ubergang/Ease/Cubic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Cubic.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Cubic: Easing, CurveEasing { 12 | 13 | /** 14 | Cubic ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t = t/d 25 | return c*t*t*t + b 26 | } 27 | 28 | /** 29 | Cubic ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t = t/d-1 40 | return c*(t*t*t + 1) + b 41 | } 42 | 43 | /** 44 | Cubic ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t = t/(d/2) 55 | if t < 1 { 56 | return c/2*t*t*t + b 57 | } 58 | 59 | t = t-2 60 | return c/2*(t*t*t + 2) + b; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Ubergang/Ease/Ease.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Ease.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public enum Ease { 10 | case linear 11 | case back(_ type: EaseType) 12 | case bounce(_ type: EaseType) 13 | case circ(_ type: EaseType) 14 | case cubic(_ type: EaseType) 15 | case elastic(_ type: EaseType) 16 | case expo(_ type: EaseType) 17 | case quad(_ type: EaseType) 18 | case quart(_ type: EaseType) 19 | case quint(_ type: EaseType) 20 | case sine(_ type: EaseType) 21 | 22 | var function: (_ t: Double, _ b: Double, _ c: Double, _ d: Double) -> Double { 23 | switch self { 24 | case .linear: return Linear.ease 25 | case let .back(type): return type.function(for: Back.self) 26 | case let .bounce(type): return type.function(for: Bounce.self) 27 | case let .circ(type): return type.function(for: Circ.self) 28 | case let .cubic(type): return type.function(for: Cubic.self) 29 | case let .elastic(type): return type.function(for: Elastic.self) 30 | case let .expo(type): return type.function(for: Expo.self) 31 | case let .quad(type): return type.function(for: Quad.self) 32 | case let .quart(type): return type.function(for: Quart.self) 33 | case let .quint(type): return type.function(for: Quint.self) 34 | case let .sine(type): return type.function(for: Sine.self) 35 | } 36 | } 37 | 38 | var opposite: Ease { 39 | switch self { 40 | case .linear: return self 41 | case let .back(type): return .back(type.opposite()) 42 | case let .bounce(type): return .bounce(type.opposite()) 43 | case let .circ(type): return .circ(type.opposite()) 44 | case let .cubic(type): return .cubic(type.opposite()) 45 | case let .elastic(type): return .elastic(type.opposite()) 46 | case let .expo(type): return .expo(type.opposite()) 47 | case let .quad(type): return .quad(type.opposite()) 48 | case let .quart(type): return .quart(type.opposite()) 49 | case let .quint(type): return .quint(type.opposite()) 50 | case let .sine(type): return .sine(type.opposite()) 51 | } 52 | } 53 | } 54 | 55 | public enum EaseType { 56 | case `in`, out, inOut 57 | 58 | internal func function(for easing: CurveEasing.Type) -> (_ t: Double, _ b: Double, _ c: Double, _ d: Double) -> Double { 59 | switch self { 60 | case .in: return easing.easeIn 61 | case .out: return easing.easeOut 62 | case .inOut: return easing.easeInOut 63 | } 64 | } 65 | 66 | internal func opposite() -> EaseType { 67 | switch self { 68 | case .in: return .out 69 | case .out: return .in 70 | case .inOut: return self 71 | } 72 | } 73 | } 74 | 75 | public protocol CurveEasing { 76 | static func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double 77 | static func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double 78 | static func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double 79 | } 80 | 81 | open class Easing {} 82 | -------------------------------------------------------------------------------- /Ubergang/Ease/Elastic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Elastic.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 10/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Elastic: Easing, CurveEasing { 12 | 13 | /** 14 | Elastic ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | if t == 0 { 25 | return b 26 | } 27 | 28 | t = t / d 29 | if t == 1 { 30 | return b+c 31 | } 32 | 33 | let p = d * 0.3 34 | let a = c 35 | let s = p / 4 36 | t = t - 1 37 | 38 | let postFix = a * pow(2.0, 10.0 * t) // this is a fix, again, with post-increment operators 39 | 40 | return -(postFix * sin((t*d-s) * (2 * .pi)/p )) + b 41 | } 42 | 43 | /** 44 | Elastic ease out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | if t == 0 { 55 | return b 56 | } 57 | 58 | t = t / d 59 | if t == 1 { 60 | return b+c 61 | } 62 | 63 | let p = d * 0.3 64 | let a = c 65 | let s = p / 4 66 | 67 | return (a * pow(2, -10 * t) * sin( (t*d-s) * (2 * .pi)/p ) + c + b) 68 | } 69 | 70 | /** 71 | Elastic ease in out. 72 | 73 | - Parameter t: The value to be mapped going from 0 to `d` 74 | - Parameter b: The mapped start value 75 | - Parameter c: The mapped end value 76 | - Parameter d: The end value 77 | - Returns: The mapped result 78 | */ 79 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 80 | var t = t 81 | if t == 0 { 82 | return b 83 | } 84 | 85 | t = t / (d / 2) 86 | if t == 2 { 87 | return b+c 88 | } 89 | 90 | let p = d * (0.3*1.5) 91 | let a = c 92 | let s = p / 4 93 | 94 | t = t - 1 95 | 96 | if (t < 1) { 97 | let postFix = a * pow(2.0, 10.0 * t) // postIncrement is evil 98 | return -0.5 * (postFix * sin((t*d-s) * (2 * .pi)/p)) + b 99 | } 100 | 101 | let postFix = a * pow(2.0, -10.0 * t) // postIncrement is evil 102 | return postFix * sin((t*d-s) * (2 * .pi) / p) * 0.5 + c + b 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Ubergang/Ease/Expo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Expo.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Expo: Easing, CurveEasing { 12 | 13 | /** 14 | Expo ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | return (t==0) ? b : c * pow(2, 10 * (t/d - 1)) + b 24 | } 25 | 26 | /** 27 | Circ ease out. 28 | 29 | - Parameter t: The value to be mapped going from 0 to `d` 30 | - Parameter b: The mapped start value 31 | - Parameter c: The mapped end value 32 | - Parameter d: The end value 33 | - Returns: The mapped result 34 | */ 35 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 36 | return (t==d) ? b+c : c * (-pow(2, -10 * t/d) + 1) + b 37 | } 38 | 39 | /** 40 | Circ ease in out. 41 | 42 | - Parameter t: The value to be mapped going from 0 to `d` 43 | - Parameter b: The mapped start value 44 | - Parameter c: The mapped end value 45 | - Parameter d: The end value 46 | - Returns: The mapped result 47 | */ 48 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 49 | var t = t 50 | if (t==0) { return b } 51 | if (t==d) { return b+c } 52 | t/=d/2 53 | if ((t) < 1) { return c/2 * pow(2, 10 * (t - 1)) + b } 54 | t-=1 55 | return c/2 * (-pow(2, -10 * t) + 2) + b 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Ubergang/Ease/Linear.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Linear.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Linear: Easing { 12 | 13 | /** 14 | Linear ease. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func ease(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | return c * t / d + b 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Ubergang/Ease/Quad.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quad.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Quad: Easing, CurveEasing { 12 | 13 | /** 14 | Quad ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t/=d 25 | return c*(t)*t + b 26 | } 27 | 28 | /** 29 | Quad ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t/=d 40 | return -c*(t)*(t-2) + b 41 | } 42 | 43 | /** 44 | Quad ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t/=d/2 55 | if ((t) < 1) { return ((c/2)*(t*t)) + b } 56 | let t2 = t-1 57 | return -c/2 * (((t-2)*(t2)) - 1) + b 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Ubergang/Ease/Quart.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quart.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Quart: Easing, CurveEasing { 12 | 13 | /** 14 | Quart ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t/=d 25 | return c*(t)*t*t*t + b 26 | } 27 | 28 | /** 29 | Quart ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t=t/d-1 40 | return -c * ((t)*t*t*t - 1) + b 41 | } 42 | 43 | /** 44 | Quart ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t/=d/2 55 | if ((t) < 1) { return c/2*t*t*t*t + b } 56 | t-=2 57 | return -c/2 * ((t)*t*t*t - 2) + b 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Ubergang/Ease/Quint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quint.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Quint: Easing, CurveEasing { 12 | 13 | /** 14 | Quint ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | var t = t 24 | t/=d 25 | return c*(t)*t*t*t*t + b 26 | } 27 | 28 | /** 29 | Quint ease out. 30 | 31 | - Parameter t: The value to be mapped going from 0 to `d` 32 | - Parameter b: The mapped start value 33 | - Parameter c: The mapped end value 34 | - Parameter d: The end value 35 | - Returns: The mapped result 36 | */ 37 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 38 | var t = t 39 | t=t/d-1 40 | return c*((t)*t*t*t*t + 1) + b 41 | } 42 | 43 | /** 44 | Quint ease in out. 45 | 46 | - Parameter t: The value to be mapped going from 0 to `d` 47 | - Parameter b: The mapped start value 48 | - Parameter c: The mapped end value 49 | - Parameter d: The end value 50 | - Returns: The mapped result 51 | */ 52 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 53 | var t = t 54 | t/=d/2 55 | if ((t) < 1) { return c/2*t*t*t*t*t + b } 56 | t-=2 57 | return c/2*((t)*t*t*t*t + 2) + b 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Ubergang/Ease/Sine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sine.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class Sine: Easing, CurveEasing { 12 | 13 | /** 14 | Sine ease in. 15 | 16 | - Parameter t: The value to be mapped going from 0 to `d` 17 | - Parameter b: The mapped start value 18 | - Parameter c: The mapped end value 19 | - Parameter d: The end value 20 | - Returns: The mapped result 21 | */ 22 | open class func easeIn(t: Double, b: Double, c: Double, d: Double) -> Double { 23 | return -c * cos(t/d * (.pi/2)) + c + b 24 | } 25 | 26 | /** 27 | Sine ease out. 28 | 29 | - Parameter t: The value to be mapped going from 0 to `d` 30 | - Parameter b: The mapped start value 31 | - Parameter c: The mapped end value 32 | - Parameter d: The end value 33 | - Returns: The mapped result 34 | */ 35 | open class func easeOut(t: Double, b: Double, c: Double, d: Double) -> Double { 36 | return c * sin(t/d * (.pi/2)) + b 37 | } 38 | 39 | /** 40 | Sine ease in out. 41 | 42 | - Parameter t: The value to be mapped going from 0 to `d` 43 | - Parameter b: The mapped start value 44 | - Parameter c: The mapped end value 45 | - Parameter d: The end value 46 | - Returns: The mapped result 47 | */ 48 | open class func easeInOut(t: Double, b: Double, c: Double, d: Double) -> Double { 49 | return -c/2 * (cos(.pi*t/d) - 1) + b 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Ubergang/Extension/CGPath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPath.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 19/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension CGPath { 12 | func forEach(_ body: @escaping @convention(block) (CGPathElement) -> Void) { 13 | typealias Body = @convention(block) (CGPathElement) -> Void 14 | func callback(_ info: UnsafeMutableRawPointer?, element: UnsafePointer) { 15 | let body = unsafeBitCast(info, to: Body.self) 16 | body(element.pointee) 17 | } 18 | let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self) 19 | self.apply(info: unsafeBody, function: callback) 20 | } 21 | 22 | func getElements() -> [(type: CGPathElementType, points: [CGPoint])] { 23 | var result = [(type: CGPathElementType, points: [CGPoint])]() 24 | var elementType: CGPathElementType! 25 | var points: [CGPoint]! 26 | var firstPoint: CGPoint! 27 | var previousLastPoint: CGPoint! 28 | forEach { element in 29 | switch (element.type) { 30 | case CGPathElementType.moveToPoint: 31 | firstPoint = element.points[0] 32 | previousLastPoint = firstPoint 33 | case .addLineToPoint: 34 | points = [CGPoint]() 35 | elementType = element.type 36 | points.append(previousLastPoint) 37 | points.append(element.points[0]) 38 | result.append((elementType, points)) 39 | 40 | previousLastPoint = element.points[0] 41 | case .addQuadCurveToPoint: 42 | points = [CGPoint]() 43 | elementType = element.type 44 | points.append(previousLastPoint) 45 | points.append(element.points[0]) 46 | points.append(element.points[1]) 47 | result.append((elementType, points)) 48 | 49 | previousLastPoint = element.points[1] 50 | case .addCurveToPoint: 51 | points = [CGPoint]() 52 | elementType = element.type 53 | points.append(previousLastPoint) 54 | points.append(element.points[0]) 55 | points.append(element.points[1]) 56 | points.append(element.points[2]) 57 | result.append((elementType, points)) 58 | 59 | previousLastPoint = element.points[2] 60 | case .closeSubpath: 61 | points = [CGPoint]() 62 | elementType = element.type 63 | points.append(previousLastPoint) 64 | points.append(firstPoint) 65 | result.append((elementType, points)) 66 | @unknown default: 67 | break 68 | } 69 | } 70 | 71 | return result 72 | } 73 | 74 | func getElement(_ index: Int) -> (type: CGPathElementType, points: [CGPoint])? { 75 | let elements = getElements() 76 | if index >= elements.count { 77 | return nil 78 | } 79 | return elements[index] 80 | } 81 | 82 | func elementCount() -> Int { 83 | var count = 0 84 | self.forEach { element in 85 | if element.type != .moveToPoint && element.type != .closeSubpath { 86 | count += 1 87 | } 88 | } 89 | return count 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Ubergang/Extension/UIBezierPath+Interpolation.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIBezierPath+Interpolation.h 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | // Source: https://github.com/jnfisher/ios-curve-interpolation 9 | 10 | #import 11 | 12 | @interface UIBezierPath (Interpolation) 13 | 14 | // pointsAsNSValues must be NSValue objects containing CGPoints. 15 | // 16 | // ex: 17 | // const char *encoding = @encode(CGPoint); 18 | // NSValue *pointAsValue = [NSValue valueWithBytes:&cgPoint objCType:encoding]; 19 | 20 | // 0.0 <= alpha <= 1.0 21 | +(UIBezierPath *)interpolateCGPointsWithCatmullRom:(NSArray *)pointsAsNSValues closed:(BOOL)closed alpha:(float)alpha; 22 | +(UIBezierPath *)interpolateCGPointsWithHermite:(NSArray *)pointsAsNSValues closed:(BOOL)closed; 23 | @end -------------------------------------------------------------------------------- /Ubergang/Extension/UIBezierPath+Interpolation.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIBezierPath+Interpolation.m 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | // Source: https://github.com/jnfisher/ios-curve-interpolation 9 | 10 | #import "UIBezierPath+Interpolation.h" 11 | #import "CGPointExtension.h" 12 | 13 | #define kEPSILON 1.0e-5 14 | 15 | @implementation UIBezierPath (Interpolation) 16 | 17 | +(UIBezierPath *)interpolateCGPointsWithCatmullRom:(NSArray *)pointsAsNSValues closed:(BOOL)closed alpha:(float)alpha { 18 | if ([pointsAsNSValues count] < 4) 19 | return nil; 20 | 21 | NSInteger endIndex = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-2); 22 | NSAssert(alpha >= 0.0 && alpha <= 1.0, @"alpha value is between 0.0 and 1.0, inclusive"); 23 | 24 | UIBezierPath *path = [UIBezierPath bezierPath]; 25 | NSInteger startIndex = (closed ? 0 : 1); 26 | for (NSInteger ii=startIndex; ii < endIndex; ++ii) { 27 | CGPoint p0, p1, p2, p3; 28 | NSInteger nextii = (ii+1)%[pointsAsNSValues count]; 29 | NSInteger nextnextii = (nextii+1)%[pointsAsNSValues count]; 30 | NSInteger previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1); 31 | 32 | [pointsAsNSValues[ii] getValue:&p1]; 33 | [pointsAsNSValues[previi] getValue:&p0]; 34 | [pointsAsNSValues[nextii] getValue:&p2]; 35 | [pointsAsNSValues[nextnextii] getValue:&p3]; 36 | 37 | CGFloat d1 = ccpLength(ccpSub(p1, p0)); 38 | CGFloat d2 = ccpLength(ccpSub(p2, p1)); 39 | CGFloat d3 = ccpLength(ccpSub(p3, p2)); 40 | 41 | CGPoint b1, b2; 42 | if (fabs(d1) < kEPSILON) { 43 | b1 = p1; 44 | } 45 | else { 46 | b1 = ccpMult(p2, powf(d1, 2*alpha)); 47 | b1 = ccpSub(b1, ccpMult(p0, powf(d2, 2*alpha))); 48 | b1 = ccpAdd(b1, ccpMult(p1,(2*powf(d1, 2*alpha) + 3*powf(d1, alpha)*powf(d2, alpha) + powf(d2, 2*alpha)))); 49 | b1 = ccpMult(b1, 1.0 / (3*powf(d1, alpha)*(powf(d1, alpha)+powf(d2, alpha)))); 50 | } 51 | 52 | if (fabs(d3) < kEPSILON) { 53 | b2 = p2; 54 | } 55 | else { 56 | b2 = ccpMult(p1, powf(d3, 2*alpha)); 57 | b2 = ccpSub(b2, ccpMult(p3, powf(d2, 2*alpha))); 58 | b2 = ccpAdd(b2, ccpMult(p2,(2*powf(d3, 2*alpha) + 3*powf(d3, alpha)*powf(d2, alpha) + powf(d2, 2*alpha)))); 59 | b2 = ccpMult(b2, 1.0 / (3*powf(d3, alpha)*(powf(d3, alpha)+powf(d2, alpha)))); 60 | } 61 | 62 | if (ii==startIndex) 63 | [path moveToPoint:p1]; 64 | 65 | [path addCurveToPoint:p2 controlPoint1:b1 controlPoint2:b2]; 66 | } 67 | 68 | if (closed) 69 | [path closePath]; 70 | 71 | return path; 72 | } 73 | 74 | +(UIBezierPath *)interpolateCGPointsWithHermite:(NSArray *)pointsAsNSValues closed:(BOOL)closed { 75 | if ([pointsAsNSValues count] < 2) 76 | return nil; 77 | 78 | NSInteger nCurves = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-1); 79 | 80 | UIBezierPath *path = [UIBezierPath bezierPath]; 81 | for (NSInteger ii=0; ii < nCurves; ++ii) { 82 | NSValue *value = pointsAsNSValues[ii]; 83 | 84 | CGPoint curPt, prevPt, nextPt, endPt; 85 | [value getValue:&curPt]; 86 | if (ii==0) 87 | [path moveToPoint:curPt]; 88 | 89 | NSInteger nextii = (ii+1)%[pointsAsNSValues count]; 90 | NSInteger previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1); 91 | 92 | [pointsAsNSValues[previi] getValue:&prevPt]; 93 | [pointsAsNSValues[nextii] getValue:&nextPt]; 94 | endPt = nextPt; 95 | 96 | CGFloat mx, my; 97 | if (closed || ii > 0) { 98 | mx = (nextPt.x - curPt.x)*0.5 + (curPt.x - prevPt.x)*0.5; 99 | my = (nextPt.y - curPt.y)*0.5 + (curPt.y - prevPt.y)*0.5; 100 | } 101 | else { 102 | mx = (nextPt.x - curPt.x)*0.5; 103 | my = (nextPt.y - curPt.y)*0.5; 104 | } 105 | 106 | CGPoint ctrlPt1; 107 | ctrlPt1.x = curPt.x + mx / 3.0; 108 | ctrlPt1.y = curPt.y + my / 3.0; 109 | 110 | [pointsAsNSValues[nextii] getValue:&curPt]; 111 | 112 | nextii = (nextii+1)%[pointsAsNSValues count]; 113 | previi = ii; 114 | 115 | [pointsAsNSValues[previi] getValue:&prevPt]; 116 | [pointsAsNSValues[nextii] getValue:&nextPt]; 117 | 118 | if (closed || ii < nCurves-1) { 119 | mx = (nextPt.x - curPt.x)*0.5 + (curPt.x - prevPt.x)*0.5; 120 | my = (nextPt.y - curPt.y)*0.5 + (curPt.y - prevPt.y)*0.5; 121 | } 122 | else { 123 | mx = (curPt.x - prevPt.x)*0.5; 124 | my = (curPt.y - prevPt.y)*0.5; 125 | } 126 | 127 | CGPoint ctrlPt2; 128 | ctrlPt2.x = curPt.x - mx / 3.0; 129 | ctrlPt2.y = curPt.y - my / 3.0; 130 | 131 | [path addCurveToPoint:endPt controlPoint1:ctrlPt1 controlPoint2:ctrlPt2]; 132 | } 133 | 134 | if (closed) 135 | [path closePath]; 136 | 137 | return path; 138 | } 139 | 140 | 141 | @end -------------------------------------------------------------------------------- /Ubergang/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Ubergang/Protocols/Numeric.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Computable.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol Numeric { 12 | init() 13 | init(_ value: Int) 14 | init(_ value: Double) 15 | init(_ value: Float) 16 | 17 | static func + (lhs: Self, rhs: Self) -> Self 18 | static func - (lhs: Self, rhs: Self) -> Self 19 | static func * (lhs: Self, rhs: Self) -> Self 20 | static func / (lhs: Self, rhs: Self) -> Self 21 | } 22 | 23 | extension Double : Numeric { 24 | public init?(_ value: T) { 25 | switch (value) { 26 | case is Int: 27 | self.init(Double(value as! Int)) 28 | break 29 | case is Int8: 30 | self.init(Double(value as! Int8)) 31 | break 32 | case is Int16: 33 | self.init(Double(value as! Int16)) 34 | break 35 | case is Int32: 36 | self.init(Double(value as! Int32)) 37 | break 38 | case is Int64: 39 | self.init(Double(value as! Int64)) 40 | break 41 | case is Float: 42 | self.init(Double(value as! Float)) 43 | break 44 | case is CGFloat: 45 | self.init(Double(value as! CGFloat)) 46 | break 47 | case is Double: 48 | fallthrough 49 | default: 50 | return nil 51 | } 52 | } 53 | } 54 | extension Float : Numeric {} 55 | extension Int : Numeric {} 56 | extension Int8 : Numeric {} 57 | extension Int16 : Numeric {} 58 | extension Int32 : Numeric {} 59 | extension Int64 : Numeric {} 60 | extension UInt : Numeric {} 61 | extension UInt8 : Numeric {} 62 | extension UInt16 : Numeric {} 63 | extension UInt32 : Numeric {} 64 | extension UInt64 : Numeric {} 65 | extension CGFloat: Numeric {} 66 | -------------------------------------------------------------------------------- /Ubergang/Protocols/Tweenable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tweenable.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 05/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public protocol Tweenable { 10 | var id: String { get } 11 | var duration: Double { get set } 12 | var progress: Double { get set } 13 | 14 | func start() -> Self 15 | func stop() 16 | func pause() 17 | func resume() 18 | func kill() 19 | } -------------------------------------------------------------------------------- /Ubergang/Protocols/TypeTweenable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tween.swift 3 | // Ubergang 4 | // 5 | // Created by RF on 06.08.17. 6 | // Copyright © 2017 Robin Falko. All rights reserved. 7 | // 8 | 9 | // Not sure why this won't work. 10 | // Use repetitive code in extensions instead 11 | //public protocol GenericTweenable { 12 | // associatedtype TweenType: UTween 13 | // func tween(to: Self) -> TweenType 14 | //} 15 | // 16 | //public extension GenericTweenable { 17 | // func tween(to: Self) -> TweenType { 18 | // return TweenType().tween(from: self, to: to) 19 | // } 20 | //} 21 | //extension CGPoint: GenericTweenable {typealias TweenType = CGPointTween} 22 | //extension UIColor: GenericTweenable {typealias TweenType = ColorTween} 23 | //extension CGAffineTransform: Generic     Tweenable {typealias TweenType = TransformTween} 24 | 25 | public extension CGPoint { 26 | func tween(to: CGPoint) -> CGPointTween { 27 | return CGPointTween().from(self, to: to) 28 | } 29 | } 30 | 31 | public extension UIColor { 32 | func tween(to: UIColor) -> ColorTween { 33 | return ColorTween().from(self, to: to) 34 | } 35 | } 36 | 37 | public extension CGAffineTransform { 38 | func tween(to: CGAffineTransform) -> TransformTween { 39 | return TransformTween().from(self, to: to) 40 | } 41 | } 42 | 43 | public protocol NumericTweenable: Numeric { 44 | func tween(to: Self) -> NumericTween 45 | } 46 | 47 | public extension NumericTweenable { 48 | func tween(to: Self) -> NumericTween { 49 | return NumericTween().from(self, to: to) 50 | } 51 | } 52 | 53 | extension Double : NumericTweenable {} 54 | extension Float : NumericTweenable {} 55 | extension Int : NumericTweenable {} 56 | extension Int8 : NumericTweenable {} 57 | extension Int16 : NumericTweenable {} 58 | extension Int32 : NumericTweenable {} 59 | extension Int64 : NumericTweenable {} 60 | extension UInt : NumericTweenable {} 61 | extension UInt8 : NumericTweenable {} 62 | extension UInt16 : NumericTweenable {} 63 | extension UInt32 : NumericTweenable {} 64 | extension UInt64 : NumericTweenable {} 65 | extension CGFloat: NumericTweenable {} 66 | -------------------------------------------------------------------------------- /Ubergang/Protocols/UTweenLoggable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTweenLoggable.swift 3 | // Ubergang 4 | // 5 | // Created by RF on 18/07/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | public protocol UTweenLoggable { 10 | func verbose(_ msg: String, function: String, file: String, line: Int) 11 | func debug(_ msg: String, function: String, file: String, line: Int) 12 | func info(_ msg: String, function: String, file: String, line: Int) 13 | func warning(_ msg: String, function: String, file: String, line: Int) 14 | func error(_ msg: String, function: String, file: String, line: Int) 15 | } 16 | 17 | 18 | extension UTweenLoggable { 19 | func verbose(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 20 | print("[\(file) - \(function)->\(line)]:\(msg)") 21 | } 22 | 23 | func debug(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 24 | print("[\(file) - \(function)->\(line)]:\(msg)") 25 | } 26 | 27 | func info(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 28 | print("[\(file) - \(function)->\(line)]:\(msg)") 29 | } 30 | 31 | func warning(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 32 | print("[\(file) - \(function)->\(line)]:\(msg)") 33 | } 34 | 35 | func error(_ msg: String, function: String = #function, file: String = #file, line: Int = #line) { 36 | print("[\(file) - \(function)->\(line)]:\(msg)") 37 | } 38 | } 39 | 40 | 41 | class UTweenLogger: UTweenLoggable {} 42 | -------------------------------------------------------------------------------- /Ubergang/Protocols/WeaklyLoopable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeaklyLoopable.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 10/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | protocol WeaklyLoopable { 10 | func loopWeakly() 11 | } -------------------------------------------------------------------------------- /Ubergang/Tween/CGPointTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPointTween.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class CGPointTween: UTween { 12 | 13 | var currentValue = CGPoint() 14 | 15 | override func compute(_ value: Double) -> CGPoint { 16 | _ = super.compute(value) 17 | 18 | let from = self.fromC() 19 | let to = self.toC() 20 | 21 | currentValue.x = from.x + (to.x - from.x) * CGFloat(value) 22 | currentValue.y = from.y + (to.y - from.y) * CGFloat(value) 23 | 24 | return currentValue 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Ubergang/Tween/ColorTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ColorTween.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class ColorTween: UTween { 13 | override func compute(_ value: Double) -> UIColor { 14 | _ = super.compute(value) 15 | 16 | let from = self.fromC() 17 | let to = self.toC() 18 | 19 | var rFrom: CGFloat = 0 20 | var gFrom: CGFloat = 0 21 | var bFrom: CGFloat = 0 22 | var aFrom: CGFloat = 0 23 | 24 | var rTo: CGFloat = 0 25 | var gTo: CGFloat = 0 26 | var bTo: CGFloat = 0 27 | var aTo: CGFloat = 0 28 | 29 | from.getRed(&rFrom, green: &gFrom, blue: &bFrom, alpha: &aFrom) 30 | to.getRed(&rTo, green: &gTo, blue: &bTo, alpha: &aTo) 31 | 32 | let r = rFrom + (rTo - rFrom) * CGFloat(value) 33 | let g = gFrom + (gTo - gFrom) * CGFloat(value) 34 | let b = bFrom + (bTo - bFrom) * CGFloat(value) 35 | let a = aFrom + (aTo - aFrom) * CGFloat(value) 36 | 37 | return UIColor(red: r, green: g, blue: b, alpha: a) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Ubergang/Tween/NumericTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NumericTween.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class NumericTween: UTween { 12 | override func compute(_ value: Double) -> T { 13 | _ = super.compute(value) 14 | 15 | let from = self.fromC() 16 | let to = self.toC() 17 | 18 | let distance = to - from 19 | var parsedDistance: Double 20 | if distance is Double { 21 | parsedDistance = distance as! Double 22 | } 23 | else { 24 | parsedDistance = Double(distance)! 25 | } 26 | 27 | let total = T( parsedDistance * value ) 28 | 29 | return from + total 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Ubergang/Tween/TransformTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransformTween.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 14/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class TransformTween: UTween { 13 | override func compute(_ value: Double) -> CGAffineTransform { 14 | _ = super.compute(value) 15 | 16 | let from = self.fromC() 17 | let to = self.toC() 18 | 19 | var currentValue = CGAffineTransform.identity 20 | currentValue.tx = from.tx + (to.tx - from.tx) * CGFloat(value) 21 | currentValue.ty = from.ty + (to.ty - from.ty) * CGFloat(value) 22 | 23 | currentValue.a = from.a + (to.a - from.a) * CGFloat(value) 24 | currentValue.b = from.b + (to.b - from.b) * CGFloat(value) 25 | currentValue.c = from.c + (to.c - from.c) * CGFloat(value) 26 | currentValue.d = from.d + (to.d - from.d) * CGFloat(value) 27 | 28 | return currentValue 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Ubergang/Tween/UTimeline.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTimeline.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 05/04/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class UTimeline: UTweenBase { 12 | var tweens: [UTweenBase] = [] 13 | var startTimeForTweenId: [String : Double] = [:] 14 | 15 | open var count: Int { return tweens.count } 16 | 17 | /** 18 | Initialize a `UTimeline` with a random id. 19 | 20 | Tweens all containing elements from start to end. 21 | */ 22 | public convenience init() { 23 | let id = "\(#file)_\(arc4random())_update" 24 | self.init(id: id) 25 | } 26 | 27 | /** 28 | Initialize a `UTimeline`. 29 | 30 | Tweens all containing elements from start to end. 31 | 32 | - Parameter id: The unique id of the Tween 33 | */ 34 | public override init(id: String) { 35 | super.init(id: id) 36 | 37 | initialDuration = 0 38 | duration = 0 39 | durationTotal = 0 40 | } 41 | 42 | override func computeConfigs() { 43 | super.computeConfigs() 44 | 45 | for tween in tweens { 46 | switch direction { 47 | case .forward: tween.currentEase = tween.ease 48 | case .reverse: tween.currentEase = tween.ease 49 | case .backward: tween.currentEase = tween.ease.opposite 50 | } 51 | } 52 | } 53 | 54 | open func append(_ tween: UTweenBase) { 55 | // tween.computeConfigs() 56 | // 57 | // tweens.append(tween) 58 | // 59 | // startTimeForTweenId[tween.id] = initialDuration 60 | // 61 | // initialDuration += tween.durationTotal 62 | // 63 | // computeConfigs() 64 | 65 | insert(tween, at: durationTotal) 66 | } 67 | 68 | open func insert(_ tween: UTweenBase, at time: Double) { 69 | tween.computeConfigs() 70 | 71 | tweens.append(tween) 72 | 73 | startTimeForTweenId[tween.id] = time 74 | duration = max(duration, time + tween.durationTotal) 75 | initialDuration = duration 76 | 77 | tweens.sort(by: { 78 | startTimeForTweenId[$0.id] ?? 0 < startTimeForTweenId[$1.id] ?? 0 79 | }) 80 | computeConfigs() 81 | } 82 | 83 | override open var progress: Double { 84 | set { 85 | time = newValue * duration 86 | 87 | for tween in tweens { 88 | let repeatCount = tweenOptions.repeatCount() 89 | var cycles = Double(repeatCount + 1) 90 | 91 | if tweenOptions.contains(.yoyo) && !tweenOptions.containsRepeat() { 92 | cycles *= 2.0 93 | } 94 | 95 | var startTime = startTimeForTweenId[tween.id]! / cycles 96 | 97 | if direction == .backward { 98 | startTime = durationTotal - tween.durationTotal - startTime 99 | } 100 | 101 | let mapped = Math.mapValueInRange(time, 102 | fromLower: startTime, fromUpper: startTime + tween.durationTotal / cycles, 103 | toLower: 0.0, toUpper: 1.0) 104 | 105 | let value = tween.direction == .forward ? mapped : 1 - mapped 106 | 107 | let clamped = Math.clamp(value, lower: 0.0, upper: 1.0) 108 | tween.progressTotal = clamped 109 | } 110 | 111 | super.progress = newValue 112 | } 113 | get { 114 | return time / duration 115 | } 116 | } 117 | 118 | 119 | @discardableResult 120 | override open func reference(_ value: TweenMemoryReference) -> Self { 121 | reference = value 122 | 123 | return self 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Ubergang/Tween/UTween.h: -------------------------------------------------------------------------------- 1 | // 2 | // UTween.h 3 | // UTween 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | //! Project version number for Tween. 13 | FOUNDATION_EXPORT double TweenVersionNumber; 14 | 15 | //! Project version string for Tween. 16 | FOUNDATION_EXPORT const unsigned char TweenVersionString[]; 17 | 18 | // In this header, you should import all the public headers of your framework using statements like #import 19 | 20 | 21 | -------------------------------------------------------------------------------- /Ubergang/Tween/UTween.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTween.swift 3 | // UTween 4 | // 5 | // Created by Robin Frielingsdorf on 07/01/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class UTween: UTweenBase { 13 | 14 | var start: T! 15 | var end: T! 16 | 17 | internal var fromC: (() -> T)! 18 | internal var toC: (() -> T)! 19 | 20 | var updateValue: ((_ value: T) -> Void)! 21 | var updateValueAndProgress: ((_ value: T, _ progress: Double) -> Void)! 22 | 23 | var offset: Double? 24 | 25 | /** 26 | Initialize a generic `UTween` with a random id. 27 | 28 | Tweens any value with type T from start to end. 29 | 30 | This object needs to know how to compute interpolations from start to end, that for 31 | `func compute(value: Double) -> T` must be overriden. 32 | */ 33 | public convenience init() { 34 | let id = "\(#file)_\(arc4random())_update" 35 | self.init(id: id) 36 | } 37 | 38 | /** 39 | Initialize a generic `UTween`. 40 | 41 | Tweens any value with type T from start to end. 42 | 43 | This object needs to know how to compute interpolations from start to end, that for 44 | `func compute(value: Double) -> T` must be overriden. 45 | 46 | - Parameter id: The unique id of the Tween 47 | */ 48 | public override init(id: String) { 49 | super.init(id: id) 50 | } 51 | 52 | override open var progress: Double { 53 | set { 54 | time = newValue * duration 55 | 56 | easeValue = currentEase.function(time, 0.0, 1.0, duration) 57 | 58 | if let offset = offset { 59 | easeValue = fmod(easeValue + offset, 1.0) 60 | } 61 | 62 | let computedValue = compute(easeValue) 63 | 64 | updateValue?( computedValue) 65 | updateValueAndProgress?( computedValue, newValue ) 66 | 67 | super.progress = newValue 68 | } 69 | get { 70 | return time / duration 71 | } 72 | } 73 | 74 | func compute(_ value: Double) -> T { 75 | //should be overriden 76 | 77 | return fromC() 78 | } 79 | 80 | //override Tweenable methods 81 | override open func kill() { 82 | super.kill() 83 | 84 | fromC = nil 85 | updateValue = nil 86 | updateValueAndProgress = nil 87 | complete = nil 88 | } 89 | 90 | @discardableResult 91 | override open func reference(_ value: TweenMemoryReference) -> Self { 92 | reference = value 93 | 94 | return self 95 | } 96 | } 97 | 98 | 99 | extension UTween { 100 | // - 101 | public func from(_ from: T, to: T) -> Self { 102 | self.fromC = {from} 103 | self.toC = {to} 104 | 105 | return self.duration(duration) 106 | } 107 | 108 | public func from(_ from: @escaping () -> T, to: @escaping () -> T) -> Self { 109 | self.fromC = from 110 | self.toC = to 111 | 112 | return self.duration(duration) 113 | } 114 | 115 | public func from(_ from: @escaping () -> T, to: T) -> Self { 116 | self.fromC = from 117 | self.toC = {to} 118 | 119 | return self.duration(duration) 120 | } 121 | 122 | public func from(_ from: T, to: @escaping () -> T) -> Self { 123 | self.fromC = {from} 124 | self.toC = to 125 | 126 | return self.duration(duration) 127 | } 128 | 129 | 130 | @discardableResult 131 | public func update(_ value: @escaping (T) -> Void) -> Self { 132 | updateValue = value 133 | 134 | return self 135 | } 136 | 137 | 138 | @discardableResult 139 | public func update(_ value: @escaping (T, Double) -> Void) -> Self { 140 | updateValueAndProgress = value 141 | 142 | return self 143 | } 144 | 145 | @discardableResult 146 | public func ease(_ ease: Ease) -> Self { 147 | self.ease = ease 148 | self.currentEase = ease 149 | return self 150 | } 151 | 152 | @discardableResult 153 | public func offset(_ value: Double) -> Self { 154 | self.offset = value 155 | return self 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /Ubergang/Util/Bezier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bezier.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 17/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GLKit 11 | 12 | //see https://en.wikipedia.org/wiki/B%C3%A9zier_curve 13 | 14 | class Bezier { 15 | static func linear(t _t: CGFloat, p0: CGPoint, p1: CGPoint) -> CGPoint { 16 | 17 | let v0 = GLKVector2(v: (Float(p0.x), Float(p0.y))) 18 | let v1 = GLKVector2(v: (Float(p1.x), Float(p1.y))) 19 | 20 | let t = Float(_t) 21 | 22 | let v0r = GLKVector2MultiplyScalar(v0, 1-t) 23 | let v1r = GLKVector2MultiplyScalar(v1, t) 24 | 25 | let vResult = GLKVector2Add(v0r, v1r) 26 | 27 | return CGPoint(x: CGFloat(vResult.x), y: CGFloat(vResult.y)) 28 | } 29 | 30 | static func quad(t _t: CGFloat, p0: CGPoint, p1: CGPoint, p2: CGPoint) -> CGPoint { 31 | 32 | let v0 = GLKVector2(v: (Float(p0.x), Float(p0.y))) 33 | let v1 = GLKVector2(v: (Float(p1.x), Float(p1.y))) 34 | let v2 = GLKVector2(v: (Float(p2.x), Float(p2.y))) 35 | 36 | let t = Float(_t) 37 | 38 | let v0r = GLKVector2MultiplyScalar(v0, pow(1-t, 2)) 39 | let v1r = GLKVector2MultiplyScalar(v1, 2*t*(1-t)) 40 | let v2r = GLKVector2MultiplyScalar(v2, t*t) 41 | 42 | var vResult = GLKVector2Add(v0r, v1r) 43 | vResult = GLKVector2Add(vResult, v2r) 44 | 45 | return CGPoint(x: CGFloat(vResult.x), y: CGFloat(vResult.y)) 46 | } 47 | 48 | static func cubic(t _t: CGFloat, p0: CGPoint, p1: CGPoint, p2: CGPoint, p3: CGPoint) -> CGPoint { 49 | let v0 = GLKVector2(v: (Float(p0.x), Float(p0.y))) 50 | let v1 = GLKVector2(v: (Float(p1.x), Float(p1.y))) 51 | let v2 = GLKVector2(v: (Float(p2.x), Float(p2.y))) 52 | let v3 = GLKVector2(v: (Float(p3.x), Float(p3.y))) 53 | 54 | let t = Float(_t) 55 | 56 | let v0r = GLKVector2MultiplyScalar(v0, pow(1-t, 3)) 57 | let v1r = GLKVector2MultiplyScalar(v1, 3 * t * pow(1-t, 2)) 58 | let v2r = GLKVector2MultiplyScalar(v2, 3 * pow(t, 2) * (1-t)) 59 | let v3r = GLKVector2MultiplyScalar(v3, pow(t, 3)) 60 | 61 | var vResult = GLKVector2Add(v0r, v1r) 62 | vResult = GLKVector2Add(vResult, v2r) 63 | vResult = GLKVector2Add(vResult, v3r) 64 | 65 | return CGPoint(x: CGFloat(vResult.x), y: CGFloat(vResult.y)) 66 | } 67 | } -------------------------------------------------------------------------------- /Ubergang/Util/Math.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Math.swift 3 | // Ubergang 4 | // 5 | // Created by Robin Frielingsdorf on 15/05/16. 6 | // Copyright © 2016 Robin Falko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Math { 12 | class func clamp(_ value: T, lower: T, upper: T) -> T { 13 | return max(lower, min(value, upper)) 14 | } 15 | 16 | class func mapValueInRange(_ value: Double, fromLower: Double, fromUpper: Double, toLower: Double, toUpper: Double) -> Double { 17 | let fromRangeSize = fromUpper - fromLower 18 | let toRangeSize = toUpper - toLower 19 | let valueScale = (value - fromLower) / fromRangeSize 20 | return toLower + (valueScale * toRangeSize) 21 | } 22 | 23 | class func zigZag(_ x: Double) -> Double { 24 | return 1 / .pi * asin(cos(Double.pi * (x + 1))) + 0.5 25 | } 26 | } 27 | --------------------------------------------------------------------------------