├── .gitignore ├── .swift-version ├── .travis.yml ├── CHANGELOG.md ├── Example ├── Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Resources │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── play.imageset │ │ │ ├── Contents.json │ │ │ ├── play_24x24@2x.png │ │ │ └── play_24x24@3x.png │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ └── Info.plist └── Source │ ├── AppDelegate.swift │ └── ViewController.swift ├── LICENSE ├── Package.swift ├── README.md ├── SimpleAnimation.podspec ├── SimpleAnimation.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── SimpleAnimation.xcscheme ├── SimpleAnimation.xcworkspace └── contents.xcworkspacedata ├── Source ├── Info.plist ├── PrivacyInfo.xcprivacy └── UIView+SimpleAnimation.swift ├── Tests ├── Info.plist └── UIView+SimpleAnimationTest.swift └── screenshots ├── bounceIn.gif ├── customShake.gif ├── popIn.gif └── shake.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | Carthage 26 | Pods/ 27 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | language: objective-c 6 | osx_image: xcode10.1 7 | before_install: 8 | - gem install cocoapods xcpretty --no-rdoc --no-ri --no-document --quiet 9 | script: 10 | - set -o pipefail && xcodebuild test -workspace SimpleAnimation.xcworkspace -scheme SimpleAnimation -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=12.1' ONLY_ACTIVE_ARCH=NO | xcpretty 11 | - pod lib lint --quick 12 | - carthage build --no-skip-current 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.4.0](https://github.com/keithito/SimpleAnimation/releases/tag/0.4.0) 2 | *2017-12-21* 3 | 4 | - Migrate project to Swift 4 - [#16](https://github.com/keithito/SimpleAnimation/pull/16) 5 | If using Xcode 8, please use the 0.3.2 release. 6 | 7 | 8 | ## [0.3.2](https://github.com/keithito/SimpleAnimation/releases/tag/0.3.2) 9 | *2017-08-21* 10 | 11 | - Add fadeColor animation - [#15](https://github.com/keithito/SimpleAnimation/pull/15) 12 | 13 | 14 | ## [0.3.1](https://github.com/keithito/SimpleAnimation/releases/tag/0.3.1) 15 | *2017-01-10* 16 | 17 | - Add support for tvOS - [#12](https://github.com/keithito/SimpleAnimation/pull/12) 18 | 19 | 20 | ## [0.3.0](https://github.com/keithito/SimpleAnimation/releases/tag/0.3.0) 21 | *2016-09-24* 22 | 23 | - Migrate to Swift 3 - [#11](https://github.com/keithito/SimpleAnimation/pull/11) 24 | For Swift 2.2 or 2.3, please use the 0.2.0 release. 25 | 26 | 27 | ## [0.2.0](https://github.com/keithito/SimpleAnimation/releases/tag/0.2.0) 28 | *2016-07-24* 29 | 30 | - Completion blocks for animations - [#9](https://github.com/keithito/SimpleAnimation/pull/9) 31 | 32 | 33 | ## [0.1.3](https://github.com/keithito/SimpleAnimation/releases/tag/0.1.3) 34 | *2016-04-21* 35 | 36 | - Support Carthage - [#8](https://github.com/keithito/SimpleAnimation/pull/8) 37 | 38 | 39 | ## [0.1.2](https://github.com/keithito/SimpleAnimation/releases/tag/0.1.2) 40 | *2016-04-20* 41 | 42 | - Add documentation - [#6](https://github.com/keithito/SimpleAnimation/pull/6) 43 | 44 | 45 | ## [0.1.1](https://github.com/keithito/SimpleAnimation/releases/tag/0.1.1) 46 | *2016-04-19* 47 | 48 | Initial release. 49 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4005237C1CC973B900E6DDA3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4005237A1CC973B900E6DDA3 /* AppDelegate.swift */; }; 11 | 4005237D1CC973B900E6DDA3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4005237B1CC973B900E6DDA3 /* ViewController.swift */; }; 12 | 400523801CC973C600E6DDA3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4005237F1CC973C600E6DDA3 /* Assets.xcassets */; }; 13 | 400523871CC973E100E6DDA3 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 400523831CC973E100E6DDA3 /* LaunchScreen.xib */; }; 14 | 400523881CC973E100E6DDA3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 400523851CC973E100E6DDA3 /* Main.storyboard */; }; 15 | 407C88111F4B2AD60077A2BC /* UIView+SimpleAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 407C88101F4B2AD60077A2BC /* UIView+SimpleAnimation.swift */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 400523511CC7B94C00E6DDA3 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | 4005237A1CC973B900E6DDA3 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Source/AppDelegate.swift; sourceTree = ""; }; 21 | 4005237B1CC973B900E6DDA3 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ViewController.swift; path = Source/ViewController.swift; sourceTree = ""; }; 22 | 4005237F1CC973C600E6DDA3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Resources/Assets.xcassets; sourceTree = ""; }; 23 | 400523841CC973E100E6DDA3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Resources/Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 24 | 400523861CC973E100E6DDA3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Resources/Base.lproj/Main.storyboard; sourceTree = ""; }; 25 | 400523891CC973F200E6DDA3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Resources/Info.plist; sourceTree = ""; }; 26 | 407C88101F4B2AD60077A2BC /* UIView+SimpleAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+SimpleAnimation.swift"; path = "../Source/UIView+SimpleAnimation.swift"; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | 4005234E1CC7B94C00E6DDA3 /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | ); 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXFrameworksBuildPhase section */ 38 | 39 | /* Begin PBXGroup section */ 40 | 400523481CC7B94C00E6DDA3 = { 41 | isa = PBXGroup; 42 | children = ( 43 | 400523791CC973A900E6DDA3 /* Source */, 44 | 4005237F1CC973C600E6DDA3 /* Assets.xcassets */, 45 | 400523851CC973E100E6DDA3 /* Main.storyboard */, 46 | 400523831CC973E100E6DDA3 /* LaunchScreen.xib */, 47 | 400523891CC973F200E6DDA3 /* Info.plist */, 48 | 400523521CC7B94C00E6DDA3 /* Products */, 49 | ); 50 | sourceTree = ""; 51 | }; 52 | 400523521CC7B94C00E6DDA3 /* Products */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 400523511CC7B94C00E6DDA3 /* Example.app */, 56 | ); 57 | name = Products; 58 | sourceTree = ""; 59 | }; 60 | 400523791CC973A900E6DDA3 /* Source */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 407C88101F4B2AD60077A2BC /* UIView+SimpleAnimation.swift */, 64 | 4005237A1CC973B900E6DDA3 /* AppDelegate.swift */, 65 | 4005237B1CC973B900E6DDA3 /* ViewController.swift */, 66 | ); 67 | name = Source; 68 | sourceTree = ""; 69 | }; 70 | /* End PBXGroup section */ 71 | 72 | /* Begin PBXNativeTarget section */ 73 | 400523501CC7B94C00E6DDA3 /* Example */ = { 74 | isa = PBXNativeTarget; 75 | buildConfigurationList = 400523631CC7B94C00E6DDA3 /* Build configuration list for PBXNativeTarget "Example" */; 76 | buildPhases = ( 77 | 4005234D1CC7B94C00E6DDA3 /* Sources */, 78 | 4005234E1CC7B94C00E6DDA3 /* Frameworks */, 79 | 4005234F1CC7B94C00E6DDA3 /* Resources */, 80 | ); 81 | buildRules = ( 82 | ); 83 | dependencies = ( 84 | ); 85 | name = Example; 86 | productName = Example; 87 | productReference = 400523511CC7B94C00E6DDA3 /* Example.app */; 88 | productType = "com.apple.product-type.application"; 89 | }; 90 | /* End PBXNativeTarget section */ 91 | 92 | /* Begin PBXProject section */ 93 | 400523491CC7B94C00E6DDA3 /* Project object */ = { 94 | isa = PBXProject; 95 | attributes = { 96 | LastSwiftUpdateCheck = 0730; 97 | LastUpgradeCheck = 0730; 98 | ORGANIZATIONNAME = "Keith Ito"; 99 | TargetAttributes = { 100 | 400523501CC7B94C00E6DDA3 = { 101 | CreatedOnToolsVersion = 7.3; 102 | LastSwiftMigration = 0920; 103 | }; 104 | }; 105 | }; 106 | buildConfigurationList = 4005234C1CC7B94C00E6DDA3 /* Build configuration list for PBXProject "Example" */; 107 | compatibilityVersion = "Xcode 3.2"; 108 | developmentRegion = English; 109 | hasScannedForEncodings = 0; 110 | knownRegions = ( 111 | en, 112 | Base, 113 | ); 114 | mainGroup = 400523481CC7B94C00E6DDA3; 115 | productRefGroup = 400523521CC7B94C00E6DDA3 /* Products */; 116 | projectDirPath = ""; 117 | projectRoot = ""; 118 | targets = ( 119 | 400523501CC7B94C00E6DDA3 /* Example */, 120 | ); 121 | }; 122 | /* End PBXProject section */ 123 | 124 | /* Begin PBXResourcesBuildPhase section */ 125 | 4005234F1CC7B94C00E6DDA3 /* Resources */ = { 126 | isa = PBXResourcesBuildPhase; 127 | buildActionMask = 2147483647; 128 | files = ( 129 | 400523881CC973E100E6DDA3 /* Main.storyboard in Resources */, 130 | 400523871CC973E100E6DDA3 /* LaunchScreen.xib in Resources */, 131 | 400523801CC973C600E6DDA3 /* Assets.xcassets in Resources */, 132 | ); 133 | runOnlyForDeploymentPostprocessing = 0; 134 | }; 135 | /* End PBXResourcesBuildPhase section */ 136 | 137 | /* Begin PBXSourcesBuildPhase section */ 138 | 4005234D1CC7B94C00E6DDA3 /* Sources */ = { 139 | isa = PBXSourcesBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | 407C88111F4B2AD60077A2BC /* UIView+SimpleAnimation.swift in Sources */, 143 | 4005237D1CC973B900E6DDA3 /* ViewController.swift in Sources */, 144 | 4005237C1CC973B900E6DDA3 /* AppDelegate.swift in Sources */, 145 | ); 146 | runOnlyForDeploymentPostprocessing = 0; 147 | }; 148 | /* End PBXSourcesBuildPhase section */ 149 | 150 | /* Begin PBXVariantGroup section */ 151 | 400523831CC973E100E6DDA3 /* LaunchScreen.xib */ = { 152 | isa = PBXVariantGroup; 153 | children = ( 154 | 400523841CC973E100E6DDA3 /* Base */, 155 | ); 156 | name = LaunchScreen.xib; 157 | sourceTree = ""; 158 | }; 159 | 400523851CC973E100E6DDA3 /* Main.storyboard */ = { 160 | isa = PBXVariantGroup; 161 | children = ( 162 | 400523861CC973E100E6DDA3 /* Base */, 163 | ); 164 | name = Main.storyboard; 165 | sourceTree = ""; 166 | }; 167 | /* End PBXVariantGroup section */ 168 | 169 | /* Begin XCBuildConfiguration section */ 170 | 400523611CC7B94C00E6DDA3 /* Debug */ = { 171 | isa = XCBuildConfiguration; 172 | buildSettings = { 173 | ALWAYS_SEARCH_USER_PATHS = NO; 174 | CLANG_ANALYZER_NONNULL = YES; 175 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 176 | CLANG_CXX_LIBRARY = "libc++"; 177 | CLANG_ENABLE_MODULES = YES; 178 | CLANG_ENABLE_OBJC_ARC = YES; 179 | CLANG_WARN_BOOL_CONVERSION = YES; 180 | CLANG_WARN_CONSTANT_CONVERSION = YES; 181 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 182 | CLANG_WARN_EMPTY_BODY = YES; 183 | CLANG_WARN_ENUM_CONVERSION = YES; 184 | CLANG_WARN_INT_CONVERSION = YES; 185 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 186 | CLANG_WARN_UNREACHABLE_CODE = YES; 187 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 188 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 189 | COPY_PHASE_STRIP = NO; 190 | DEBUG_INFORMATION_FORMAT = dwarf; 191 | ENABLE_STRICT_OBJC_MSGSEND = YES; 192 | ENABLE_TESTABILITY = YES; 193 | GCC_C_LANGUAGE_STANDARD = gnu99; 194 | GCC_DYNAMIC_NO_PIC = NO; 195 | GCC_NO_COMMON_BLOCKS = YES; 196 | GCC_OPTIMIZATION_LEVEL = 0; 197 | GCC_PREPROCESSOR_DEFINITIONS = ( 198 | "DEBUG=1", 199 | "$(inherited)", 200 | ); 201 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 202 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 203 | GCC_WARN_UNDECLARED_SELECTOR = YES; 204 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 205 | GCC_WARN_UNUSED_FUNCTION = YES; 206 | GCC_WARN_UNUSED_VARIABLE = YES; 207 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 208 | MTL_ENABLE_DEBUG_INFO = YES; 209 | ONLY_ACTIVE_ARCH = YES; 210 | SDKROOT = iphoneos; 211 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 212 | TARGETED_DEVICE_FAMILY = "1,2"; 213 | }; 214 | name = Debug; 215 | }; 216 | 400523621CC7B94C00E6DDA3 /* Release */ = { 217 | isa = XCBuildConfiguration; 218 | buildSettings = { 219 | ALWAYS_SEARCH_USER_PATHS = NO; 220 | CLANG_ANALYZER_NONNULL = YES; 221 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 222 | CLANG_CXX_LIBRARY = "libc++"; 223 | CLANG_ENABLE_MODULES = YES; 224 | CLANG_ENABLE_OBJC_ARC = YES; 225 | CLANG_WARN_BOOL_CONVERSION = YES; 226 | CLANG_WARN_CONSTANT_CONVERSION = YES; 227 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 228 | CLANG_WARN_EMPTY_BODY = YES; 229 | CLANG_WARN_ENUM_CONVERSION = YES; 230 | CLANG_WARN_INT_CONVERSION = YES; 231 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 232 | CLANG_WARN_UNREACHABLE_CODE = YES; 233 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 234 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 235 | COPY_PHASE_STRIP = NO; 236 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 237 | ENABLE_NS_ASSERTIONS = NO; 238 | ENABLE_STRICT_OBJC_MSGSEND = YES; 239 | GCC_C_LANGUAGE_STANDARD = gnu99; 240 | GCC_NO_COMMON_BLOCKS = YES; 241 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 242 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 243 | GCC_WARN_UNDECLARED_SELECTOR = YES; 244 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 245 | GCC_WARN_UNUSED_FUNCTION = YES; 246 | GCC_WARN_UNUSED_VARIABLE = YES; 247 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 248 | MTL_ENABLE_DEBUG_INFO = NO; 249 | SDKROOT = iphoneos; 250 | TARGETED_DEVICE_FAMILY = "1,2"; 251 | VALIDATE_PRODUCT = YES; 252 | }; 253 | name = Release; 254 | }; 255 | 400523641CC7B94C00E6DDA3 /* Debug */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 259 | CLANG_ENABLE_MODULES = YES; 260 | INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; 261 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 262 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 263 | PRODUCT_BUNDLE_IDENTIFIER = com.keithito.SimpleAnimationExample; 264 | PRODUCT_NAME = "$(TARGET_NAME)"; 265 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 266 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 267 | SWIFT_VERSION = 4.0; 268 | }; 269 | name = Debug; 270 | }; 271 | 400523651CC7B94C00E6DDA3 /* Release */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 275 | CLANG_ENABLE_MODULES = YES; 276 | INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; 277 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 278 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 279 | PRODUCT_BUNDLE_IDENTIFIER = com.keithito.SimpleAnimationExample; 280 | PRODUCT_NAME = "$(TARGET_NAME)"; 281 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 282 | SWIFT_VERSION = 4.0; 283 | }; 284 | name = Release; 285 | }; 286 | /* End XCBuildConfiguration section */ 287 | 288 | /* Begin XCConfigurationList section */ 289 | 4005234C1CC7B94C00E6DDA3 /* Build configuration list for PBXProject "Example" */ = { 290 | isa = XCConfigurationList; 291 | buildConfigurations = ( 292 | 400523611CC7B94C00E6DDA3 /* Debug */, 293 | 400523621CC7B94C00E6DDA3 /* Release */, 294 | ); 295 | defaultConfigurationIsVisible = 0; 296 | defaultConfigurationName = Release; 297 | }; 298 | 400523631CC7B94C00E6DDA3 /* Build configuration list for PBXNativeTarget "Example" */ = { 299 | isa = XCConfigurationList; 300 | buildConfigurations = ( 301 | 400523641CC7B94C00E6DDA3 /* Debug */, 302 | 400523651CC7B94C00E6DDA3 /* Release */, 303 | ); 304 | defaultConfigurationIsVisible = 0; 305 | defaultConfigurationName = Release; 306 | }; 307 | /* End XCConfigurationList section */ 308 | }; 309 | rootObject = 400523491CC7B94C00E6DDA3 /* Project object */; 310 | } 311 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/play.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "play_24x24@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "play_24x24@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/play.imageset/play_24x24@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keithito/SimpleAnimation/8f7c63ea1049d67b2b1f044cbd2eef150e1df656/Example/Resources/Assets.xcassets/play.imageset/play_24x24@2x.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/play.imageset/play_24x24@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keithito/SimpleAnimation/8f7c63ea1049d67b2b1f044cbd2eef150e1df656/Example/Resources/Assets.xcassets/play.imageset/play_24x24@3x.png -------------------------------------------------------------------------------- /Example/Resources/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Example/Resources/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /Example/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Example/Source/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SimpleAnimation 4 | // 5 | // Created by Keith Ito on 04/18/2016. 6 | // Copyright (c) 2016 Keith Ito. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | var window: UIWindow? 14 | 15 | func application(_ application: UIApplication, 16 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 17 | return true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Example/Source/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SimpleAnimation 4 | // 5 | // Created by Keith Ito on 04/18/2016. 6 | // Copyright (c) 2016 Keith Ito. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private enum AnimationExampleType: String { 12 | case fadeIn = "fadeIn()" 13 | case fadeOut = "fadeOut()" 14 | case fadeColor = "fadeColor(toColor: .blue)" 15 | case popIn = "popIn()" 16 | case popOut = "popOut()" 17 | case slideInFromTop = "slideIn(from: .top)" 18 | case slideInFromBottom = "slideIn(from: .bottom)" 19 | case slideInFromLeft = "slideIn(from: .left)" 20 | case slideInFromRight = "slideIn(from: .right)" 21 | case slideOutToTop = "slideOut(to: .top)" 22 | case slideOutToBottom = "slideOut(to: .bottom)" 23 | case slideOutToLeft = "slideOut(to: .left)" 24 | case slideOutToRight = "slideOut(to: .right)" 25 | case bounceInFromTop = "bounceIn(from: .top)" 26 | case bounceInFromBottom = "bounceIn(from: .bottom)" 27 | case bounceInFromLeft = "bounceIn(from: .left)" 28 | case bounceInFromRight = "bounceIn(from: .right)" 29 | case bounceOutToTop = "bounceOut(to: .top)" 30 | case bounceOutToBottom = "bounceOut(to: .bottom)" 31 | case bounceOutToLeft = "bounceOut(to: .left)" 32 | case bounceOutToRight = "bounceOut(to: .right)" 33 | case shake = "shake()" 34 | case shakeTowardLeft = "shake(toward: .left)" 35 | case shakeTowardTop = "shake(toward: .top)" 36 | case hop = "hop()" 37 | case hopTowardTop = "hop(toward: .top)" 38 | case hopTowardBottom = "hop(toward: .bottom)" 39 | case hopTowardLeft = "hop(toward: .left)" 40 | case hopTowardRight = "hop(toward: .right)" 41 | } 42 | 43 | private let AllExamples: [AnimationExampleType] = [ 44 | .fadeIn, 45 | .fadeOut, 46 | .fadeColor, 47 | .popIn, 48 | .popOut, 49 | .slideInFromTop, 50 | .slideInFromBottom, 51 | .slideInFromLeft, 52 | .slideInFromRight, 53 | .slideOutToTop, 54 | .slideOutToBottom, 55 | .slideOutToLeft, 56 | .slideOutToRight, 57 | .bounceInFromTop, 58 | .bounceInFromBottom, 59 | .bounceInFromLeft, 60 | .bounceInFromRight, 61 | .bounceOutToTop, 62 | .bounceOutToBottom, 63 | .bounceOutToLeft, 64 | .bounceOutToRight, 65 | .shake, 66 | .shakeTowardLeft, 67 | .shakeTowardTop, 68 | .hop, 69 | .hopTowardTop, 70 | .hopTowardBottom, 71 | .hopTowardLeft, 72 | .hopTowardRight, 73 | ] 74 | 75 | class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource { 76 | @IBOutlet weak var animatedView: UIView! 77 | @IBOutlet weak var typePicker: UIPickerView! 78 | @IBOutlet weak var startButton: UIButton! 79 | 80 | override func viewDidLoad() { 81 | super.viewDidLoad() 82 | animatedView.layer.cornerRadius = 20 83 | } 84 | 85 | @IBAction func startButtonPressed(_ sender: AnyObject) { 86 | startAnimation(AllExamples[typePicker.selectedRow(inComponent: 0)]) 87 | } 88 | 89 | func numberOfComponents(in pickerView: UIPickerView) -> Int { 90 | return 1 91 | } 92 | 93 | func pickerView(_ view: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 94 | return AllExamples.count 95 | } 96 | 97 | func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, 98 | reusing view: UIView?) -> UIView { 99 | let label = UILabel() 100 | label.text = AllExamples[row].rawValue 101 | label.font = UIFont(name: "Courier", size: 15) 102 | label.textAlignment = .center 103 | label.textColor = UIColor.black 104 | return label 105 | } 106 | 107 | private func startAnimation(_ type: AnimationExampleType) { 108 | animatedView.transform = .identity 109 | switch (type) { 110 | case .fadeIn: 111 | animatedView.fadeIn() 112 | case .fadeOut: 113 | animatedView.alpha = 1 114 | animatedView.fadeOut() 115 | case .fadeColor: 116 | animatedView.alpha = 1 117 | animatedView.fadeColor(toColor: .blue) 118 | case .popIn: 119 | animatedView.popIn() 120 | case .popOut: 121 | animatedView.alpha = 1 122 | animatedView.popOut() 123 | case .slideInFromTop: 124 | animatedView.slideIn(from: .top) 125 | case .slideInFromBottom: 126 | animatedView.slideIn(from: .bottom) 127 | case .slideInFromLeft: 128 | animatedView.slideIn(from: .left) 129 | case .slideInFromRight: 130 | animatedView.slideIn(from: .right) 131 | case .slideOutToTop: 132 | animatedView.alpha = 1 133 | animatedView.slideOut(to: .top) 134 | case .slideOutToBottom: 135 | animatedView.alpha = 1 136 | animatedView.slideOut(to: .bottom) 137 | case .slideOutToLeft: 138 | animatedView.alpha = 1 139 | animatedView.slideOut(to: .left) 140 | case .slideOutToRight: 141 | animatedView.alpha = 1 142 | animatedView.slideOut(to: .right) 143 | case .bounceInFromTop: 144 | animatedView.bounceIn(from: .top) 145 | case .bounceInFromBottom: 146 | animatedView.bounceIn(from: .bottom) 147 | case .bounceInFromLeft: 148 | animatedView.bounceIn(from: .left) 149 | case .bounceInFromRight: 150 | animatedView.bounceIn(from: .right) 151 | case .bounceOutToTop: 152 | animatedView.alpha = 1 153 | animatedView.bounceOut(to: .top) 154 | case .bounceOutToBottom: 155 | animatedView.alpha = 1 156 | animatedView.bounceOut(to: .bottom) 157 | case .bounceOutToLeft: 158 | animatedView.bounceOut(to: .left) 159 | animatedView.alpha = 1 160 | case .bounceOutToRight: 161 | animatedView.alpha = 1 162 | animatedView.bounceOut(to: .right) 163 | case .shake: 164 | animatedView.alpha = 1 165 | animatedView.shake() 166 | case .shakeTowardLeft: 167 | animatedView.alpha = 1 168 | animatedView.shake(toward: .left) 169 | case .shakeTowardTop: 170 | animatedView.alpha = 1 171 | animatedView.shake(toward: .top) 172 | case .hop: 173 | animatedView.alpha = 1 174 | animatedView.hop() 175 | case .hopTowardTop: 176 | animatedView.alpha = 1 177 | animatedView.hop(toward: .top) 178 | case .hopTowardBottom: 179 | animatedView.alpha = 1 180 | animatedView.hop(toward: .bottom) 181 | case .hopTowardLeft: 182 | animatedView.alpha = 1 183 | animatedView.hop(toward: .left) 184 | case .hopTowardRight: 185 | animatedView.alpha = 1 186 | animatedView.hop(toward: .right) 187 | } 188 | } 189 | } 190 | 191 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Keith Ito 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.8 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "SimpleAnimation", 6 | platforms: [ 7 | .iOS(.v11), 8 | .tvOS(.v11), 9 | .watchOS(.v4) 10 | ], 11 | products: [ 12 | .library(name: "SimpleAnimation", targets: ["SimpleAnimation"]), 13 | ], 14 | targets: [ 15 | .target(name: "SimpleAnimation", path: "Source", resources: [.copy("PrivacyInfo.xcprivacy")]), 16 | ], 17 | swiftLanguageVersions: [ 18 | .v5 19 | ] 20 | ) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleAnimation 2 | 3 | [![CI Status](https://travis-ci.org/keithito/SimpleAnimation.svg?branch=master)](https://travis-ci.org/keithito/SimpleAnimation) 4 | [![Version](https://img.shields.io/cocoapods/v/SimpleAnimation.svg?style=flat)](http://cocoapods.org/pods/SimpleAnimation) 5 | [![License](https://img.shields.io/cocoapods/l/SimpleAnimation.svg?style=flat)](http://cocoapods.org/pods/SimpleAnimation) 6 | [![Platform](https://img.shields.io/cocoapods/p/SimpleAnimation.svg?style=flat)](http://cocoapods.org/pods/SimpleAnimation) 7 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 8 | 9 | 10 | **SimpleAnimation is a UIView extension that makes adding basic animations, like fades and bounces, simple...** 11 | 12 | ```swift 13 | view.bounceIn(from: .left) 14 | ``` 15 | 16 | 17 | 18 | **...with sensible defaults...** 19 | 20 | ```swift 21 | view.popIn() 22 | ``` 23 | 24 | 25 | 26 | **...while remaining customizable** 27 | 28 | ```swift 29 | view.shake(toward: .top, amount: 0.5, duration: 2, delay: 0.5) 30 | ``` 31 | 32 | 33 | 34 | ## Installation 35 | 36 | ### CocoaPods 37 | 38 | To integrate SimpleAnimation into a project using [CocoaPods](http://cocoapods.org), add the following to your `Podfile`: 39 | 40 | ```ruby 41 | pod "SimpleAnimation" 42 | ``` 43 | 44 | 45 | 46 | ### Carthage 47 | 48 | To integrate SimpleAnimation into a project using [Carthage](https://github.com/Carthage/Carthage), add the following to your `Cartfile`: 49 | 50 | ``` 51 | github "keithito/SimpleAnimation" 52 | ``` 53 | 54 | 55 | ### Older Xcode Versions 56 | 57 | If you are using Xcode 8 to build your project, you need to use version **0.3.2** of SimpleAnimation. 58 | You can do so by specifying the version number in your Podfile or Cartfile. 59 | 60 | 61 | 62 | ## Supported Animations 63 | 64 | The following animations are supported so far: 65 | * fadeIn 66 | * fadeOut 67 | * fadeColor 68 | * slideIn 69 | * slideOut 70 | * bounceIn 71 | * bounceOut 72 | * popIn 73 | * popOut 74 | * hop 75 | * shake 76 | 77 | Please see the [example ViewController](Example/Source/ViewController.swift) for more usage examples. 78 | To build the example in XCode, open Example/Example.xcodeproj. 79 | 80 | 81 | ## License 82 | 83 | SimpleAnimation is available under the MIT license. See the LICENSE file for more info. 84 | -------------------------------------------------------------------------------- /SimpleAnimation.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "SimpleAnimation" 3 | s.version = "0.4.2" 4 | s.summary = "A UIView extension to make basic animations, like fades and bounces, simple." 5 | s.homepage = "https://github.com/keithito/SimpleAnimation" 6 | s.license = 'MIT' 7 | s.author = { "Keith Ito" => "kito@kito.us" } 8 | s.source = { :git => "https://github.com/keithito/SimpleAnimation.git", :tag => s.version.to_s } 9 | s.social_media_url = 'https://twitter.com/keeeto' 10 | 11 | s.ios.deployment_target = '8.0' 12 | s.tvos.deployment_target = '9.0' 13 | 14 | s.source_files = 'Source/*' 15 | s.exclude_files = 'Source/*.plist' 16 | s.frameworks = 'UIKit' 17 | end 18 | -------------------------------------------------------------------------------- /SimpleAnimation.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4005232F1CC7B47800E6DDA3 /* SimpleAnimation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 400523241CC7B47800E6DDA3 /* SimpleAnimation.framework */; }; 11 | 4005233F1CC7B51F00E6DDA3 /* UIView+SimpleAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4005233E1CC7B51F00E6DDA3 /* UIView+SimpleAnimation.swift */; }; 12 | 400523471CC7B87500E6DDA3 /* UIView+SimpleAnimationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400523431CC7B5E000E6DDA3 /* UIView+SimpleAnimationTest.swift */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXContainerItemProxy section */ 16 | 400523301CC7B47800E6DDA3 /* PBXContainerItemProxy */ = { 17 | isa = PBXContainerItemProxy; 18 | containerPortal = 4005231B1CC7B47800E6DDA3 /* Project object */; 19 | proxyType = 1; 20 | remoteGlobalIDString = 400523231CC7B47800E6DDA3; 21 | remoteInfo = SimpleAnimation; 22 | }; 23 | /* End PBXContainerItemProxy section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 400523241CC7B47800E6DDA3 /* SimpleAnimation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SimpleAnimation.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 4005232E1CC7B47800E6DDA3 /* SimpleAnimationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SimpleAnimationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 4005233E1CC7B51F00E6DDA3 /* UIView+SimpleAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+SimpleAnimation.swift"; path = "Source/UIView+SimpleAnimation.swift"; sourceTree = SOURCE_ROOT; }; 29 | 400523401CC7B56D00E6DDA3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Source/Info.plist; sourceTree = SOURCE_ROOT; }; 30 | 400523421CC7B5E000E6DDA3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; 31 | 400523431CC7B5E000E6DDA3 /* UIView+SimpleAnimationTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+SimpleAnimationTest.swift"; path = "Tests/UIView+SimpleAnimationTest.swift"; sourceTree = SOURCE_ROOT; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | 400523201CC7B47800E6DDA3 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | 4005232B1CC7B47800E6DDA3 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | 4005232F1CC7B47800E6DDA3 /* SimpleAnimation.framework in Frameworks */, 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | /* End PBXFrameworksBuildPhase section */ 51 | 52 | /* Begin PBXGroup section */ 53 | 4005231A1CC7B47800E6DDA3 = { 54 | isa = PBXGroup; 55 | children = ( 56 | 400523261CC7B47800E6DDA3 /* Source */, 57 | 400523321CC7B47800E6DDA3 /* Tests */, 58 | 400523251CC7B47800E6DDA3 /* Products */, 59 | ); 60 | sourceTree = ""; 61 | }; 62 | 400523251CC7B47800E6DDA3 /* Products */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 400523241CC7B47800E6DDA3 /* SimpleAnimation.framework */, 66 | 4005232E1CC7B47800E6DDA3 /* SimpleAnimationTests.xctest */, 67 | ); 68 | name = Products; 69 | sourceTree = ""; 70 | }; 71 | 400523261CC7B47800E6DDA3 /* Source */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 4005233E1CC7B51F00E6DDA3 /* UIView+SimpleAnimation.swift */, 75 | 400523401CC7B56D00E6DDA3 /* Info.plist */, 76 | ); 77 | name = Source; 78 | path = SimpleAnimation; 79 | sourceTree = ""; 80 | }; 81 | 400523321CC7B47800E6DDA3 /* Tests */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 400523431CC7B5E000E6DDA3 /* UIView+SimpleAnimationTest.swift */, 85 | 400523421CC7B5E000E6DDA3 /* Info.plist */, 86 | ); 87 | name = Tests; 88 | path = SimpleAnimationTests; 89 | sourceTree = ""; 90 | }; 91 | /* End PBXGroup section */ 92 | 93 | /* Begin PBXHeadersBuildPhase section */ 94 | 400523211CC7B47800E6DDA3 /* Headers */ = { 95 | isa = PBXHeadersBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | /* End PBXHeadersBuildPhase section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 400523231CC7B47800E6DDA3 /* SimpleAnimation */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 400523381CC7B47800E6DDA3 /* Build configuration list for PBXNativeTarget "SimpleAnimation" */; 107 | buildPhases = ( 108 | 4005231F1CC7B47800E6DDA3 /* Sources */, 109 | 400523201CC7B47800E6DDA3 /* Frameworks */, 110 | 400523211CC7B47800E6DDA3 /* Headers */, 111 | 400523221CC7B47800E6DDA3 /* Resources */, 112 | ); 113 | buildRules = ( 114 | ); 115 | dependencies = ( 116 | ); 117 | name = SimpleAnimation; 118 | productName = SimpleAnimation; 119 | productReference = 400523241CC7B47800E6DDA3 /* SimpleAnimation.framework */; 120 | productType = "com.apple.product-type.framework"; 121 | }; 122 | 4005232D1CC7B47800E6DDA3 /* SimpleAnimationTests */ = { 123 | isa = PBXNativeTarget; 124 | buildConfigurationList = 4005233B1CC7B47800E6DDA3 /* Build configuration list for PBXNativeTarget "SimpleAnimationTests" */; 125 | buildPhases = ( 126 | 4005232A1CC7B47800E6DDA3 /* Sources */, 127 | 4005232B1CC7B47800E6DDA3 /* Frameworks */, 128 | 4005232C1CC7B47800E6DDA3 /* Resources */, 129 | ); 130 | buildRules = ( 131 | ); 132 | dependencies = ( 133 | 400523311CC7B47800E6DDA3 /* PBXTargetDependency */, 134 | ); 135 | name = SimpleAnimationTests; 136 | productName = SimpleAnimationTests; 137 | productReference = 4005232E1CC7B47800E6DDA3 /* SimpleAnimationTests.xctest */; 138 | productType = "com.apple.product-type.bundle.unit-test"; 139 | }; 140 | /* End PBXNativeTarget section */ 141 | 142 | /* Begin PBXProject section */ 143 | 4005231B1CC7B47800E6DDA3 /* Project object */ = { 144 | isa = PBXProject; 145 | attributes = { 146 | LastSwiftUpdateCheck = 0730; 147 | LastUpgradeCheck = 0920; 148 | ORGANIZATIONNAME = "Keith Ito"; 149 | TargetAttributes = { 150 | 400523231CC7B47800E6DDA3 = { 151 | CreatedOnToolsVersion = 7.3; 152 | LastSwiftMigration = 0800; 153 | ProvisioningStyle = Automatic; 154 | }; 155 | 4005232D1CC7B47800E6DDA3 = { 156 | CreatedOnToolsVersion = 7.3; 157 | LastSwiftMigration = 0800; 158 | }; 159 | }; 160 | }; 161 | buildConfigurationList = 4005231E1CC7B47800E6DDA3 /* Build configuration list for PBXProject "SimpleAnimation" */; 162 | compatibilityVersion = "Xcode 3.2"; 163 | developmentRegion = English; 164 | hasScannedForEncodings = 0; 165 | knownRegions = ( 166 | en, 167 | ); 168 | mainGroup = 4005231A1CC7B47800E6DDA3; 169 | productRefGroup = 400523251CC7B47800E6DDA3 /* Products */; 170 | projectDirPath = ""; 171 | projectRoot = ""; 172 | targets = ( 173 | 400523231CC7B47800E6DDA3 /* SimpleAnimation */, 174 | 4005232D1CC7B47800E6DDA3 /* SimpleAnimationTests */, 175 | ); 176 | }; 177 | /* End PBXProject section */ 178 | 179 | /* Begin PBXResourcesBuildPhase section */ 180 | 400523221CC7B47800E6DDA3 /* Resources */ = { 181 | isa = PBXResourcesBuildPhase; 182 | buildActionMask = 2147483647; 183 | files = ( 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | 4005232C1CC7B47800E6DDA3 /* Resources */ = { 188 | isa = PBXResourcesBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | ); 192 | runOnlyForDeploymentPostprocessing = 0; 193 | }; 194 | /* End PBXResourcesBuildPhase section */ 195 | 196 | /* Begin PBXSourcesBuildPhase section */ 197 | 4005231F1CC7B47800E6DDA3 /* Sources */ = { 198 | isa = PBXSourcesBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | 4005233F1CC7B51F00E6DDA3 /* UIView+SimpleAnimation.swift in Sources */, 202 | ); 203 | runOnlyForDeploymentPostprocessing = 0; 204 | }; 205 | 4005232A1CC7B47800E6DDA3 /* Sources */ = { 206 | isa = PBXSourcesBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | 400523471CC7B87500E6DDA3 /* UIView+SimpleAnimationTest.swift in Sources */, 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | }; 213 | /* End PBXSourcesBuildPhase section */ 214 | 215 | /* Begin PBXTargetDependency section */ 216 | 400523311CC7B47800E6DDA3 /* PBXTargetDependency */ = { 217 | isa = PBXTargetDependency; 218 | target = 400523231CC7B47800E6DDA3 /* SimpleAnimation */; 219 | targetProxy = 400523301CC7B47800E6DDA3 /* PBXContainerItemProxy */; 220 | }; 221 | /* End PBXTargetDependency section */ 222 | 223 | /* Begin XCBuildConfiguration section */ 224 | 400523361CC7B47800E6DDA3 /* Debug */ = { 225 | isa = XCBuildConfiguration; 226 | buildSettings = { 227 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 228 | ALWAYS_SEARCH_USER_PATHS = NO; 229 | CLANG_ANALYZER_NONNULL = YES; 230 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 231 | CLANG_CXX_LIBRARY = "libc++"; 232 | CLANG_ENABLE_MODULES = YES; 233 | CLANG_ENABLE_OBJC_ARC = YES; 234 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 235 | CLANG_WARN_BOOL_CONVERSION = YES; 236 | CLANG_WARN_COMMA = YES; 237 | CLANG_WARN_CONSTANT_CONVERSION = YES; 238 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 239 | CLANG_WARN_EMPTY_BODY = YES; 240 | CLANG_WARN_ENUM_CONVERSION = YES; 241 | CLANG_WARN_INFINITE_RECURSION = YES; 242 | CLANG_WARN_INT_CONVERSION = YES; 243 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 244 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 245 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 246 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 247 | CLANG_WARN_STRICT_PROTOTYPES = YES; 248 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 249 | CLANG_WARN_UNREACHABLE_CODE = YES; 250 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 251 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 252 | COPY_PHASE_STRIP = NO; 253 | CURRENT_PROJECT_VERSION = 1; 254 | DEBUG_INFORMATION_FORMAT = dwarf; 255 | ENABLE_STRICT_OBJC_MSGSEND = YES; 256 | ENABLE_TESTABILITY = YES; 257 | GCC_C_LANGUAGE_STANDARD = gnu99; 258 | GCC_DYNAMIC_NO_PIC = NO; 259 | GCC_NO_COMMON_BLOCKS = YES; 260 | GCC_OPTIMIZATION_LEVEL = 0; 261 | GCC_PREPROCESSOR_DEFINITIONS = ( 262 | "DEBUG=1", 263 | "$(inherited)", 264 | ); 265 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 266 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 267 | GCC_WARN_UNDECLARED_SELECTOR = YES; 268 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 269 | GCC_WARN_UNUSED_FUNCTION = YES; 270 | GCC_WARN_UNUSED_VARIABLE = YES; 271 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 272 | MTL_ENABLE_DEBUG_INFO = YES; 273 | ONLY_ACTIVE_ARCH = YES; 274 | SDKROOT = iphoneos; 275 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 276 | TARGETED_DEVICE_FAMILY = "1,2"; 277 | VERSIONING_SYSTEM = "apple-generic"; 278 | VERSION_INFO_PREFIX = ""; 279 | }; 280 | name = Debug; 281 | }; 282 | 400523371CC7B47800E6DDA3 /* Release */ = { 283 | isa = XCBuildConfiguration; 284 | buildSettings = { 285 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 286 | ALWAYS_SEARCH_USER_PATHS = NO; 287 | CLANG_ANALYZER_NONNULL = YES; 288 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 289 | CLANG_CXX_LIBRARY = "libc++"; 290 | CLANG_ENABLE_MODULES = YES; 291 | CLANG_ENABLE_OBJC_ARC = YES; 292 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 293 | CLANG_WARN_BOOL_CONVERSION = YES; 294 | CLANG_WARN_COMMA = YES; 295 | CLANG_WARN_CONSTANT_CONVERSION = YES; 296 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 297 | CLANG_WARN_EMPTY_BODY = YES; 298 | CLANG_WARN_ENUM_CONVERSION = YES; 299 | CLANG_WARN_INFINITE_RECURSION = YES; 300 | CLANG_WARN_INT_CONVERSION = YES; 301 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 302 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 303 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 304 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 305 | CLANG_WARN_STRICT_PROTOTYPES = YES; 306 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 307 | CLANG_WARN_UNREACHABLE_CODE = YES; 308 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 309 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 310 | COPY_PHASE_STRIP = NO; 311 | CURRENT_PROJECT_VERSION = 1; 312 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 313 | ENABLE_NS_ASSERTIONS = NO; 314 | ENABLE_STRICT_OBJC_MSGSEND = YES; 315 | GCC_C_LANGUAGE_STANDARD = gnu99; 316 | GCC_NO_COMMON_BLOCKS = YES; 317 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 318 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 319 | GCC_WARN_UNDECLARED_SELECTOR = YES; 320 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 321 | GCC_WARN_UNUSED_FUNCTION = YES; 322 | GCC_WARN_UNUSED_VARIABLE = YES; 323 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 324 | MTL_ENABLE_DEBUG_INFO = NO; 325 | SDKROOT = iphoneos; 326 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 327 | TARGETED_DEVICE_FAMILY = "1,2"; 328 | VALIDATE_PRODUCT = YES; 329 | VERSIONING_SYSTEM = "apple-generic"; 330 | VERSION_INFO_PREFIX = ""; 331 | }; 332 | name = Release; 333 | }; 334 | 400523391CC7B47800E6DDA3 /* Debug */ = { 335 | isa = XCBuildConfiguration; 336 | buildSettings = { 337 | CLANG_ENABLE_MODULES = YES; 338 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 339 | DEFINES_MODULE = YES; 340 | DYLIB_COMPATIBILITY_VERSION = 1; 341 | DYLIB_CURRENT_VERSION = 1; 342 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 343 | INFOPLIST_FILE = Source/Info.plist; 344 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 345 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 346 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 347 | PRODUCT_BUNDLE_IDENTIFIER = com.keithito.SimpleAnimation; 348 | PRODUCT_NAME = "$(TARGET_NAME)"; 349 | SKIP_INSTALL = YES; 350 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 351 | SWIFT_VERSION = 3.0; 352 | }; 353 | name = Debug; 354 | }; 355 | 4005233A1CC7B47800E6DDA3 /* Release */ = { 356 | isa = XCBuildConfiguration; 357 | buildSettings = { 358 | CLANG_ENABLE_MODULES = YES; 359 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 360 | DEFINES_MODULE = YES; 361 | DYLIB_COMPATIBILITY_VERSION = 1; 362 | DYLIB_CURRENT_VERSION = 1; 363 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 364 | INFOPLIST_FILE = Source/Info.plist; 365 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 366 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 367 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 368 | PRODUCT_BUNDLE_IDENTIFIER = com.keithito.SimpleAnimation; 369 | PRODUCT_NAME = "$(TARGET_NAME)"; 370 | SKIP_INSTALL = YES; 371 | SWIFT_VERSION = 3.0; 372 | }; 373 | name = Release; 374 | }; 375 | 4005233C1CC7B47800E6DDA3 /* Debug */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | INFOPLIST_FILE = Tests/Info.plist; 379 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 380 | PRODUCT_BUNDLE_IDENTIFIER = com.keithito.SimpleAnimationTests; 381 | PRODUCT_NAME = "$(TARGET_NAME)"; 382 | SWIFT_VERSION = 3.0; 383 | }; 384 | name = Debug; 385 | }; 386 | 4005233D1CC7B47800E6DDA3 /* Release */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | INFOPLIST_FILE = Tests/Info.plist; 390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 391 | PRODUCT_BUNDLE_IDENTIFIER = com.keithito.SimpleAnimationTests; 392 | PRODUCT_NAME = "$(TARGET_NAME)"; 393 | SWIFT_VERSION = 3.0; 394 | }; 395 | name = Release; 396 | }; 397 | /* End XCBuildConfiguration section */ 398 | 399 | /* Begin XCConfigurationList section */ 400 | 4005231E1CC7B47800E6DDA3 /* Build configuration list for PBXProject "SimpleAnimation" */ = { 401 | isa = XCConfigurationList; 402 | buildConfigurations = ( 403 | 400523361CC7B47800E6DDA3 /* Debug */, 404 | 400523371CC7B47800E6DDA3 /* Release */, 405 | ); 406 | defaultConfigurationIsVisible = 0; 407 | defaultConfigurationName = Release; 408 | }; 409 | 400523381CC7B47800E6DDA3 /* Build configuration list for PBXNativeTarget "SimpleAnimation" */ = { 410 | isa = XCConfigurationList; 411 | buildConfigurations = ( 412 | 400523391CC7B47800E6DDA3 /* Debug */, 413 | 4005233A1CC7B47800E6DDA3 /* Release */, 414 | ); 415 | defaultConfigurationIsVisible = 0; 416 | defaultConfigurationName = Release; 417 | }; 418 | 4005233B1CC7B47800E6DDA3 /* Build configuration list for PBXNativeTarget "SimpleAnimationTests" */ = { 419 | isa = XCConfigurationList; 420 | buildConfigurations = ( 421 | 4005233C1CC7B47800E6DDA3 /* Debug */, 422 | 4005233D1CC7B47800E6DDA3 /* Release */, 423 | ); 424 | defaultConfigurationIsVisible = 0; 425 | defaultConfigurationName = Release; 426 | }; 427 | /* End XCConfigurationList section */ 428 | }; 429 | rootObject = 4005231B1CC7B47800E6DDA3 /* Project object */; 430 | } 431 | -------------------------------------------------------------------------------- /SimpleAnimation.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SimpleAnimation.xcodeproj/xcshareddata/xcschemes/SimpleAnimation.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /SimpleAnimation.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Source/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Source/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTracking 6 | 7 | NSPrivacyAccessedAPITypes 8 | 9 | NSPrivacyCollectedDataTypes 10 | 11 | NSPrivacyTrackingDomains 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Source/UIView+SimpleAnimation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SimpleAnimation.swift 3 | // SimpleAnimation.swift 4 | // 5 | // Created by Keith Ito on 4/19/16. 6 | // 7 | 8 | import UIKit 9 | 10 | 11 | /** 12 | Edge of the view's parent that the animation should involve 13 | - none: involves no edge 14 | - top: involves the top edge of the parent 15 | - bottom: involves the bottom edge of the parent 16 | - left: involves the left edge of the parent 17 | - right: involves the right edge of the parent 18 | */ 19 | public enum SimpleAnimationEdge { 20 | case none 21 | case top 22 | case bottom 23 | case left 24 | case right 25 | } 26 | 27 | /** 28 | A UIView extension that makes adding basic animations, like fades and bounces, simple. 29 | */ 30 | public extension UIView { 31 | /** 32 | Fades this view in. This method can be chained with other animations to combine a fade with 33 | the other animation, for instance: 34 | ``` 35 | view.fadeIn().slideIn(from: .left) 36 | ``` 37 | - Parameters: 38 | - duration: duration of the animation, in seconds 39 | - delay: delay before the animation starts, in seconds 40 | - completion: block executed when the animation ends 41 | */ 42 | @discardableResult func fadeIn(duration: TimeInterval = 0.25, 43 | delay: TimeInterval = 0, 44 | completion: ((Bool) -> Void)? = nil) -> UIView { 45 | isHidden = false 46 | alpha = 0 47 | UIView.animate( 48 | withDuration: duration, delay: delay, options: .curveEaseInOut, animations: { 49 | self.alpha = 1 50 | }, completion: completion) 51 | return self 52 | } 53 | 54 | /** 55 | Fades this view out. This method can be chained with other animations to combine a fade with 56 | the other animation, for instance: 57 | ``` 58 | view.fadeOut().slideOut(to: .right) 59 | ``` 60 | - Parameters: 61 | - duration: duration of the animation, in seconds 62 | - delay: delay before the animation starts, in seconds 63 | - completion: block executed when the animation ends 64 | */ 65 | @discardableResult func fadeOut(duration: TimeInterval = 0.25, 66 | delay: TimeInterval = 0, 67 | completion: ((Bool) -> Void)? = nil) -> UIView { 68 | UIView.animate( 69 | withDuration: duration, delay: delay, options: .curveEaseOut, animations: { 70 | self.alpha = 0 71 | }, completion: completion) 72 | return self 73 | } 74 | 75 | /** 76 | Fades the background color of a view from existing bg color to a specified color without using alpha values. 77 | 78 | - Parameters: 79 | - toColor: the final color you want to fade to 80 | - duration: duration of the animation, in seconds 81 | - delay: delay before the animation starts, in seconds 82 | - completion: block executed when the animation ends 83 | */ 84 | @discardableResult func fadeColor(toColor: UIColor = UIColor.red, 85 | duration: TimeInterval = 0.25, 86 | delay: TimeInterval = 0, 87 | completion: ((Bool) -> Void)? = nil) -> UIView { 88 | UIView.animate( 89 | withDuration: duration, delay: delay, options: .curveEaseIn, animations: { 90 | self.backgroundColor = toColor 91 | }, completion: completion) 92 | return self 93 | } 94 | 95 | /** 96 | Slides this view into position, from an edge of the parent (if "from" is set) or a fixed offset 97 | away from its position (if "x" and "y" are set). 98 | - Parameters: 99 | - from: edge of the parent view that should be used as the starting point of the animation 100 | - x: horizontal offset that should be used for the starting point of the animation 101 | - y: vertical offset that should be used for the starting point of the animation 102 | - duration: duration of the animation, in seconds 103 | - delay: delay before the animation starts, in seconds 104 | - completion: block executed when the animation ends 105 | */ 106 | @discardableResult func slideIn(from edge: SimpleAnimationEdge = .none, 107 | x: CGFloat = 0, 108 | y: CGFloat = 0, 109 | duration: TimeInterval = 0.4, 110 | delay: TimeInterval = 0, 111 | completion: ((Bool) -> Void)? = nil) -> UIView { 112 | let offset = offsetFor(edge: edge) 113 | transform = CGAffineTransform(translationX: offset.x + x, y: offset.y + y) 114 | isHidden = false 115 | UIView.animate( 116 | withDuration: duration, delay: delay, usingSpringWithDamping: 1, initialSpringVelocity: 2, 117 | options: .curveEaseOut, animations: { 118 | self.transform = .identity 119 | self.alpha = 1 120 | }, completion: completion) 121 | return self 122 | } 123 | 124 | /** 125 | Slides this view out of its position, toward an edge of the parent (if "to" is set) or a fixed 126 | offset away from its position (if "x" and "y" are set). 127 | - Parameters: 128 | - to: edge of the parent view that should be used as the ending point of the animation 129 | - x: horizontal offset that should be used for the ending point of the animation 130 | - y: vertical offset that should be used for the ending point of the animation 131 | - duration: duration of the animation, in seconds 132 | - delay: delay before the animation starts, in seconds 133 | - completion: block executed when the animation ends 134 | */ 135 | @discardableResult func slideOut(to edge: SimpleAnimationEdge = .none, 136 | x: CGFloat = 0, 137 | y: CGFloat = 0, 138 | duration: TimeInterval = 0.25, 139 | delay: TimeInterval = 0, 140 | completion: ((Bool) -> Void)? = nil) -> UIView { 141 | let offset = offsetFor(edge: edge) 142 | let endTransform = CGAffineTransform(translationX: offset.x + x, y: offset.y + y) 143 | UIView.animate( 144 | withDuration: duration, delay: delay, options: .curveEaseOut, animations: { 145 | self.transform = endTransform 146 | }, completion: completion) 147 | return self 148 | } 149 | 150 | /** 151 | Moves this view into position, with a bounce at the end, either from an edge of the parent (if 152 | "from" is set) or a fixed offset away from its position (if "x" and "y" are set). 153 | - Parameters: 154 | - from: edge of the parent view that should be used as the starting point of the animation 155 | - x: horizontal offset that should be used for the starting point of the animation 156 | - y: vertical offset that should be used for the starting point of the animation 157 | - duration: duration of the animation, in seconds 158 | - delay: delay before the animation starts, in seconds 159 | - completion: block executed when the animation ends 160 | */ 161 | @discardableResult func bounceIn(from edge: SimpleAnimationEdge = .none, 162 | x: CGFloat = 0, 163 | y: CGFloat = 0, 164 | duration: TimeInterval = 0.5, 165 | delay: TimeInterval = 0, 166 | completion: ((Bool) -> Void)? = nil) -> UIView { 167 | let offset = offsetFor(edge: edge) 168 | transform = CGAffineTransform(translationX: offset.x + x, y: offset.y + y) 169 | isHidden = false 170 | UIView.animate( 171 | withDuration: duration, delay: delay, usingSpringWithDamping: 0.58, initialSpringVelocity: 3, 172 | options: .curveEaseOut, animations: { 173 | self.transform = .identity 174 | self.alpha = 1 175 | }, completion: completion) 176 | return self 177 | } 178 | 179 | /** 180 | Moves this view out of its position, starting with a bounce. The view moves toward an edge of 181 | the parent (if "to" is set) or a fixed offset away from its position (if "x" and "y" are set). 182 | - Parameters: 183 | - to: edge of the parent view that should be used as the ending point of the animation 184 | - x: horizontal offset that should be used for the ending point of the animation 185 | - y: vertical offset that should be used for the ending point of the animation 186 | - duration: duration of the animation, in seconds 187 | - delay: delay before the animation starts, in seconds 188 | - completion: block executed when the animation ends 189 | */ 190 | @discardableResult func bounceOut(to edge: SimpleAnimationEdge = .none, 191 | x: CGFloat = 0, 192 | y: CGFloat = 0, 193 | duration: TimeInterval = 0.35, 194 | delay: TimeInterval = 0, 195 | completion: ((Bool) -> Void)? = nil) -> UIView { 196 | let offset = offsetFor(edge: edge) 197 | let delta = CGPoint(x: offset.x + x, y: offset.y + y) 198 | let endTransform = CGAffineTransform(translationX: delta.x, y: delta.y) 199 | let prepareTransform = CGAffineTransform(translationX: -delta.x * 0.2, y: -delta.y * 0.2) 200 | UIView.animateKeyframes( 201 | withDuration: duration, delay: delay, options: .calculationModeCubic, animations: { 202 | UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.2) { 203 | self.transform = prepareTransform 204 | } 205 | UIView.addKeyframe(withRelativeStartTime: 0.2, relativeDuration: 0.2) { 206 | self.transform = prepareTransform 207 | } 208 | UIView.addKeyframe(withRelativeStartTime: 0.4, relativeDuration: 0.6) { 209 | self.transform = endTransform 210 | } 211 | }, completion: completion) 212 | return self 213 | } 214 | 215 | /** 216 | Moves this view into position, as though it were popping out of the screen. 217 | - Parameters: 218 | - fromScale: starting scale for the view, should be between 0 and 1 219 | - duration: duration of the animation, in seconds 220 | - delay: delay before the animation starts, in seconds 221 | - completion: block executed when the animation ends 222 | */ 223 | @discardableResult func popIn(fromScale: CGFloat = 0.5, 224 | duration: TimeInterval = 0.5, 225 | delay: TimeInterval = 0, 226 | completion: ((Bool) -> Void)? = nil) -> UIView { 227 | isHidden = false 228 | alpha = 0 229 | transform = CGAffineTransform(scaleX: fromScale, y: fromScale) 230 | UIView.animate( 231 | withDuration: duration, delay: delay, usingSpringWithDamping: 0.55, initialSpringVelocity: 3, 232 | options: .curveEaseOut, animations: { 233 | self.transform = .identity 234 | self.alpha = 1 235 | }, completion: completion) 236 | return self 237 | } 238 | 239 | /** 240 | Moves this view out of position, as though it were withdrawing into the screen. 241 | - Parameters: 242 | - toScale: ending scale for the view, should be between 0 and 1 243 | - duration: duration of the animation, in seconds 244 | - delay: delay before the animation starts, in seconds 245 | - completion: block executed when the animation ends 246 | */ 247 | @discardableResult func popOut(toScale: CGFloat = 0.5, 248 | duration: TimeInterval = 0.3, 249 | delay: TimeInterval = 0, 250 | completion: ((Bool) -> Void)? = nil) -> UIView { 251 | let endTransform = CGAffineTransform(scaleX: toScale, y: toScale) 252 | let prepareTransform = CGAffineTransform(scaleX: 1.1, y: 1.1) 253 | UIView.animateKeyframes( 254 | withDuration: duration, delay: delay, options: .calculationModeCubic, animations: { 255 | UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.2) { 256 | self.transform = prepareTransform 257 | } 258 | UIView.addKeyframe(withRelativeStartTime: 0.2, relativeDuration: 0.3) { 259 | self.transform = prepareTransform 260 | } 261 | UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) { 262 | self.transform = endTransform 263 | self.alpha = 0 264 | } 265 | }, completion: completion) 266 | return self 267 | } 268 | 269 | /** 270 | Causes the view to hop, either toward a particular edge or out of the screen (if "toward" is 271 | .None). 272 | - Parameters: 273 | - toward: the edge to hop toward, or .None to hop out 274 | - amount: distance to hop, expressed as a fraction of the view's size 275 | - duration: duration of the animation, in seconds 276 | - delay: delay before the animation starts, in seconds 277 | - completion: block executed when the animation ends 278 | */ 279 | @discardableResult func hop(toward edge: SimpleAnimationEdge = .none, 280 | amount: CGFloat = 0.4, 281 | duration: TimeInterval = 0.6, 282 | delay: TimeInterval = 0, 283 | completion: ((Bool) -> Void)? = nil) -> UIView { 284 | var dx: CGFloat = 0, dy: CGFloat = 0, ds: CGFloat = 0 285 | if edge == .none { 286 | ds = amount / 2 287 | } else if edge == .left || edge == .right { 288 | dx = (edge == .left ? -1 : 1) * self.bounds.size.width * amount; 289 | dy = 0 290 | } else { 291 | dx = 0 292 | dy = (edge == .top ? -1 : 1) * self.bounds.size.height * amount; 293 | } 294 | UIView.animateKeyframes( 295 | withDuration: duration, delay: delay, options: .calculationModeLinear, animations: { 296 | UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.28) { 297 | let t = CGAffineTransform(translationX: dx, y: dy) 298 | self.transform = t.scaledBy(x: 1 + ds, y: 1 + ds) 299 | } 300 | UIView.addKeyframe(withRelativeStartTime: 0.28, relativeDuration: 0.28) { 301 | self.transform = .identity 302 | } 303 | UIView.addKeyframe(withRelativeStartTime: 0.56, relativeDuration: 0.28) { 304 | let t = CGAffineTransform(translationX: dx * 0.5, y: dy * 0.5) 305 | self.transform = t.scaledBy(x: 1 + ds * 0.5, y: 1 + ds * 0.5) 306 | } 307 | UIView.addKeyframe(withRelativeStartTime: 0.84, relativeDuration: 0.16) { 308 | self.transform = .identity 309 | } 310 | }, completion: completion) 311 | return self 312 | } 313 | 314 | /** 315 | Causes the view to shake, either toward a particular edge or in all directions (if "toward" is 316 | .None). 317 | - Parameters: 318 | - toward: the edge to shake toward, or .None to shake in all directions 319 | - amount: distance to shake, expressed as a fraction of the view's size 320 | - duration: duration of the animation, in seconds 321 | - delay: delay before the animation starts, in seconds 322 | - completion: block executed when the animation ends 323 | */ 324 | @discardableResult func shake(toward edge: SimpleAnimationEdge = .none, 325 | amount: CGFloat = 0.15, 326 | duration: TimeInterval = 0.6, 327 | delay: TimeInterval = 0, 328 | completion: ((Bool) -> Void)? = nil) -> UIView { 329 | let steps = 8 330 | let timeStep = 1.0 / Double(steps) 331 | var dx: CGFloat, dy: CGFloat 332 | if edge == .left || edge == .right { 333 | dx = (edge == .left ? -1 : 1) * self.bounds.size.width * amount; 334 | dy = 0 335 | } else { 336 | dx = 0 337 | dy = (edge == .top ? -1 : 1) * self.bounds.size.height * amount; 338 | } 339 | UIView.animateKeyframes( 340 | withDuration: duration, delay: delay, options: .calculationModeCubic, animations: { 341 | var start = 0.0 342 | for i in 0..<(steps - 1) { 343 | UIView.addKeyframe(withRelativeStartTime: start, relativeDuration: timeStep) { 344 | self.transform = CGAffineTransform(translationX: dx, y: dy) 345 | } 346 | if (edge == .none && i % 2 == 0) { 347 | swap(&dx, &dy) // Change direction 348 | dy *= -1 349 | } 350 | dx *= -0.85 351 | dy *= -0.85 352 | start += timeStep 353 | } 354 | UIView.addKeyframe(withRelativeStartTime: start, relativeDuration: timeStep) { 355 | self.transform = .identity 356 | } 357 | }, completion: completion) 358 | return self 359 | } 360 | 361 | private func offsetFor(edge: SimpleAnimationEdge) -> CGPoint { 362 | if let parentSize = self.superview?.frame.size { 363 | switch edge { 364 | case .none: return CGPoint.zero 365 | case .top: return CGPoint(x: 0, y: -frame.maxY) 366 | case .bottom: return CGPoint(x: 0, y: parentSize.height - frame.minY) 367 | case .left: return CGPoint(x: -frame.maxX, y: 0) 368 | case .right: return CGPoint(x: parentSize.width - frame.minX, y: 0) 369 | } 370 | } 371 | return .zero 372 | } 373 | } 374 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/UIView+SimpleAnimationTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleAnimationTests.swift 3 | // SimpleAnimationTests 4 | // 5 | // Created by Keith Ito on 4/20/16. 6 | // Copyright © 2016 Keith Ito. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SimpleAnimation 11 | 12 | class UIView_SimpleAnimationTest: XCTestCase { 13 | func testNeedToWriteTests() { 14 | XCTAssert(true); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /screenshots/bounceIn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keithito/SimpleAnimation/8f7c63ea1049d67b2b1f044cbd2eef150e1df656/screenshots/bounceIn.gif -------------------------------------------------------------------------------- /screenshots/customShake.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keithito/SimpleAnimation/8f7c63ea1049d67b2b1f044cbd2eef150e1df656/screenshots/customShake.gif -------------------------------------------------------------------------------- /screenshots/popIn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keithito/SimpleAnimation/8f7c63ea1049d67b2b1f044cbd2eef150e1df656/screenshots/popIn.gif -------------------------------------------------------------------------------- /screenshots/shake.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keithito/SimpleAnimation/8f7c63ea1049d67b2b1f044cbd2eef150e1df656/screenshots/shake.gif --------------------------------------------------------------------------------