diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40b64a0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Xcode + +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate diff --git a/Assets/1.gif b/Assets/1.gif new file mode 100644 index 0000000..bbbc962 Binary files /dev/null and b/Assets/1.gif differ diff --git a/Assets/header.png b/Assets/header.png new file mode 100644 index 0000000..32608fe Binary files /dev/null and b/Assets/header.png differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..990946e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 David Roman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Popsicle.podspec b/Popsicle.podspec new file mode 100755 index 0000000..dc4be7f --- /dev/null +++ b/Popsicle.podspec @@ -0,0 +1,16 @@ +Pod::Spec.new do |s| + s.name = "Popsicle" + s.version = "1.0.0" + s.summary = "Simple, extensible value interpolation framework" + s.homepage = "https://github.com/Dromaguirre/Popsicle" + s.author = { "David Roman" => "dromaguirre@gmail.com" } + s.license = { :type => 'MIT', :file => 'LICENSE' } + + s.platform = :ios, '8.0' + s.ios.deployment_target = '8.0' + + s.source = { :git => "https://github.com/Dromaguirre/Popsicle.git", :tag => s.version.to_s } + s.source_files = 'Popsicle/*.{h,m}' + s.frameworks = 'Foundation', 'UIKit' + s.requires_arc = true +end diff --git a/Popsicle.xcodeproj/project.pbxproj b/Popsicle.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d92f16d --- /dev/null +++ b/Popsicle.xcodeproj/project.pbxproj @@ -0,0 +1,828 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 759390AF1AF7CA44003427F2 /* Popsicle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75CE051F1ACA133B008B893D /* Popsicle.framework */; }; + 759390C81AF7D129003427F2 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 759390C71AF7D129003427F2 /* Images.xcassets */; }; + 759390CB1AF7E31F003427F2 /* DRPageScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 759390CA1AF7E31F003427F2 /* DRPageScrollView.m */; }; + 75CE04F61ACA131B008B893D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE04F51ACA131B008B893D /* main.m */; }; + 75CE04F91ACA131B008B893D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE04F81ACA131B008B893D /* AppDelegate.m */; }; + 75CE05071ACA131B008B893D /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 75CE05051ACA131B008B893D /* LaunchScreen.xib */; }; + 75CE05361ACA133B008B893D /* Popsicle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75CE051F1ACA133B008B893D /* Popsicle.framework */; }; + 75CE05371ACA133B008B893D /* Popsicle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 75CE051F1ACA133B008B893D /* Popsicle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 75CE05531ACA14C0008B893D /* Popsicle.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE053F1ACA14C0008B893D /* Popsicle.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75CE05541ACA14C0008B893D /* PSInterpolator.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE05401ACA14C0008B893D /* PSInterpolator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75CE05551ACA14C0008B893D /* PSInterpolator.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE05411ACA14C0008B893D /* PSInterpolator.m */; }; + 75CE05561ACA14C0008B893D /* PSInterpolation.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE05421ACA14C0008B893D /* PSInterpolation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75CE05571ACA14C0008B893D /* PSInterpolation.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE05431ACA14C0008B893D /* PSInterpolation.m */; }; + 75CE05591ACA14C0008B893D /* PSIntegerInterpolation.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE05451ACA14C0008B893D /* PSIntegerInterpolation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75CE055A1ACA14C0008B893D /* PSIntegerInterpolation.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE05461ACA14C0008B893D /* PSIntegerInterpolation.m */; }; + 75CE055B1ACA14C0008B893D /* PSFloatInterpolation.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE05471ACA14C0008B893D /* PSFloatInterpolation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75CE055C1ACA14C0008B893D /* PSFloatInterpolation.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE05481ACA14C0008B893D /* PSFloatInterpolation.m */; }; + 75DCA4AA1ACB6334000F3646 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 75DCA4A91ACB6334000F3646 /* MainViewController.m */; }; + 75DE00D71AFEE83500BE40E0 /* PSInterpolationContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 75DE00D51AFEE83500BE40E0 /* PSInterpolationContext.h */; }; + 75DE00D81AFEE83500BE40E0 /* PSInterpolationContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 75DE00D61AFEE83500BE40E0 /* PSInterpolationContext.m */; }; + 75DFE0DB1AFBF24500090283 /* PSInterpolation+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = 75DFE0DA1AFBF24500090283 /* PSInterpolation+Subclass.h */; }; + 75DFE10E1AFD51B000090283 /* PSPointInterpolation.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE05491ACA14C0008B893D /* PSPointInterpolation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75DFE10F1AFD51B000090283 /* PSPointInterpolation.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE054A1ACA14C0008B893D /* PSPointInterpolation.m */; }; + 75DFE1101AFD51B000090283 /* PSSizeInterpolation.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE054B1ACA14C0008B893D /* PSSizeInterpolation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75DFE1111AFD51B000090283 /* PSSizeInterpolation.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE054C1ACA14C0008B893D /* PSSizeInterpolation.m */; }; + 75DFE1121AFD51B000090283 /* PSRectInterpolation.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE054D1ACA14C0008B893D /* PSRectInterpolation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75DFE1131AFD51B000090283 /* PSRectInterpolation.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE054E1ACA14C0008B893D /* PSRectInterpolation.m */; }; + 75DFE1141AFD51B000090283 /* PSAffineTransformInterpolation.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE054F1ACA14C0008B893D /* PSAffineTransformInterpolation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75DFE1151AFD51B000090283 /* PSAffineTransformInterpolation.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE05501ACA14C0008B893D /* PSAffineTransformInterpolation.m */; }; + 75DFE1161AFD51B000090283 /* PSColorInterpolation.h in Headers */ = {isa = PBXBuildFile; fileRef = 75CE05511ACA14C0008B893D /* PSColorInterpolation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 75DFE1171AFD51B000090283 /* PSColorInterpolation.m in Sources */ = {isa = PBXBuildFile; fileRef = 75CE05521ACA14C0008B893D /* PSColorInterpolation.m */; }; + 75DFE1191AFD51B500090283 /* PSInterpolationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 759390BB1AF7CA70003427F2 /* PSInterpolationTests.m */; }; + 75DFE11A1AFD51B500090283 /* PSIntegerInterpolationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 759390BD1AF7CA70003427F2 /* PSIntegerInterpolationTests.m */; }; + 75DFE11B1AFD51B500090283 /* PSFloatInterpolationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 759390B71AF7CA70003427F2 /* PSFloatInterpolationTests.m */; }; + 75DFE11C1AFD51B500090283 /* PSPointInterpolationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 759390B91AF7CA70003427F2 /* PSPointInterpolationTests.m */; }; + 75DFE11D1AFD51B500090283 /* PSSizeInterpolationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 759390B61AF7CA70003427F2 /* PSSizeInterpolationTests.m */; }; + 75DFE11E1AFD51B500090283 /* PSRectInterpolationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 759390B51AF7CA70003427F2 /* PSRectInterpolationTests.m */; }; + 75DFE1201AFD51B500090283 /* PSColorInterpolationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 759390B81AF7CA70003427F2 /* PSColorInterpolationTests.m */; }; + 75DFE1211AFD576A00090283 /* PSAffineTransformInterpolationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 759390BA1AF7CA70003427F2 /* PSAffineTransformInterpolationTests.m */; }; + 75DFE1241AFD6FED00090283 /* UIView+Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 75DFE1231AFD6FED00090283 /* UIView+Utils.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 759390B01AF7CA44003427F2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 75CE04E61ACA130A008B893D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 75CE051E1ACA133B008B893D; + remoteInfo = Popsicle; + }; + 75CE05341ACA133B008B893D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 75CE04E61ACA130A008B893D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 75CE051E1ACA133B008B893D; + remoteInfo = Popsicle; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 75CE053B1ACA133B008B893D /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 75CE05371ACA133B008B893D /* Popsicle.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 759390A91AF7CA44003427F2 /* PopsicleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PopsicleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 759390AC1AF7CA44003427F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 759390B51AF7CA70003427F2 /* PSRectInterpolationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSRectInterpolationTests.m; sourceTree = ""; }; + 759390B61AF7CA70003427F2 /* PSSizeInterpolationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSSizeInterpolationTests.m; sourceTree = ""; }; + 759390B71AF7CA70003427F2 /* PSFloatInterpolationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSFloatInterpolationTests.m; sourceTree = ""; }; + 759390B81AF7CA70003427F2 /* PSColorInterpolationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSColorInterpolationTests.m; sourceTree = ""; }; + 759390B91AF7CA70003427F2 /* PSPointInterpolationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSPointInterpolationTests.m; sourceTree = ""; }; + 759390BA1AF7CA70003427F2 /* PSAffineTransformInterpolationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSAffineTransformInterpolationTests.m; sourceTree = ""; }; + 759390BB1AF7CA70003427F2 /* PSInterpolationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSInterpolationTests.m; sourceTree = ""; }; + 759390BD1AF7CA70003427F2 /* PSIntegerInterpolationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSIntegerInterpolationTests.m; sourceTree = ""; }; + 759390C71AF7D129003427F2 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 759390C91AF7E31F003427F2 /* DRPageScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DRPageScrollView.h; sourceTree = ""; }; + 759390CA1AF7E31F003427F2 /* DRPageScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DRPageScrollView.m; sourceTree = ""; }; + 75CE04F01ACA131B008B893D /* PopsicleDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PopsicleDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 75CE04F41ACA131B008B893D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 75CE04F51ACA131B008B893D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 75CE04F71ACA131B008B893D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 75CE04F81ACA131B008B893D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 75CE05061ACA131B008B893D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 75CE051F1ACA133B008B893D /* Popsicle.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Popsicle.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 75CE05221ACA133B008B893D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 75CE053F1ACA14C0008B893D /* Popsicle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Popsicle.h; sourceTree = ""; }; + 75CE05401ACA14C0008B893D /* PSInterpolator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSInterpolator.h; sourceTree = ""; }; + 75CE05411ACA14C0008B893D /* PSInterpolator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSInterpolator.m; sourceTree = ""; }; + 75CE05421ACA14C0008B893D /* PSInterpolation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSInterpolation.h; sourceTree = ""; }; + 75CE05431ACA14C0008B893D /* PSInterpolation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSInterpolation.m; sourceTree = ""; }; + 75CE05451ACA14C0008B893D /* PSIntegerInterpolation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSIntegerInterpolation.h; sourceTree = ""; }; + 75CE05461ACA14C0008B893D /* PSIntegerInterpolation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSIntegerInterpolation.m; sourceTree = ""; }; + 75CE05471ACA14C0008B893D /* PSFloatInterpolation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSFloatInterpolation.h; sourceTree = ""; }; + 75CE05481ACA14C0008B893D /* PSFloatInterpolation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSFloatInterpolation.m; sourceTree = ""; }; + 75CE05491ACA14C0008B893D /* PSPointInterpolation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSPointInterpolation.h; sourceTree = ""; }; + 75CE054A1ACA14C0008B893D /* PSPointInterpolation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSPointInterpolation.m; sourceTree = ""; }; + 75CE054B1ACA14C0008B893D /* PSSizeInterpolation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSSizeInterpolation.h; sourceTree = ""; }; + 75CE054C1ACA14C0008B893D /* PSSizeInterpolation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSSizeInterpolation.m; sourceTree = ""; }; + 75CE054D1ACA14C0008B893D /* PSRectInterpolation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSRectInterpolation.h; sourceTree = ""; }; + 75CE054E1ACA14C0008B893D /* PSRectInterpolation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSRectInterpolation.m; sourceTree = ""; }; + 75CE054F1ACA14C0008B893D /* PSAffineTransformInterpolation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSAffineTransformInterpolation.h; sourceTree = ""; }; + 75CE05501ACA14C0008B893D /* PSAffineTransformInterpolation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSAffineTransformInterpolation.m; sourceTree = ""; }; + 75CE05511ACA14C0008B893D /* PSColorInterpolation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSColorInterpolation.h; sourceTree = ""; }; + 75CE05521ACA14C0008B893D /* PSColorInterpolation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSColorInterpolation.m; sourceTree = ""; }; + 75DCA4A81ACB6334000F3646 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; + 75DCA4A91ACB6334000F3646 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; + 75DE00D51AFEE83500BE40E0 /* PSInterpolationContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSInterpolationContext.h; sourceTree = ""; }; + 75DE00D61AFEE83500BE40E0 /* PSInterpolationContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSInterpolationContext.m; sourceTree = ""; }; + 75DFE0DA1AFBF24500090283 /* PSInterpolation+Subclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PSInterpolation+Subclass.h"; sourceTree = ""; }; + 75DFE1221AFD6FED00090283 /* UIView+Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Utils.h"; sourceTree = ""; }; + 75DFE1231AFD6FED00090283 /* UIView+Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Utils.m"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 759390A61AF7CA44003427F2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 759390AF1AF7CA44003427F2 /* Popsicle.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75CE04ED1ACA131B008B893D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 75CE05361ACA133B008B893D /* Popsicle.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75CE051B1ACA133B008B893D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 759390AA1AF7CA44003427F2 /* PopsicleTests */ = { + isa = PBXGroup; + children = ( + 759390BB1AF7CA70003427F2 /* PSInterpolationTests.m */, + 759390BD1AF7CA70003427F2 /* PSIntegerInterpolationTests.m */, + 759390B71AF7CA70003427F2 /* PSFloatInterpolationTests.m */, + 759390B91AF7CA70003427F2 /* PSPointInterpolationTests.m */, + 759390B61AF7CA70003427F2 /* PSSizeInterpolationTests.m */, + 759390B51AF7CA70003427F2 /* PSRectInterpolationTests.m */, + 759390BA1AF7CA70003427F2 /* PSAffineTransformInterpolationTests.m */, + 759390B81AF7CA70003427F2 /* PSColorInterpolationTests.m */, + 759390AB1AF7CA44003427F2 /* Supporting Files */, + ); + path = PopsicleTests; + sourceTree = ""; + }; + 759390AB1AF7CA44003427F2 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 759390AC1AF7CA44003427F2 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 75CE04E51ACA130A008B893D = { + isa = PBXGroup; + children = ( + 75CE04F21ACA131B008B893D /* PopsicleDemo */, + 75CE05201ACA133B008B893D /* Popsicle */, + 759390AA1AF7CA44003427F2 /* PopsicleTests */, + 75CE04F11ACA131B008B893D /* Products */, + ); + sourceTree = ""; + }; + 75CE04F11ACA131B008B893D /* Products */ = { + isa = PBXGroup; + children = ( + 75CE04F01ACA131B008B893D /* PopsicleDemo.app */, + 75CE051F1ACA133B008B893D /* Popsicle.framework */, + 759390A91AF7CA44003427F2 /* PopsicleTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 75CE04F21ACA131B008B893D /* PopsicleDemo */ = { + isa = PBXGroup; + children = ( + 75CE04F71ACA131B008B893D /* AppDelegate.h */, + 75CE04F81ACA131B008B893D /* AppDelegate.m */, + 75DCA4A81ACB6334000F3646 /* MainViewController.h */, + 75DCA4A91ACB6334000F3646 /* MainViewController.m */, + 759390C91AF7E31F003427F2 /* DRPageScrollView.h */, + 759390CA1AF7E31F003427F2 /* DRPageScrollView.m */, + 75DFE1221AFD6FED00090283 /* UIView+Utils.h */, + 75DFE1231AFD6FED00090283 /* UIView+Utils.m */, + 75CE04F31ACA131B008B893D /* Supporting Files */, + ); + path = PopsicleDemo; + sourceTree = ""; + }; + 75CE04F31ACA131B008B893D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 759390C71AF7D129003427F2 /* Images.xcassets */, + 75CE05051ACA131B008B893D /* LaunchScreen.xib */, + 75CE04F41ACA131B008B893D /* Info.plist */, + 75CE04F51ACA131B008B893D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 75CE05201ACA133B008B893D /* Popsicle */ = { + isa = PBXGroup; + children = ( + 75CE053F1ACA14C0008B893D /* Popsicle.h */, + 75CE05401ACA14C0008B893D /* PSInterpolator.h */, + 75CE05411ACA14C0008B893D /* PSInterpolator.m */, + 75DE00D51AFEE83500BE40E0 /* PSInterpolationContext.h */, + 75DE00D61AFEE83500BE40E0 /* PSInterpolationContext.m */, + 75CE05421ACA14C0008B893D /* PSInterpolation.h */, + 75CE05431ACA14C0008B893D /* PSInterpolation.m */, + 75DFE0DA1AFBF24500090283 /* PSInterpolation+Subclass.h */, + 75CE05451ACA14C0008B893D /* PSIntegerInterpolation.h */, + 75CE05461ACA14C0008B893D /* PSIntegerInterpolation.m */, + 75CE05471ACA14C0008B893D /* PSFloatInterpolation.h */, + 75CE05481ACA14C0008B893D /* PSFloatInterpolation.m */, + 75CE05491ACA14C0008B893D /* PSPointInterpolation.h */, + 75CE054A1ACA14C0008B893D /* PSPointInterpolation.m */, + 75CE054B1ACA14C0008B893D /* PSSizeInterpolation.h */, + 75CE054C1ACA14C0008B893D /* PSSizeInterpolation.m */, + 75CE054D1ACA14C0008B893D /* PSRectInterpolation.h */, + 75CE054E1ACA14C0008B893D /* PSRectInterpolation.m */, + 75CE054F1ACA14C0008B893D /* PSAffineTransformInterpolation.h */, + 75CE05501ACA14C0008B893D /* PSAffineTransformInterpolation.m */, + 75CE05511ACA14C0008B893D /* PSColorInterpolation.h */, + 75CE05521ACA14C0008B893D /* PSColorInterpolation.m */, + 75CE05211ACA133B008B893D /* Supporting Files */, + ); + path = Popsicle; + sourceTree = ""; + }; + 75CE05211ACA133B008B893D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 75CE05221ACA133B008B893D /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 75CE051C1ACA133B008B893D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 75DFE1141AFD51B000090283 /* PSAffineTransformInterpolation.h in Headers */, + 75DFE1121AFD51B000090283 /* PSRectInterpolation.h in Headers */, + 75CE05541ACA14C0008B893D /* PSInterpolator.h in Headers */, + 75DFE1161AFD51B000090283 /* PSColorInterpolation.h in Headers */, + 75DFE1101AFD51B000090283 /* PSSizeInterpolation.h in Headers */, + 75DFE10E1AFD51B000090283 /* PSPointInterpolation.h in Headers */, + 75DE00D71AFEE83500BE40E0 /* PSInterpolationContext.h in Headers */, + 75DFE0DB1AFBF24500090283 /* PSInterpolation+Subclass.h in Headers */, + 75CE055B1ACA14C0008B893D /* PSFloatInterpolation.h in Headers */, + 75CE05591ACA14C0008B893D /* PSIntegerInterpolation.h in Headers */, + 75CE05531ACA14C0008B893D /* Popsicle.h in Headers */, + 75CE05561ACA14C0008B893D /* PSInterpolation.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 759390A81AF7CA44003427F2 /* PopsicleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 759390B21AF7CA44003427F2 /* Build configuration list for PBXNativeTarget "PopsicleTests" */; + buildPhases = ( + 759390A51AF7CA44003427F2 /* Sources */, + 759390A61AF7CA44003427F2 /* Frameworks */, + 759390A71AF7CA44003427F2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 759390B11AF7CA44003427F2 /* PBXTargetDependency */, + ); + name = PopsicleTests; + productName = PopsicleTests; + productReference = 759390A91AF7CA44003427F2 /* PopsicleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 75CE04EF1ACA131B008B893D /* PopsicleDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 75CE05141ACA131B008B893D /* Build configuration list for PBXNativeTarget "PopsicleDemo" */; + buildPhases = ( + 75CE04EC1ACA131B008B893D /* Sources */, + 75CE04ED1ACA131B008B893D /* Frameworks */, + 75CE04EE1ACA131B008B893D /* Resources */, + 75CE053B1ACA133B008B893D /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 75CE05351ACA133B008B893D /* PBXTargetDependency */, + ); + name = PopsicleDemo; + productName = PopsicleDemo; + productReference = 75CE04F01ACA131B008B893D /* PopsicleDemo.app */; + productType = "com.apple.product-type.application"; + }; + 75CE051E1ACA133B008B893D /* Popsicle */ = { + isa = PBXNativeTarget; + buildConfigurationList = 75CE05381ACA133B008B893D /* Build configuration list for PBXNativeTarget "Popsicle" */; + buildPhases = ( + 75CE051A1ACA133B008B893D /* Sources */, + 75CE051B1ACA133B008B893D /* Frameworks */, + 75CE051C1ACA133B008B893D /* Headers */, + 75CE051D1ACA133B008B893D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Popsicle; + productName = Popsicle; + productReference = 75CE051F1ACA133B008B893D /* Popsicle.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 75CE04E61ACA130A008B893D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0630; + TargetAttributes = { + 759390A81AF7CA44003427F2 = { + CreatedOnToolsVersion = 6.3.1; + }; + 75CE04EF1ACA131B008B893D = { + CreatedOnToolsVersion = 6.2; + DevelopmentTeam = 928NVD8D9L; + }; + 75CE051E1ACA133B008B893D = { + CreatedOnToolsVersion = 6.2; + }; + }; + }; + buildConfigurationList = 75CE04E91ACA130A008B893D /* Build configuration list for PBXProject "Popsicle" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 75CE04E51ACA130A008B893D; + productRefGroup = 75CE04F11ACA131B008B893D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 75CE04EF1ACA131B008B893D /* PopsicleDemo */, + 75CE051E1ACA133B008B893D /* Popsicle */, + 759390A81AF7CA44003427F2 /* PopsicleTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 759390A71AF7CA44003427F2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75CE04EE1ACA131B008B893D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 75CE05071ACA131B008B893D /* LaunchScreen.xib in Resources */, + 759390C81AF7D129003427F2 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75CE051D1ACA133B008B893D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 759390A51AF7CA44003427F2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 75DFE1201AFD51B500090283 /* PSColorInterpolationTests.m in Sources */, + 75DFE11A1AFD51B500090283 /* PSIntegerInterpolationTests.m in Sources */, + 75DFE11D1AFD51B500090283 /* PSSizeInterpolationTests.m in Sources */, + 75DFE1211AFD576A00090283 /* PSAffineTransformInterpolationTests.m in Sources */, + 75DFE11B1AFD51B500090283 /* PSFloatInterpolationTests.m in Sources */, + 75DFE1191AFD51B500090283 /* PSInterpolationTests.m in Sources */, + 75DFE11C1AFD51B500090283 /* PSPointInterpolationTests.m in Sources */, + 75DFE11E1AFD51B500090283 /* PSRectInterpolationTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75CE04EC1ACA131B008B893D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 75CE04F91ACA131B008B893D /* AppDelegate.m in Sources */, + 75DCA4AA1ACB6334000F3646 /* MainViewController.m in Sources */, + 759390CB1AF7E31F003427F2 /* DRPageScrollView.m in Sources */, + 75DFE1241AFD6FED00090283 /* UIView+Utils.m in Sources */, + 75CE04F61ACA131B008B893D /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75CE051A1ACA133B008B893D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 75DFE1131AFD51B000090283 /* PSRectInterpolation.m in Sources */, + 75DE00D81AFEE83500BE40E0 /* PSInterpolationContext.m in Sources */, + 75CE05551ACA14C0008B893D /* PSInterpolator.m in Sources */, + 75DFE1171AFD51B000090283 /* PSColorInterpolation.m in Sources */, + 75CE05571ACA14C0008B893D /* PSInterpolation.m in Sources */, + 75DFE1111AFD51B000090283 /* PSSizeInterpolation.m in Sources */, + 75CE055C1ACA14C0008B893D /* PSFloatInterpolation.m in Sources */, + 75DFE10F1AFD51B000090283 /* PSPointInterpolation.m in Sources */, + 75DFE1151AFD51B000090283 /* PSAffineTransformInterpolation.m in Sources */, + 75CE055A1ACA14C0008B893D /* PSIntegerInterpolation.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 759390B11AF7CA44003427F2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 75CE051E1ACA133B008B893D /* Popsicle */; + targetProxy = 759390B01AF7CA44003427F2 /* PBXContainerItemProxy */; + }; + 75CE05351ACA133B008B893D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 75CE051E1ACA133B008B893D /* Popsicle */; + targetProxy = 75CE05341ACA133B008B893D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 75CE05051ACA131B008B893D /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 75CE05061ACA131B008B893D /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 759390B31AF7CA44003427F2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = PopsicleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 759390B41AF7CA44003427F2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = PopsicleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 75CE04EA1ACA130A008B893D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 75CE04EB1ACA130A008B893D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + }; + name = Release; + }; + 75CE05151ACA131B008B893D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = PopsicleDemo/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 75CE05161ACA131B008B893D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = PopsicleDemo/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 75CE05391ACA133B008B893D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Popsicle/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 75CE053A1ACA133B008B893D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Popsicle/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 759390B21AF7CA44003427F2 /* Build configuration list for PBXNativeTarget "PopsicleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 759390B31AF7CA44003427F2 /* Debug */, + 759390B41AF7CA44003427F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 75CE04E91ACA130A008B893D /* Build configuration list for PBXProject "Popsicle" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 75CE04EA1ACA130A008B893D /* Debug */, + 75CE04EB1ACA130A008B893D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 75CE05141ACA131B008B893D /* Build configuration list for PBXNativeTarget "PopsicleDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 75CE05151ACA131B008B893D /* Debug */, + 75CE05161ACA131B008B893D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 75CE05381ACA133B008B893D /* Build configuration list for PBXNativeTarget "Popsicle" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 75CE05391ACA133B008B893D /* Debug */, + 75CE053A1ACA133B008B893D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 75CE04E61ACA130A008B893D /* Project object */; +} diff --git a/Popsicle.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Popsicle.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..324ddd8 --- /dev/null +++ b/Popsicle.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Popsicle.xcodeproj/xcshareddata/xcschemes/Popsicle.xcscheme b/Popsicle.xcodeproj/xcshareddata/xcschemes/Popsicle.xcscheme new file mode 100644 index 0000000..585a296 --- /dev/null +++ b/Popsicle.xcodeproj/xcshareddata/xcschemes/Popsicle.xcscheme @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Popsicle/Info.plist b/Popsicle/Info.plist new file mode 100644 index 0000000..24a00a8 --- /dev/null +++ b/Popsicle/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + me.davidroman.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Popsicle/PSAffineTransformInterpolation.h b/Popsicle/PSAffineTransformInterpolation.h new file mode 100644 index 0000000..c25c94f --- /dev/null +++ b/Popsicle/PSAffineTransformInterpolation.h @@ -0,0 +1,18 @@ +// +// PSAffineTransformInterpolation.h +// Popsicle +// +// Created by David Román Aguirre on 3/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolation.h" +#import + +#define CGAffineTransformCreate(tx, ty, sx, sy, deg) CGAffineTransformRotate(CGAffineTransformConcat(CGAffineTransformMakeTranslation(tx, ty), CGAffineTransformMakeScale(sx, sy)), (deg*M_PI_2)/180) + +@interface PSAffineTransformInterpolation : PSInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(CGAffineTransform)fromValue toValue:(CGAffineTransform)toValue; + +@end diff --git a/Popsicle/PSAffineTransformInterpolation.m b/Popsicle/PSAffineTransformInterpolation.m new file mode 100644 index 0000000..ee0b6b3 --- /dev/null +++ b/Popsicle/PSAffineTransformInterpolation.m @@ -0,0 +1,45 @@ +// +// PSAffineTransformInterpolation.m +// Popsicle +// +// Created by David Román Aguirre on 3/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSAffineTransformInterpolation.h" + +#import "PSInterpolation+Subclass.h" + +#define CGAffineTransformGetXTranslation(t) t.tx +#define CGAffineTransformGetYTranslation(t) t.ty +#define CGAffineTransformGetXScale(t) sqrt(t.a * t.a + t.c * t.c) +#define CGAffineTransformGetYScale(t) sqrt(t.b * t.b + t.d * t.d) +#define CGAffineTransformGetRotation(t) atan2f(t.b, t.a) + +@implementation PSAffineTransformInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(CGAffineTransform)fromValue toValue:(CGAffineTransform)toValue { + return [super interpolationWithStartTime:startTime endTime:endTime fromValue:[NSValue valueWithCGAffineTransform:fromValue] toValue:[NSValue valueWithCGAffineTransform:toValue]]; +} + +- (id)valueForTimeFraction:(float)timeFraction { + CGAffineTransform fromValue = [self.fromValue CGAffineTransformValue]; + CGAffineTransform toValue = [self.toValue CGAffineTransformValue]; + + CGFloat xTranslationInterpolation = Interpolation(fromValue.tx, toValue.tx, timeFraction); + CGFloat yTranslationInterpolation = Interpolation(fromValue.ty, toValue.ty, timeFraction); + CGAffineTransform translationValue = CGAffineTransformMakeTranslation(xTranslationInterpolation, yTranslationInterpolation); + + CGFloat xScaleInterpolation = Interpolation(CGAffineTransformGetXScale(fromValue), CGAffineTransformGetXScale(toValue), timeFraction); + CGFloat yScaleInterpolation = Interpolation(CGAffineTransformGetYScale(fromValue), CGAffineTransformGetYScale(toValue), timeFraction); + CGAffineTransform scaleValue = CGAffineTransformMakeScale(xScaleInterpolation, yScaleInterpolation); + + CGFloat rotationInterpolation = Interpolation(CGAffineTransformGetRotation(fromValue), CGAffineTransformGetRotation(toValue), timeFraction); + CGAffineTransform rotationValue = CGAffineTransformMakeRotation(rotationInterpolation); + + CGAffineTransform value = CGAffineTransformConcat(CGAffineTransformConcat(translationValue, scaleValue), rotationValue); + + return [NSValue valueWithCGAffineTransform:value]; +} + +@end diff --git a/Popsicle/PSColorInterpolation.h b/Popsicle/PSColorInterpolation.h new file mode 100644 index 0000000..35306b5 --- /dev/null +++ b/Popsicle/PSColorInterpolation.h @@ -0,0 +1,16 @@ +// +// PSColorInterpolation.h +// Popsicle +// +// Created by David Román Aguirre on 3/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolation.h" +#import + +@interface PSColorInterpolation : PSInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(UIColor *)fromValue toValue:(UIColor *)toValue; + +@end diff --git a/Popsicle/PSColorInterpolation.m b/Popsicle/PSColorInterpolation.m new file mode 100644 index 0000000..26046d7 --- /dev/null +++ b/Popsicle/PSColorInterpolation.m @@ -0,0 +1,46 @@ +// +// PSColorInterpolation.m +// Popsicle +// +// Created by David Román Aguirre on 3/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSColorInterpolation.h" + +#import "PSInterpolation+Subclass.h" + +@implementation PSColorInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(UIColor *)fromValue toValue:(UIColor *)toValue { + return [super interpolationWithStartTime:startTime endTime:endTime fromValue:fromValue toValue:toValue]; +} + +- (id)valueForTimeFraction:(float)timeFraction { + UIColor *fromValue = self.fromValue; + UIColor *toValue = self.toValue; + + CGFloat fromRed; + CGFloat fromGreen; + CGFloat fromBlue; + CGFloat fromAlpha; + + CGFloat toRed; + CGFloat toGreen; + CGFloat toBlue; + CGFloat toAlpha; + + [fromValue getRed:&fromRed green:&fromGreen blue:&fromBlue alpha:&fromAlpha]; + [toValue getRed:&toRed green:&toGreen blue:&toBlue alpha:&toAlpha]; + + CGFloat redInterpolation = Interpolation(fromRed, toRed, timeFraction); + CGFloat greenInterpolation = Interpolation(fromGreen, toGreen, timeFraction); + CGFloat blueInterpolation = Interpolation(fromBlue, toBlue, timeFraction); + CGFloat alphaInterpolation = Interpolation(fromAlpha, toAlpha, timeFraction); + + UIColor *value = [UIColor colorWithRed:redInterpolation green:greenInterpolation blue:blueInterpolation alpha:alphaInterpolation]; + + return value; +} + +@end diff --git a/Popsicle/PSFloatInterpolation.h b/Popsicle/PSFloatInterpolation.h new file mode 100644 index 0000000..2212579 --- /dev/null +++ b/Popsicle/PSFloatInterpolation.h @@ -0,0 +1,15 @@ +// +// PSFloatInterpolation.h +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolation.h" + +@interface PSFloatInterpolation : PSInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(float)fromValue toValue:(float)toValue; + +@end diff --git a/Popsicle/PSFloatInterpolation.m b/Popsicle/PSFloatInterpolation.m new file mode 100644 index 0000000..758a9ac --- /dev/null +++ b/Popsicle/PSFloatInterpolation.m @@ -0,0 +1,28 @@ +// +// PSFloatInterpolation.m +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSFloatInterpolation.h" + +#import "PSInterpolation+Subclass.h" + +@implementation PSFloatInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(float)fromValue toValue:(float)toValue { + return [super interpolationWithStartTime:startTime endTime:endTime fromValue:@(fromValue) toValue:@(toValue)]; +} + +- (id)valueForTimeFraction:(float)timeFraction { + float fromValue = [self.fromValue floatValue]; + float toValue = [self.toValue floatValue]; + + float value = Interpolation(fromValue, toValue, timeFraction); + + return @(value); +} + +@end diff --git a/Popsicle/PSIntegerInterpolation.h b/Popsicle/PSIntegerInterpolation.h new file mode 100644 index 0000000..933e099 --- /dev/null +++ b/Popsicle/PSIntegerInterpolation.h @@ -0,0 +1,15 @@ +// +// PSIntegerInterpolation.h +// Popsicle +// +// Created by David Román Aguirre on 27/10/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolation.h" + +@interface PSIntegerInterpolation : PSInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(NSInteger)fromValue toValue:(NSInteger)toValue; + +@end diff --git a/Popsicle/PSIntegerInterpolation.m b/Popsicle/PSIntegerInterpolation.m new file mode 100644 index 0000000..f1a8adf --- /dev/null +++ b/Popsicle/PSIntegerInterpolation.m @@ -0,0 +1,28 @@ +// +// PSIntegerInterpolation.m +// Popsicle +// +// Created by David Román Aguirre on 27/10/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSIntegerInterpolation.h" + +#import "PSInterpolation+Subclass.h" + +@implementation PSIntegerInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(NSInteger)fromValue toValue:(NSInteger)toValue { + return [super interpolationWithStartTime:startTime endTime:endTime fromValue:@(fromValue) toValue:@(toValue)]; +} + +- (id)valueForTimeFraction:(float)timeFraction { + NSInteger fromValue = [self.fromValue integerValue]; + NSInteger toValue = [self.toValue integerValue]; + + NSInteger value = (NSInteger)floor(Interpolation(fromValue, toValue, timeFraction)); + + return @(value); +} + +@end diff --git a/Popsicle/PSInterpolation+Subclass.h b/Popsicle/PSInterpolation+Subclass.h new file mode 100644 index 0000000..39e8b3d --- /dev/null +++ b/Popsicle/PSInterpolation+Subclass.h @@ -0,0 +1,15 @@ +// +// PSInterpolation+Subclass.h +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#define Interpolation(FROM_VALUE, TO_VALUE, TIME_FRACTION) (float)FROM_VALUE+((float)TO_VALUE-(float)FROM_VALUE)*(float)TIME_FRACTION + +@interface PSInterpolation () + +- (id)valueForTimeFraction:(float)timeFraction; + +@end diff --git a/Popsicle/PSInterpolation.h b/Popsicle/PSInterpolation.h new file mode 100644 index 0000000..023ff9e --- /dev/null +++ b/Popsicle/PSInterpolation.h @@ -0,0 +1,23 @@ +// +// PSInterpolation.h +// Popsicle +// +// Created by David Román Aguirre on 27/10/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +#define PS(INTERPOLATION_CLASS, START_TIME, END_TIME, FROM_VALUE, TO_VALUE) [INTERPOLATION_CLASS interpolationWithStartTime:START_TIME endTime:END_TIME fromValue:FROM_VALUE toValue:TO_VALUE] + +@interface PSInterpolation : NSObject + +@property (nonatomic) float startTime; +@property (nonatomic) float endTime; + +@property (nonatomic, strong) id fromValue; +@property (nonatomic, strong) id toValue; + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(id)fromValue toValue:(id)toValue; + +@end diff --git a/Popsicle/PSInterpolation.m b/Popsicle/PSInterpolation.m new file mode 100644 index 0000000..d40c220 --- /dev/null +++ b/Popsicle/PSInterpolation.m @@ -0,0 +1,29 @@ +// +// PSInterpolation.m +// Popsicle +// +// Created by David Román Aguirre on 27/10/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolation.h" + +@implementation PSInterpolation + +- (instancetype)initWithStartTime:(float)startTime endTime:(float)endTime fromValue:(id)fromValue toValue:(id)toValue { + if (self = [super init]) { + self.startTime = startTime; + self.endTime = endTime; + + self.fromValue = fromValue; + self.toValue = toValue; + } + + return self; +} + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(id)fromValue toValue:(id)toValue { + return [[self alloc] initWithStartTime:startTime endTime:endTime fromValue:fromValue toValue:toValue]; +} + +@end diff --git a/Popsicle/PSInterpolationContext.h b/Popsicle/PSInterpolationContext.h new file mode 100644 index 0000000..6d455b5 --- /dev/null +++ b/Popsicle/PSInterpolationContext.h @@ -0,0 +1,22 @@ +// +// PSInterpolationContext.h +// Popsicle +// +// Created by David Román Aguirre on 10/5/15. +// Copyright (c) 2015 David Roman. All rights reserved. +// + +#import + +@class PSInterpolation; + +@interface PSInterpolationContext : NSObject + +@property (nonatomic, strong) PSInterpolation *interpolation; +@property (nonatomic, weak) id object; +@property (nonatomic, strong) NSString *keyPath; +@property (nonatomic) float timeFraction; + ++ (instancetype)contextWithInterpolation:(PSInterpolation *)interpolation object:(id)object keyPath:(NSString *)keyPath; + +@end diff --git a/Popsicle/PSInterpolationContext.m b/Popsicle/PSInterpolationContext.m new file mode 100644 index 0000000..71cc265 --- /dev/null +++ b/Popsicle/PSInterpolationContext.m @@ -0,0 +1,27 @@ +// +// PSInterpolationContext.m +// Popsicle +// +// Created by David Román Aguirre on 10/5/15. +// Copyright (c) 2015 David Roman. All rights reserved. +// + +#import "PSInterpolationContext.h" + +@implementation PSInterpolationContext + +- (instancetype)initWithWithInterpolation:(PSInterpolation *)interpolation object:(id)object keyPath:(NSString *)keyPath { + if (self = [super init]) { + self.interpolation = interpolation; + self.object = object; + self.keyPath = keyPath; + } + + return self; +} + ++ (instancetype)contextWithInterpolation:(PSInterpolation *)interpolation object:(id)object keyPath:(NSString *)keyPath { + return [[self alloc] initWithWithInterpolation:interpolation object:object keyPath:keyPath]; +} + +@end diff --git a/Popsicle/PSInterpolator.h b/Popsicle/PSInterpolator.h new file mode 100644 index 0000000..7ab31aa --- /dev/null +++ b/Popsicle/PSInterpolator.h @@ -0,0 +1,17 @@ +// +// PSInterpolator.h +// Popsicle +// +// Created by David Román Aguirre on 27/10/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +@interface PSInterpolator : NSObject + +@property (nonatomic, assign) float time; + +- (void)addInterpolations:(id)interpolations forObjects:(id)objects keyPath:(NSString *)keyPath; + +@end diff --git a/Popsicle/PSInterpolator.m b/Popsicle/PSInterpolator.m new file mode 100644 index 0000000..4c5869a --- /dev/null +++ b/Popsicle/PSInterpolator.m @@ -0,0 +1,73 @@ +// +// PSInterpolator.m +// Popsicle +// +// Created by David Román Aguirre on 27/10/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolator.h" + +#import "PSInterpolation.h" +#import "PSInterpolationContext.h" +#import "PSInterpolation+Subclass.h" + +#define Fraction(START_VALUE, END_VALUE, VALUE) ((float)VALUE-(float)START_VALUE)/((float)END_VALUE-(float)START_VALUE) + +@interface PSInterpolator () + +@property (nonatomic, strong) NSArray *interpolationContexts; + +@end + +@implementation PSInterpolator + +- (instancetype)init { + if (self = [super init]) { + self.interpolationContexts = [NSArray new]; + } + + return self; +} + +- (void)performInterpolations { + for (PSInterpolationContext *ic in self.interpolationContexts) { + float timeFraction = Fraction(ic.interpolation.startTime, ic.interpolation.endTime, self.time); + timeFraction = MAX(0, timeFraction); + timeFraction = MIN(1, timeFraction); + + if ((ic.interpolation.startTime <= self.time && self.time <= ic.interpolation.endTime) || (ic.timeFraction != 1 && ic.timeFraction != 0)) { + id value = [ic.interpolation valueForTimeFraction:timeFraction]; + [ic.object setValue:value forKeyPath:ic.keyPath]; + ic.timeFraction = timeFraction; + } + } +} + +- (void)addInterpolations:(id)interpolations forObjects:(id)objects keyPath:(NSString *)keyPath { + safeFor(objects, ^void(id object) { + safeFor(interpolations, ^void(PSInterpolation *interpolation) { + interpolation.fromValue = interpolation.fromValue ? interpolation.fromValue : [object valueForKey:keyPath]; + + PSInterpolationContext *context = [PSInterpolationContext contextWithInterpolation:interpolation object:object keyPath:keyPath]; + self.interpolationContexts = [self.interpolationContexts arrayByAddingObject:context]; + }); + }); +} + +void safeFor(id arrayOrObject, void (^forBlock)(id object)) { + if ([arrayOrObject isKindOfClass:[NSArray class]]) { + for (id object in arrayOrObject) { + forBlock(object); + } + } else { + forBlock(arrayOrObject); + } +} + +- (void)setTime:(float)time { + _time = time; + [self performInterpolations]; +} + +@end diff --git a/Popsicle/PSPointInterpolation.h b/Popsicle/PSPointInterpolation.h new file mode 100644 index 0000000..88a8f05 --- /dev/null +++ b/Popsicle/PSPointInterpolation.h @@ -0,0 +1,16 @@ +// +// PSPointInterpolation.h +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolation.h" +#import + +@interface PSPointInterpolation : PSInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(CGPoint)fromValue toValue:(CGPoint)toValue; + +@end diff --git a/Popsicle/PSPointInterpolation.m b/Popsicle/PSPointInterpolation.m new file mode 100644 index 0000000..cdee16d --- /dev/null +++ b/Popsicle/PSPointInterpolation.m @@ -0,0 +1,31 @@ +// +// PSPointInterpolation.m +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSPointInterpolation.h" + +#import "PSInterpolation+Subclass.h" + +@implementation PSPointInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(CGPoint)fromValue toValue:(CGPoint)toValue { + return [super interpolationWithStartTime:startTime endTime:endTime fromValue:[NSValue valueWithCGPoint:fromValue] toValue:[NSValue valueWithCGPoint:toValue]]; +} + +- (id)valueForTimeFraction:(float)timeFraction { + CGPoint fromValue = [self.fromValue CGPointValue]; + CGPoint toValue = [self.toValue CGPointValue]; + + CGFloat xInterpolation = Interpolation(fromValue.x, toValue.x, timeFraction); + CGFloat yInterpolation = Interpolation(fromValue.y, toValue.y, timeFraction); + + CGPoint value = CGPointMake(xInterpolation, yInterpolation); + + return [NSValue valueWithCGPoint:value]; +} + +@end diff --git a/Popsicle/PSRectInterpolation.h b/Popsicle/PSRectInterpolation.h new file mode 100644 index 0000000..edf6780 --- /dev/null +++ b/Popsicle/PSRectInterpolation.h @@ -0,0 +1,16 @@ +// +// PSRectInterpolation.h +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolation.h" +#import + +@interface PSRectInterpolation : PSInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(CGRect)fromValue toValue:(CGRect)toValue; + +@end diff --git a/Popsicle/PSRectInterpolation.m b/Popsicle/PSRectInterpolation.m new file mode 100644 index 0000000..7d8be06 --- /dev/null +++ b/Popsicle/PSRectInterpolation.m @@ -0,0 +1,33 @@ +// +// PSRectInterpolation.m +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSRectInterpolation.h" + +#import "PSInterpolation+Subclass.h" + +@implementation PSRectInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(CGRect)fromValue toValue:(CGRect)toValue { + return [super interpolationWithStartTime:startTime endTime:endTime fromValue:[NSValue valueWithCGRect:fromValue] toValue:[NSValue valueWithCGRect:toValue]]; +} + +- (id)valueForTimeFraction:(float)timeFraction { + CGRect fromValue = [self.fromValue CGRectValue]; + CGRect toValue = [self.toValue CGRectValue]; + + CGFloat xInterpolation = Interpolation(fromValue.origin.x, toValue.origin.x, timeFraction); + CGFloat yInterpolation = Interpolation(fromValue.origin.y, toValue.origin.y, timeFraction); + CGFloat widthInterpolation = Interpolation(fromValue.size.width, toValue.size.width, timeFraction); + CGFloat heightInterpolation = Interpolation(fromValue.size.height, toValue.size.height, timeFraction); + + CGRect value = CGRectMake(xInterpolation, yInterpolation, widthInterpolation, heightInterpolation); + + return [NSValue valueWithCGRect:value]; +} + +@end diff --git a/Popsicle/PSSizeInterpolation.h b/Popsicle/PSSizeInterpolation.h new file mode 100644 index 0000000..e881c38 --- /dev/null +++ b/Popsicle/PSSizeInterpolation.h @@ -0,0 +1,16 @@ +// +// PSSizeInterpolation.h +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolation.h" +#import + +@interface PSSizeInterpolation : PSInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(CGSize)fromValue toValue:(CGSize)toValue; + +@end diff --git a/Popsicle/PSSizeInterpolation.m b/Popsicle/PSSizeInterpolation.m new file mode 100644 index 0000000..1889428 --- /dev/null +++ b/Popsicle/PSSizeInterpolation.m @@ -0,0 +1,31 @@ +// +// PSSizeInterpolation.m +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSSizeInterpolation.h" + +#import "PSInterpolation+Subclass.h" + +@implementation PSSizeInterpolation + ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(CGSize)fromValue toValue:(CGSize)toValue { + return [super interpolationWithStartTime:startTime endTime:endTime fromValue:[NSValue valueWithCGSize:fromValue] toValue:[NSValue valueWithCGSize:toValue]]; +} + +- (id)valueForTimeFraction:(float)timeFraction { + CGSize fromValue = [self.fromValue CGSizeValue]; + CGSize toValue = [self.toValue CGSizeValue]; + + CGFloat widthInterpolation = Interpolation(fromValue.width, toValue.width, timeFraction); + CGFloat heightInterpolation = Interpolation(fromValue.height, toValue.height, timeFraction); + + CGSize value = CGSizeMake(widthInterpolation, heightInterpolation); + + return [NSValue valueWithCGSize:value]; +} + +@end diff --git a/Popsicle/Popsicle.h b/Popsicle/Popsicle.h new file mode 100644 index 0000000..64d8bea --- /dev/null +++ b/Popsicle/Popsicle.h @@ -0,0 +1,20 @@ +// +// Popsicle.h +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import "PSInterpolator.h" +#import "PSInterpolation.h" + +#import "PSIntegerInterpolation.h" +#import "PSFloatInterpolation.h" + +#import "PSPointInterpolation.h" +#import "PSSizeInterpolation.h" +#import "PSRectInterpolation.h" +#import "PSAffineTransformInterpolation.h" + +#import "PSColorInterpolation.h" diff --git a/PopsicleDemo/AppDelegate.h b/PopsicleDemo/AppDelegate.h new file mode 100644 index 0000000..cff3e42 --- /dev/null +++ b/PopsicleDemo/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// PopsicleDemo +// +// Created by David Román Aguirre on 31/3/15. +// Copyright (c) 2015 David Roman. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (nonatomic, strong) UIWindow *window; + +@end diff --git a/PopsicleDemo/AppDelegate.m b/PopsicleDemo/AppDelegate.m new file mode 100644 index 0000000..6ec499f --- /dev/null +++ b/PopsicleDemo/AppDelegate.m @@ -0,0 +1,23 @@ +// +// AppDelegate.m +// PopsicleDemo +// +// Created by David Román Aguirre on 31/3/15. +// Copyright (c) 2015 David Roman. All rights reserved. +// + +#import "AppDelegate.h" +#import "MainViewController.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + self.window.backgroundColor = [UIColor whiteColor]; + self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[MainViewController new]]; + [self.window makeKeyAndVisible]; + + return YES; +} + +@end diff --git a/PopsicleDemo/Base.lproj/LaunchScreen.xib b/PopsicleDemo/Base.lproj/LaunchScreen.xib new file mode 100644 index 0000000..119062a --- /dev/null +++ b/PopsicleDemo/Base.lproj/LaunchScreen.xib @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PopsicleDemo/DRPageScrollView.h b/PopsicleDemo/DRPageScrollView.h new file mode 100755 index 0000000..0cf177a --- /dev/null +++ b/PopsicleDemo/DRPageScrollView.h @@ -0,0 +1,32 @@ +// +// DRPageScrollView.h +// DRPageScrollView +// +// Created by David Román Aguirre on 3/4/15. +// Copyright (c) 2015 David Román Aguirre. All rights reserved. +// + +#import + +/// The type of block used to define what to display on each page view. +typedef void(^DRPageHandlerBlock)(UIView *pageView); + +@interface DRPageScrollView : UIScrollView + +/// Determines whether page views are reused or not in order to reduce memory consumption. +@property (nonatomic, getter=isPageReuseEnabled) BOOL pageReuseEnabled; + +/// The current page index (starting from 0). +@property (nonatomic, assign) NSInteger currentPage; + +/// The total number of pages in the scroll view. +@property (nonatomic, readonly) NSInteger numberOfPages; + +/** + * Sets up a new page for the scroll view. + * + * @param handler A block that defines what to display on the page. +**/ +- (void)addPageWithHandler:(DRPageHandlerBlock)handler; + +@end diff --git a/PopsicleDemo/DRPageScrollView.m b/PopsicleDemo/DRPageScrollView.m new file mode 100755 index 0000000..9c91fac --- /dev/null +++ b/PopsicleDemo/DRPageScrollView.m @@ -0,0 +1,174 @@ +// +// DRPageScrollView.m +// DRPageScrollView +// +// Created by David Román Aguirre on 3/4/15. +// Copyright (c) 2015 David Román Aguirre. All rights reserved. +// + +#import "DRPageScrollView.h" + +@interface DRPageScrollView () { + NSInteger previousPage; + NSInteger instantaneousPreviousPage; +} + +@property (nonatomic, strong) NSArray *pageViews; +@property (nonatomic, strong) NSArray *pageHandlers; + +@end + +@implementation DRPageScrollView + +- (instancetype)init { + if (self = [super init]) { + previousPage = -1; + self.pagingEnabled = YES; + self.showsHorizontalScrollIndicator = NO; + self.showsVerticalScrollIndicator = NO; + + self.pageViews = [NSMutableArray new]; + self.pageHandlers = [NSArray new]; + } + + return self; +} + +- (void)setPageReuseEnabled:(BOOL)pageReuseEnabled { + if (self.numberOfPages > 0) return; + _pageReuseEnabled = pageReuseEnabled; +} + +- (NSInteger)currentPage { + CGPoint presentationLayerContentOffset = [self.layer.presentationLayer bounds].origin; + return MAX(round(presentationLayerContentOffset.x/self.frame.size.width), 0); +} + +- (void)setCurrentPage:(NSInteger)currentPage { + self.contentOffset = CGPointMake(self.frame.size.width*currentPage, self.contentOffset.y); +} + +- (NSInteger)numberOfPages { + return [self.pageHandlers count]; +} + +- (void)addPageWithHandler:(DRPageHandlerBlock)handler { + self.pageHandlers = [self.pageHandlers arrayByAddingObject:handler]; +} + +#pragma mark Pages + +- (BOOL)isAnimating { + return [[self.layer animationKeys] count] != 0; +} + +- (void)setContentOffset:(CGPoint)contentOffset { + [super setContentOffset:contentOffset]; + + if ([self isAnimating]) { + CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(didRefreshDisplay:)]; + [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; + } else { + [self didScrollToPosition:contentOffset]; + } +} + +- (void)didRefreshDisplay:(CADisplayLink *)displayLink { + if ([self isAnimating]) { + CGPoint presentationLayerContentOffset = [self.layer.presentationLayer bounds].origin; + [self didScrollToPosition:presentationLayerContentOffset]; + } else { + [displayLink invalidate]; + } +} + +- (void)didScrollToPosition:(CGPoint)position { + if (self.numberOfPages == 0 || self.currentPage == previousPage) return; + + if (self.pageReuseEnabled) { + for (UIView *pageView in self.pageViews) { + if (pageView.tag < self.currentPage - 1 || pageView.tag > self.currentPage + 1) { + [self queuePageView:pageView]; + } + } + } + + for (NSInteger i = self.currentPage-1; i <= self.currentPage+1; i++) { + if (i >= 0 && i < self.numberOfPages && ![self pageViewWithTag:i]) { + UIView *pageView = [self dequeuePageView]; + pageView.tag = i; + + DRPageHandlerBlock handler = self.pageHandlers[i]; + handler(pageView); + [self addSubview:pageView]; + + NSInteger pageMultiplier = 2*i+1; // We need an odd multiplier. Any odd number can be expressed as 2n+1. + + NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:pageView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:pageMultiplier constant:0]; + NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:pageView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; + NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:pageView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1 constant:0]; + NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:pageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1 constant:0]; + + [self addConstraints:@[centerXConstraint, centerYConstraint, widthConstraint, heightConstraint]]; // This may lead to vertical orientation support in the future ;) + } + } + + previousPage = self.currentPage; +} + +- (void)queuePageView:(UIView *)pageView { + [pageView removeFromSuperview]; + + for (UIView *sb in pageView.subviews) { + [sb removeFromSuperview]; + } + + pageView.tag = -1; +} + +- (UIView *)dequeuePageView { + for (UIView *pv in self.pageViews) { + if (!pv.superview) { + return pv; + } + } + + UIView *pageView = [UIView new]; + pageView.tag = -1; + pageView.translatesAutoresizingMaskIntoConstraints = NO; + self.pageViews = [self.pageViews arrayByAddingObject:pageView]; + + return pageView; +} + +- (UIView *)pageViewWithTag:(NSInteger)tag { + for (UIView *pageView in self.subviews) { + if (pageView.tag == tag && pageView.class == [UIView class]) { + return pageView; + } + } + + return nil; +} + +#pragma mark Rotation/resize + +- (void)layoutSubviews { + CGFloat neededContentSizeWidth = self.frame.size.width*self.numberOfPages; + + if (self.contentSize.width != neededContentSizeWidth) { + [self refreshDimensions]; + self.currentPage = instantaneousPreviousPage; + } else { + instantaneousPreviousPage = self.currentPage; + } + + [super layoutSubviews]; +} + +- (void)refreshDimensions { + self.contentSize = CGSizeMake(self.frame.size.width*self.numberOfPages, self.frame.size.height); + self.contentInset = UIEdgeInsetsZero; +} + +@end diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Contents.json b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..209a46b --- /dev/null +++ b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,83 @@ +{ + "images" : [ + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-Small@3x.png", + "scale" : "3x", + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-40@3x.png", + "scale" : "3x", + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@3x.png", + "scale" : "3x", + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-40@2x.png", + "scale" : "2x", + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@2x.png", + "scale" : "2x", + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-Small@2x.png", + "scale" : "2x", + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-40~iPad.png", + "scale" : "1x", + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-40~iPad@2x.png", + "scale" : "2x", + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-76.png", + "scale" : "1x", + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-76@2x.png", + "scale" : "2x", + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-Small~iPad.png", + "scale" : "1x", + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-Small~iPad@2x.png", + "scale" : "2x", + }, + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "pre-rendered" : false + } +} \ No newline at end of file diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png new file mode 100644 index 0000000..9f3d9bd Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png new file mode 100644 index 0000000..dae5e68 Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40~iPad.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40~iPad.png new file mode 100644 index 0000000..fc1e838 Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40~iPad.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40~iPad@2x.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40~iPad@2x.png new file mode 100644 index 0000000..9f3d9bd Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-40~iPad@2x.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png new file mode 100644 index 0000000..dae5e68 Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png new file mode 100644 index 0000000..c426fbc Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png new file mode 100644 index 0000000..85da01f Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png new file mode 100644 index 0000000..f9462b6 Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png new file mode 100644 index 0000000..c5837fe Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png new file mode 100644 index 0000000..78563ab Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small~iPad.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small~iPad.png new file mode 100644 index 0000000..248e128 Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small~iPad.png differ diff --git a/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small~iPad@2x.png b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small~iPad@2x.png new file mode 100644 index 0000000..c5837fe Binary files /dev/null and b/PopsicleDemo/Images.xcassets/AppIcon.appiconset/Icon-Small~iPad@2x.png differ diff --git a/PopsicleDemo/Images.xcassets/logo.imageset/Contents.json b/PopsicleDemo/Images.xcassets/logo.imageset/Contents.json new file mode 100644 index 0000000..c369d6f --- /dev/null +++ b/PopsicleDemo/Images.xcassets/logo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "logo.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/PopsicleDemo/Images.xcassets/logo.imageset/logo.pdf b/PopsicleDemo/Images.xcassets/logo.imageset/logo.pdf new file mode 100644 index 0000000..077f3cc Binary files /dev/null and b/PopsicleDemo/Images.xcassets/logo.imageset/logo.pdf differ diff --git a/PopsicleDemo/Info.plist b/PopsicleDemo/Info.plist new file mode 100644 index 0000000..8e2f9b8 --- /dev/null +++ b/PopsicleDemo/Info.plist @@ -0,0 +1,53 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + me.davidroman.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Popsicle + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/PopsicleDemo/MainViewController.h b/PopsicleDemo/MainViewController.h new file mode 100644 index 0000000..b511008 --- /dev/null +++ b/PopsicleDemo/MainViewController.h @@ -0,0 +1,13 @@ +// +// MainViewController.h +// Popsicle +// +// Created by David Román Aguirre on 1/4/15. +// Copyright (c) 2015 David Roman. All rights reserved. +// + +#import + +@interface MainViewController : UIViewController + +@end diff --git a/PopsicleDemo/MainViewController.m b/PopsicleDemo/MainViewController.m new file mode 100644 index 0000000..d3b6a5b --- /dev/null +++ b/PopsicleDemo/MainViewController.m @@ -0,0 +1,130 @@ +// +// MainViewController.m +// Popsicle +// +// Created by David Román Aguirre on 1/4/15. +// Copyright (c) 2015 David Roman. All rights reserved. +// + +#import "MainViewController.h" + +#import "Popsicle.h" +#import "DRPageScrollView.h" +#import "UIView+Utils.h" // Extremely useful to simplify code. + +@interface MainViewController () + +@property (nonatomic, strong) PSInterpolator *interpolator; +@property (nonatomic, strong) DRPageScrollView *pageScrollView; + +@end + +@implementation MainViewController + +- (id)init { + if (self = [super init]) { + self.interpolator = [PSInterpolator new]; + self.pageScrollView = [DRPageScrollView new]; + } + + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"Popsicle"; + self.view.backgroundColor = [UIColor whiteColor]; + + self.pageScrollView.delegate = self; + self.pageScrollView.frame = self.view.frame; + self.pageScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.view addSubview:self.pageScrollView]; + + // Page 1 + + UIImageView *logoImageView = [UIImageView new]; + logoImageView.image = [UIImage imageNamed:@"logo"]; + logoImageView.size = CGSizeMake(logoImageView.image.size.width/2, logoImageView.image.size.height/2); + logoImageView.center = self.pageScrollView.center; + + CGFloat logoImageViewCenterX1 = logoImageView.centerX+self.pageScrollView.width; + CGFloat logoImageViewCenterY1 = self.pageScrollView.height-80; + [self.interpolator addInterpolations:PS(PSPointInterpolation, 0, 1, logoImageView.center, CGPointMake(logoImageViewCenterX1, logoImageViewCenterY1)) forObjects:logoImageView keyPath:@"center"]; + + UILabel *firstLabel = [self labelWithText:@"Hello world! This is a Popsicle demo app."]; + firstLabel.y = self.pageScrollView.height-firstLabel.height-30; + + [self.interpolator addInterpolations:PS(PSFloatInterpolation, 0, 0.4, 1, 0) forObjects:firstLabel keyPath:@"alpha"]; + + [self.pageScrollView addPageWithHandler:^(UIView *pageView) { + [pageView addSubview:logoImageView]; + [pageView addSubview:firstLabel]; + }]; + + // Page 2 + + CGFloat logoImageViewCenterX2 = logoImageView.centerX+self.pageScrollView.width*2; + [self.interpolator addInterpolations:PS(PSFloatInterpolation, 1, 2, logoImageViewCenterX1, logoImageViewCenterX2) forObjects:logoImageView keyPath:@"centerX"]; + + UILabel *secondLabel = [self labelWithText:@"Woah! That was smooth!\n\nAs you can see, Popsicle provides a great way to create transitions through value interpolations."]; + secondLabel.centerY = (self.pageScrollView.height-80-logoImageView.height/2)/2+self.navigationController.navigationBar.height/2; + + [self.interpolator addInterpolations:PS(PSFloatInterpolation, 1, 1.4, 1, 0) forObjects:secondLabel keyPath:@"alpha"]; + + [self.pageScrollView addPageWithHandler:^(UIView *pageView) { + [pageView addSubview:secondLabel]; + }]; + + // Page 3 + + CGFloat logoImageViewCenterX3 = logoImageView.centerX+self.pageScrollView.width*3; + [self.interpolator addInterpolations:PS(PSFloatInterpolation, 2, 3, logoImageViewCenterX2, logoImageViewCenterX3) forObjects:logoImageView keyPath:@"centerX"]; + [self.interpolator addInterpolations:PS(PSFloatInterpolation, 2, 3, logoImageViewCenterY1, self.pageScrollView.centerY+self.navigationController.navigationBar.height/2) forObjects:logoImageView keyPath:@"centerY"]; + [self.interpolator addInterpolations:PS(PSFloatInterpolation, 2, 3, 1, 0.1) forObjects:logoImageView keyPath:@"alpha"]; + [self.interpolator addInterpolations:PS(PSAffineTransformInterpolation, 2, 3, logoImageView.transform, CGAffineTransformCreate(0, 0, 1.4, 1.4, 60)) forObjects:logoImageView keyPath:@"transform"]; + + UILabel *thirdLabel = [self labelWithText:@"Such values are not bound to UIKit, although Popsicle offers some built-in interpolations for values such as int, float, CGRect, CGAffineTransform and UIColor."]; + thirdLabel.centerY = (self.pageScrollView.height-80-logoImageView.height/2)/2+self.navigationController.navigationBar.height/2; + + CGAffineTransform thirdLabelTransform1 = CGAffineTransformCreate(0, 0, 0.5, 0.5, -70); + CGAffineTransform thirdLabelTransform2 = CGAffineTransformCreate(0, 0, 0.5, 0.5, 0); + [self.interpolator addInterpolations:@[PS(PSAffineTransformInterpolation, 1, 2, thirdLabelTransform1, CGAffineTransformIdentity), + PS(PSAffineTransformInterpolation, 2, 3, CGAffineTransformIdentity, thirdLabelTransform2)] + forObjects:thirdLabel + keyPath:@"transform"]; + [self.interpolator addInterpolations:PS(PSFloatInterpolation, 2, 2.4, 1, 0) forObjects:thirdLabel keyPath:@"alpha"]; + + [self.pageScrollView addPageWithHandler:^(UIView *pageView) { + [pageView addSubview:thirdLabel]; + }]; + + // Page 4 + + UILabel *fourthLabel = [self labelWithText:@"There's a lot more coming for Popsicle.\n\nFor requests, comments or concerns, just open a GitHub issue or ping me @Dromaguirre and I'll reply as soon as I can."]; + fourthLabel.center = self.pageScrollView.center; + + [self.pageScrollView addPageWithHandler:^(UIView *pageView) { + [pageView addSubview:fourthLabel]; + }]; +} + +- (UILabel *)labelWithText:(NSString *)text { + UILabel *label = [UILabel new]; + + label.numberOfLines = 100; + label.textAlignment = NSTextAlignmentCenter; + label.text = text; + label.width = self.pageScrollView.width-60; + [label sizeToFit]; // Adjusts height for current width + label.frame = CGRectMake(roundf(label.x), roundf(label.y), roundf(label.width), roundf(label.height)); // sizeToFit is an d*** to frame. + label.centerX = self.pageScrollView.centerX; + + return label; +} + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + self.interpolator.time = scrollView.contentOffset.x/scrollView.frame.size.width; // contentOffset.x/frame.size.width = current page index. +} + +@end diff --git a/PopsicleDemo/UIView+Utils.h b/PopsicleDemo/UIView+Utils.h new file mode 100644 index 0000000..b5bffca --- /dev/null +++ b/PopsicleDemo/UIView+Utils.h @@ -0,0 +1,24 @@ +// +// UIView+Utils.h +// Popsicle +// +// Created by David Román Aguirre on 9/5/15. +// Copyright (c) 2015 David Roman. All rights reserved. +// + +#import + +@interface UIView (Utils) + +@property (nonatomic, assign) CGFloat x; +@property (nonatomic, assign) CGFloat y; +@property (nonatomic, assign) CGFloat width; +@property (nonatomic, assign) CGFloat height; + +@property (nonatomic, assign) CGPoint origin; +@property (nonatomic, assign) CGSize size; + +@property (nonatomic, assign) CGFloat centerX; +@property (nonatomic, assign) CGFloat centerY; + +@end diff --git a/PopsicleDemo/UIView+Utils.m b/PopsicleDemo/UIView+Utils.m new file mode 100644 index 0000000..3e04f6a --- /dev/null +++ b/PopsicleDemo/UIView+Utils.m @@ -0,0 +1,85 @@ +// +// UIView+Utils.m +// Popsicle +// +// Created by David Román Aguirre on 9/5/15. +// Copyright (c) 2015 David Roman. All rights reserved. +// + +#import "UIView+Utils.h" + +@implementation UIView (Utils) + +#pragma Frame + +- (CGFloat)x { + return self.frame.origin.x; +} + +- (void)setX:(CGFloat)x { + self.frame = CGRectMake(x, self.frame.origin.y, self.frame.size.width, self.frame.size.height); +} + +- (CGFloat)y { + return self.frame.origin.y; +} + +- (void)setY:(CGFloat)y { + self.frame = CGRectMake(self.frame.origin.x, y, self.frame.size.width, self.frame.size.height); +} + +- (CGFloat)width { + return self.frame.size.width; +} + +- (void)setWidth:(CGFloat)width { + self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, width, self.frame.size.height); +} + +- (CGFloat)height { + return self.frame.size.height; +} + +- (void)setHeight:(CGFloat)height { + self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, height); +} + +#pragma Origin + +- (CGPoint)origin { + return self.frame.origin; +} + +- (void)setOrigin:(CGPoint)origin { + self.frame = CGRectMake(origin.x, origin.y, self.frame.size.width, self.frame.size.height); +} + +#pragma Size + +- (CGSize)size { + return self.frame.size; +} + +- (void)setSize:(CGSize)size { + self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, size.width, size.height); +} + +#pragma Center + +- (CGFloat)centerX { + return self.center.x; +} + +- (void)setCenterX:(CGFloat)centerX { + self.center = CGPointMake(centerX, self.center.y); +} + +- (CGFloat)centerY { + return self.center.y; +} + +- (void)setCenterY:(CGFloat)centerY { + self.center = CGPointMake(self.center.x, centerY); +} + +@end diff --git a/PopsicleDemo/main.m b/PopsicleDemo/main.m new file mode 100644 index 0000000..77598ab --- /dev/null +++ b/PopsicleDemo/main.m @@ -0,0 +1,16 @@ +// +// main.m +// PopsicleDemo +// +// Created by David Román Aguirre on 31/3/15. +// +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/PopsicleTests/Info.plist b/PopsicleTests/Info.plist new file mode 100644 index 0000000..bdb7eda --- /dev/null +++ b/PopsicleTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + me.davidroman.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/PopsicleTests/PSAffineTransformInterpolationTests.m b/PopsicleTests/PSAffineTransformInterpolationTests.m new file mode 100644 index 0000000..4433c8d --- /dev/null +++ b/PopsicleTests/PSAffineTransformInterpolationTests.m @@ -0,0 +1,49 @@ +// +// PSAffineTransformInterpolationTests.m +// Popsicle +// +// Created by David Román Aguirre on 3/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +#import "PSAffineTransformInterpolation.h" +#import "PSInterpolation+Subclass.h" + +#define CGAffineTransformGetXTranslation(t) t.tx +#define CGAffineTransformGetYTranslation(t) t.ty +#define CGAffineTransformGetXScale(t) sqrt(t.a * t.a + t.c * t.c) +#define CGAffineTransformGetYScale(t) sqrt(t.b * t.b + t.d * t.d) +#define CGAffineTransformGetRotation(t) atan2f(t.b, t.a) + +@interface PSAffineTransformInterpolationTests : XCTestCase + +@end + +@implementation PSAffineTransformInterpolationTests + +- (void)testTranslationAffineTransformInterpolation { + PSAffineTransformInterpolation *interpolation = PS(PSAffineTransformInterpolation, 0, 100, CGAffineTransformIdentity, CGAffineTransformMakeTranslation(100, 100)); + + CGAffineTransform intermediateAffineTransform = [[interpolation valueForTimeFraction:0.5] CGAffineTransformValue]; + XCTAssertEqual(CGAffineTransformGetXTranslation(intermediateAffineTransform), 50); + XCTAssertEqual(CGAffineTransformGetYTranslation(intermediateAffineTransform), 50); +} + +- (void)testScaleAffineTransformInterpolation { + PSAffineTransformInterpolation *interpolation = PS(PSAffineTransformInterpolation, 0, 100, CGAffineTransformIdentity, CGAffineTransformMakeScale(1.5, 1.5)); + + CGAffineTransform intermediateAffineTransform = [[interpolation valueForTimeFraction:0.5] CGAffineTransformValue]; + XCTAssertEqual(CGAffineTransformGetXScale(intermediateAffineTransform), 1.25); + XCTAssertEqual(CGAffineTransformGetYScale(intermediateAffineTransform), 1.25); +} + +- (void)testRotationAffineTransformInterpolation { + PSAffineTransformInterpolation *interpolation = PS(PSAffineTransformInterpolation, 0, 100, CGAffineTransformIdentity, CGAffineTransformMakeRotation(0.5)); + + CGAffineTransform intermediateAffineTransform = [[interpolation valueForTimeFraction:0.5] CGAffineTransformValue]; + XCTAssertEqual(CGAffineTransformGetRotation(intermediateAffineTransform), 0.25); +} + +@end diff --git a/PopsicleTests/PSColorInterpolationTests.m b/PopsicleTests/PSColorInterpolationTests.m new file mode 100644 index 0000000..73e778b --- /dev/null +++ b/PopsicleTests/PSColorInterpolationTests.m @@ -0,0 +1,42 @@ +// +// PSColorInterpolationTests.m +// Popsicle +// +// Created by David Román Aguirre on 4/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +#import "PSColorInterpolation.h" +#import "PSInterpolation+Subclass.h" + +@interface PSColorInterpolationTests : XCTestCase + +@end + +@implementation PSColorInterpolationTests + +- (void)testColorInterpolation { + PSColorInterpolation *interpolation = PS(PSColorInterpolation, 0, 100, [UIColor whiteColor], [UIColor blackColor]); + + CGFloat intermediateColorRedComponent; + CGFloat intermediateColorGreenComponent; + CGFloat intermediateColorBlueComponent; + CGFloat intermediateColorAlphaComponent; + + CGFloat grayColorRedComponent; + CGFloat grayColorGreenComponent; + CGFloat grayColorBlueComponent; + CGFloat grayColorAlphaComponent; + + [[interpolation valueForTimeFraction:0.5] getRed:&intermediateColorRedComponent green:&intermediateColorGreenComponent blue:&intermediateColorBlueComponent alpha:&intermediateColorAlphaComponent]; + [[UIColor grayColor] getRed:&grayColorRedComponent green:&grayColorGreenComponent blue:&grayColorBlueComponent alpha:&grayColorAlphaComponent]; + + XCTAssertEqual(intermediateColorRedComponent, grayColorRedComponent); + XCTAssertEqual(intermediateColorGreenComponent, grayColorGreenComponent); + XCTAssertEqual(intermediateColorBlueComponent, grayColorBlueComponent); + XCTAssertEqual(intermediateColorAlphaComponent, grayColorAlphaComponent); +} + +@end diff --git a/PopsicleTests/PSFloatInterpolationTests.m b/PopsicleTests/PSFloatInterpolationTests.m new file mode 100644 index 0000000..9a51859 --- /dev/null +++ b/PopsicleTests/PSFloatInterpolationTests.m @@ -0,0 +1,29 @@ +// +// PSFloatInterpolationTests.m +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +#import "PSFloatInterpolation.h" +#import "PSInterpolation+Subclass.h" + +@interface PSFloatInterpolationTests : XCTestCase + +@end + +@implementation PSFloatInterpolationTests + +- (void)testFloatInterpolation { + PSFloatInterpolation *interpolation = PS(PSFloatInterpolation, 0, 30, 10, 20); + + XCTAssertEqualObjects([interpolation valueForTimeFraction:0], @10); + XCTAssertEqualObjects([interpolation valueForTimeFraction:0.5], @15); + XCTAssertEqual([[interpolation valueForTimeFraction:0.6916666] floatValue], 16.916666f); + XCTAssertEqualObjects([interpolation valueForTimeFraction:1], @20); +} + +@end diff --git a/PopsicleTests/PSIntegerInterpolationTests.m b/PopsicleTests/PSIntegerInterpolationTests.m new file mode 100644 index 0000000..9f8b349 --- /dev/null +++ b/PopsicleTests/PSIntegerInterpolationTests.m @@ -0,0 +1,29 @@ +// +// PSIntegerInterpolationTests.m +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +#import "PSIntegerInterpolation.h" +#import "PSInterpolation+Subclass.h" + +@interface PSIntegerInterpolationTests : XCTestCase + +@end + +@implementation PSIntegerInterpolationTests + +- (void)testIntegerInterpolation { + PSIntegerInterpolation *interpolation = PS(PSIntegerInterpolation, 20, 30, 10, 20); + + XCTAssertEqualObjects([interpolation valueForTimeFraction:0], @10); + XCTAssertEqualObjects([interpolation valueForTimeFraction:0.5], @15); + XCTAssertEqualObjects([interpolation valueForTimeFraction:0.7], @17); + XCTAssertEqualObjects([interpolation valueForTimeFraction:1], @20); +} + +@end diff --git a/PopsicleTests/PSInterpolationTests.m b/PopsicleTests/PSInterpolationTests.m new file mode 100644 index 0000000..a66c5ee --- /dev/null +++ b/PopsicleTests/PSInterpolationTests.m @@ -0,0 +1,33 @@ +// +// PSInterpolationTests.m +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +#import "PSInterpolation.h" +#import "PSInterpolation+Subclass.h" + +@interface PSInterpolationTests : XCTestCase + +@end + +@implementation PSInterpolationTests + +- (void)testInterpolation { + XCTAssertEqual(Interpolation(10, 20, 0.75), 17.5); +} + +- (void)testInitialization { + PSInterpolation *interpolation = PS(PSInterpolation, 20, 30, [NSObject new], [NSObject new]); + + XCTAssertEqual(interpolation.startTime, 20); + XCTAssertEqual(interpolation.endTime, 30); + XCTAssertNotNil(interpolation.fromValue); + XCTAssertNotNil(interpolation.toValue); +} + +@end diff --git a/PopsicleTests/PSPointInterpolationTests.m b/PopsicleTests/PSPointInterpolationTests.m new file mode 100644 index 0000000..abe66e0 --- /dev/null +++ b/PopsicleTests/PSPointInterpolationTests.m @@ -0,0 +1,33 @@ +// +// PSPointInterpolationTests.m +// Popsicle +// +// Created by David Román Aguirre on 1/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +#import "PSPointInterpolation.h" +#import "PSInterpolation+Subclass.h" + +@interface PSPointInterpolationTests : XCTestCase + +@end + +@implementation PSPointInterpolationTests + +- (void)testPointInterpolation { + PSPointInterpolation *interpolation = PS(PSPointInterpolation, 0, 100, CGPointMake(30, 10), CGPointMake(90, 20)); + + XCTAssertEqual([[interpolation valueForTimeFraction:0] CGPointValue].x, 30); + XCTAssertEqual([[interpolation valueForTimeFraction:0] CGPointValue].y, 10); + + XCTAssertEqual([[interpolation valueForTimeFraction:0.5] CGPointValue].x, 60); + XCTAssertEqual([[interpolation valueForTimeFraction:0.5] CGPointValue].y, 15); + + XCTAssertEqual([[interpolation valueForTimeFraction:1] CGPointValue].x, 90); + XCTAssertEqual([[interpolation valueForTimeFraction:1] CGPointValue].y, 20); +} + +@end diff --git a/PopsicleTests/PSRectInterpolationTests.m b/PopsicleTests/PSRectInterpolationTests.m new file mode 100644 index 0000000..7fbefe4 --- /dev/null +++ b/PopsicleTests/PSRectInterpolationTests.m @@ -0,0 +1,39 @@ +// +// PSRectInterpolationTests.m +// Popsicle +// +// Created by David Román Aguirre on 2/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +#import "PSRectInterpolation.h" +#import "PSInterpolation+Subclass.h" + +@interface PSRectInterpolationTests : XCTestCase + +@end + +@implementation PSRectInterpolationTests + +- (void)testRectInterpolation { + PSRectInterpolation *interpolation = PS(PSRectInterpolation, 0, 100, CGRectMake(30, 10, 200, 150), CGRectMake(90, 20, 100, 100)); + + XCTAssertEqual([[interpolation valueForTimeFraction:0] CGRectValue].origin.x, 30); + XCTAssertEqual([[interpolation valueForTimeFraction:0] CGRectValue].origin.y, 10); + XCTAssertEqual([[interpolation valueForTimeFraction:0] CGRectValue].size.width, 200); + XCTAssertEqual([[interpolation valueForTimeFraction:0] CGRectValue].size.height, 150); + + XCTAssertEqual([[interpolation valueForTimeFraction:0.5] CGRectValue].origin.x, 60); + XCTAssertEqual([[interpolation valueForTimeFraction:0.5] CGRectValue].origin.y, 15); + XCTAssertEqual([[interpolation valueForTimeFraction:0.5] CGRectValue].size.width, 150); + XCTAssertEqual([[interpolation valueForTimeFraction:0.5] CGRectValue].size.height, 125); + + XCTAssertEqual([[interpolation valueForTimeFraction:1] CGRectValue].origin.x, 90); + XCTAssertEqual([[interpolation valueForTimeFraction:1] CGRectValue].origin.y, 20); + XCTAssertEqual([[interpolation valueForTimeFraction:1] CGRectValue].size.width, 100); + XCTAssertEqual([[interpolation valueForTimeFraction:1] CGRectValue].size.height, 100); +} + +@end diff --git a/PopsicleTests/PSSizeInterpolationTests.m b/PopsicleTests/PSSizeInterpolationTests.m new file mode 100644 index 0000000..c04200a --- /dev/null +++ b/PopsicleTests/PSSizeInterpolationTests.m @@ -0,0 +1,33 @@ +// +// PSSizeInterpolationTests.m +// Popsicle +// +// Created by David Román Aguirre on 2/11/14. +// Copyright (c) 2014 David Roman. All rights reserved. +// + +#import + +#import "PSSizeInterpolation.h" +#import "PSInterpolation+Subclass.h" + +@interface PSSizeInterpolationTests : XCTestCase + +@end + +@implementation PSSizeInterpolationTests + +- (void)testSizeInterpolation { + PSSizeInterpolation *interpolation = PS(PSSizeInterpolation, 0, 100, CGSizeMake(30, 10), CGSizeMake(90, 20)); + + XCTAssertEqual([[interpolation valueForTimeFraction:0] CGSizeValue].width, 30); + XCTAssertEqual([[interpolation valueForTimeFraction:0] CGSizeValue].height, 10); + + XCTAssertEqual([[interpolation valueForTimeFraction:0.5] CGSizeValue].width, 60); + XCTAssertEqual([[interpolation valueForTimeFraction:0.5] CGSizeValue].height, 15); + + XCTAssertEqual([[interpolation valueForTimeFraction:1] CGSizeValue].width, 90); + XCTAssertEqual([[interpolation valueForTimeFraction:1] CGSizeValue].height, 20); +} + +@end diff --git a/README.md b/README.md new file mode 100644 index 0000000..a9503d1 --- /dev/null +++ b/README.md @@ -0,0 +1,113 @@ +

+ Header +

+ +Popsicle is an easy-as-pie approach to creating and managing interpolations of different value types, as well as implementing your own custom value interpolations. + +

+ GIF 1 +

+ +_Note: this framework comes out as an abstraction of former `DRDynamicSlideShow`'s keyframing logic. You can combine this framework with components such as [__`DRPageScrollView`__](https://github.com/Dromaguirre/DRPageScrollView) or vanilla `UIScrollView` and still get the same functionality provided by `DRDynamicSlideShow`._ + +## Installation + +#### Carthage + + github "Dromaguirre/Popsicle" + +#### CocoaPods + + pod 'Popsicle' + +#### Manual + +Drag and copy all files in the [__Popsicle__](Popsicle) folder into your project. + +## At a glance + +#### Interpolating UIView values + +`Popsicle` is basically divided in two classes: `PSInterpolator` and `PSInterpolation`. + +First, you need a retained instance of `PSInterpolator`, which is as simple as declaring it as a property or ivar (commonly in your view controller) and initializing it like this: + +```objective-c +interpolator = [PSInterpolator new]; +``` + +_Note: `interpolator` has a `time` property. Every `PSInterpolation` instance you add to that `PSInterpolator` instance will depend on that property to determine its current value. `time` is an abstract concept here, and has nothing to do with literal time. You may define `time` however you want. For example, `time` may be the position of a finger on the screen from 0 to 240, determined by a `UIPanGestureRecognizer`, or the amount of brightness of the screen from 0 to 1, determined by `UIScreen`._ + +Next, you need to add some `PSInterpolation` instances to your `interpolator`. In the example below, we are going to interpolate the alpha value of a UIView through a `PSFloatInterpolation`, with a `time` range of 0 to 100: + +```objective-c +[self.interpolator addInterpolations:PS(PSFloatInterpolation, 0, 100, 1, 0) forObjects:view keyPath:@"alpha"]; +``` + +_Note: for the sake of simplicity, Popsicle provides a great macro to create instances of `PSInterpolation`: `PS(INTERPOLATION_CLASS, START_TIME, END_TIME, FROM_VALUE, TO_VALUE)`. Also note you can specify multiple interpolations for multiple objects at once._ + +Finally, just make your `interpolator` varie its `time` depending on whatever you want. For example, in case you're using a `UIScrollView`: + +```objective-c +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + interpolator.time = scrollView.contentOffset.x + // view.alpha = 1 when scrollView.contentOffset.x = 0 + // view.alpha = 0.75 when scrollView.contentOffset.x = 25 + // view.alpha = 0.5 when scrollView.contentOffset.x = 50 + // ... and so on. +} +``` + +#### Creating custom value interpolations + +You can create your own value interpolations subclassing `PSInterpolation`. + +In the example below, you'll see how `PSFloatInterpolation` has been implemented. + +```objective-c +// PSFloatInterpolation.h + +#import "PSInterpolation.h" + +@interface PSFloatInterpolation : PSInterpolation + +// This allows `PS()` macro to work correctly. ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(float)fromValue toValue:(float)toValue; + +@end +``` + +```objective-c +// PSFloatInterpolation.h + +#import "PSFloatInterpolation.h" +#import "PSInterpolation+Subclass.h" // Notice you need this file for Interpolation() to work. + +@implementation PSFloatInterpolation + +// Remember fromValue and toValue are objects, so we need to pass in a NSNumber. You may make any necessary value conversions as shown below. +// If this library was written in Swift, this "problem" wouldn't exist, since values like float are already objects in Swift. Give me some time :) ++ (instancetype)interpolationWithStartTime:(float)startTime endTime:(float)endTime fromValue:(float)fromValue toValue:(float)toValue { + return [super interpolationWithStartTime:startTime endTime:endTime fromValue:@(fromValue) toValue:@(toValue)]; +} + +// This method is called whenever PSInterpolator performs a new interpolation, so you must return a value here depending on timeFraction (from 0 to 1). +// The easiest way possible is using Interpolation(), already included in PSInterpolation+Subclass.h. +- (id)valueForTimeFraction:(float)timeFraction { + // Here we retrieve our fromValue and toValue and convert them to float in order to manage them with Interpolation(). + float fromValue = [self.fromValue floatValue]; + float toValue = [self.toValue floatValue]; + + // Here we interpolate fromValue and toValue depending on the parameter timeFraction in order to get the intermediate value we need to return. + float value = Interpolation(fromValue, toValue, timeFraction); + + // Here we retrieve our fromValue and toValue and convert them to float in order to manage them with Interpolation(). + return @(value); +} + +@end +``` + +## License + +Popsicle is available under the MIT license. \ No newline at end of file