├── .gitignore ├── .swift-version ├── CONTRIBUTING.md ├── Example └── Ripple │ ├── Podfile │ ├── Podfile.lock │ ├── README.md │ ├── Ripple │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-40.png │ │ │ ├── Icon-40@2x.png │ │ │ ├── Icon-40@3x.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-72.png │ │ │ ├── Icon-72@2x.png │ │ │ ├── Icon-76.png │ │ │ ├── Icon-76@2x.png │ │ │ ├── Icon-83.5@2x.png │ │ │ ├── Icon-Small-50.png │ │ │ ├── Icon-Small-50@2x.png │ │ │ ├── Icon-Small.png │ │ │ ├── Icon-Small@2x.png │ │ │ ├── Icon-Small@3x.png │ │ │ ├── Icon.png │ │ │ └── Icon@2x.png │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Info.plist │ └── ViewController.swift │ ├── RippleDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── RippleDemo.xcscheme │ └── RippleDemo.xcworkspace │ └── contents.xcworkspacedata ├── LICENSE.md ├── Others └── Info.plist ├── README.md ├── Resources ├── cover.png ├── demo.gif └── example.png ├── Ripple.podspec ├── Ripple.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── Ripple.xcscheme └── Sources └── Ripple.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | Icon 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | 10 | # Xcode 11 | # 12 | build/ 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata 22 | *.xccheckout 23 | *.moved-aside 24 | DerivedData 25 | *.hmap 26 | *.ipa 27 | *.xcuserstate 28 | 29 | # CocoaPods 30 | Pods 31 | 32 | # Carthage 33 | Carthage 34 | 35 | # SPM 36 | .build/ 37 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | GitHub Issues is for reporting bugs, discussing features and general feedback in **Ripple**. Be sure to check our [documentation](http://cocoadocs.org/docsets/Ripple), [FAQ](https://github.com/RamonGilabert/Ripple/wiki/FAQ) and [past issues](https://github.com/RamonGilabert/Ripple/issues?state=closed) before opening any new issues. 2 | 3 | If you are posting about a crash in your application, a stack trace is helpful, but additional context, in the form of code and explanation, is necessary to be of any use. 4 | -------------------------------------------------------------------------------- /Example/Ripple/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | platform :ios, '8.0' 4 | 5 | pod 'Ripple', path: '../../' 6 | 7 | target 'RippleDemo' 8 | -------------------------------------------------------------------------------- /Example/Ripple/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Ripple (2.1) 3 | 4 | DEPENDENCIES: 5 | - Ripple (from `../../`) 6 | 7 | EXTERNAL SOURCES: 8 | Ripple: 9 | :path: "../../" 10 | 11 | SPEC CHECKSUMS: 12 | Ripple: fb35d2d638e9bcc03c291f14e80ae6ab1e3a3dea 13 | 14 | PODFILE CHECKSUM: 89640b13351516546be4227dc228ac490ac358b0 15 | 16 | COCOAPODS: 1.1.0.rc.2 17 | -------------------------------------------------------------------------------- /Example/Ripple/README.md: -------------------------------------------------------------------------------- 1 | ![Ripple](https://github.com/RamonGilabert/Ripple/blob/master/Resources/demo.gif) 2 | -------------------------------------------------------------------------------- /Example/Ripple/Ripple/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | 6 | lazy var rootViewController: UIViewController = ViewController() 7 | var window: UIWindow? 8 | 9 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 10 | window = UIWindow() 11 | window?.rootViewController = rootViewController 12 | window?.makeKeyAndVisible() 13 | 14 | return true 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "3x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "size" : "40x40", 25 | "idiom" : "iphone", 26 | "filename" : "Icon-40@3x.png", 27 | "scale" : "3x" 28 | }, 29 | { 30 | "size" : "57x57", 31 | "idiom" : "iphone", 32 | "filename" : "Icon.png", 33 | "scale" : "1x" 34 | }, 35 | { 36 | "size" : "57x57", 37 | "idiom" : "iphone", 38 | "filename" : "Icon@2x.png", 39 | "scale" : "2x" 40 | }, 41 | { 42 | "size" : "60x60", 43 | "idiom" : "iphone", 44 | "filename" : "Icon-60@2x.png", 45 | "scale" : "2x" 46 | }, 47 | { 48 | "size" : "60x60", 49 | "idiom" : "iphone", 50 | "filename" : "Icon-60@3x.png", 51 | "scale" : "3x" 52 | }, 53 | { 54 | "size" : "29x29", 55 | "idiom" : "ipad", 56 | "filename" : "Icon-Small.png", 57 | "scale" : "1x" 58 | }, 59 | { 60 | "idiom" : "ipad", 61 | "size" : "29x29", 62 | "scale" : "2x" 63 | }, 64 | { 65 | "size" : "40x40", 66 | "idiom" : "ipad", 67 | "filename" : "Icon-40.png", 68 | "scale" : "1x" 69 | }, 70 | { 71 | "size" : "40x40", 72 | "idiom" : "ipad", 73 | "filename" : "Icon-40@2x.png", 74 | "scale" : "2x" 75 | }, 76 | { 77 | "size" : "50x50", 78 | "idiom" : "ipad", 79 | "filename" : "Icon-Small-50.png", 80 | "scale" : "1x" 81 | }, 82 | { 83 | "size" : "50x50", 84 | "idiom" : "ipad", 85 | "filename" : "Icon-Small-50@2x.png", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "size" : "72x72", 90 | "idiom" : "ipad", 91 | "filename" : "Icon-72.png", 92 | "scale" : "1x" 93 | }, 94 | { 95 | "size" : "72x72", 96 | "idiom" : "ipad", 97 | "filename" : "Icon-72@2x.png", 98 | "scale" : "2x" 99 | }, 100 | { 101 | "size" : "76x76", 102 | "idiom" : "ipad", 103 | "filename" : "Icon-76.png", 104 | "scale" : "1x" 105 | }, 106 | { 107 | "size" : "76x76", 108 | "idiom" : "ipad", 109 | "filename" : "Icon-76@2x.png", 110 | "scale" : "2x" 111 | }, 112 | { 113 | "size" : "83.5x83.5", 114 | "idiom" : "ipad", 115 | "filename" : "Icon-83.5@2x.png", 116 | "scale" : "2x" 117 | }, 118 | { 119 | "size" : "24x24", 120 | "idiom" : "watch", 121 | "scale" : "2x", 122 | "role" : "notificationCenter", 123 | "subtype" : "38mm" 124 | }, 125 | { 126 | "size" : "27.5x27.5", 127 | "idiom" : "watch", 128 | "scale" : "2x", 129 | "role" : "notificationCenter", 130 | "subtype" : "42mm" 131 | }, 132 | { 133 | "size" : "29x29", 134 | "idiom" : "watch", 135 | "filename" : "Icon-Small@2x.png", 136 | "role" : "companionSettings", 137 | "scale" : "2x" 138 | }, 139 | { 140 | "size" : "29x29", 141 | "idiom" : "watch", 142 | "filename" : "Icon-Small@3x.png", 143 | "role" : "companionSettings", 144 | "scale" : "3x" 145 | }, 146 | { 147 | "size" : "40x40", 148 | "idiom" : "watch", 149 | "scale" : "2x", 150 | "role" : "appLauncher", 151 | "subtype" : "38mm" 152 | }, 153 | { 154 | "size" : "86x86", 155 | "idiom" : "watch", 156 | "scale" : "2x", 157 | "role" : "quickLook", 158 | "subtype" : "38mm" 159 | }, 160 | { 161 | "size" : "98x98", 162 | "idiom" : "watch", 163 | "scale" : "2x", 164 | "role" : "quickLook", 165 | "subtype" : "42mm" 166 | } 167 | ], 168 | "info" : { 169 | "version" : 1, 170 | "author" : "xcode" 171 | } 172 | } -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-72.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Example/Ripple/Ripple/Assets.xcassets/AppIcon.appiconset/Icon@2x.png -------------------------------------------------------------------------------- /Example/Ripple/Ripple/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/Ripple/Ripple/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 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Example/Ripple/Ripple/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Ripple 3 | 4 | class ViewController: UIViewController { 5 | 6 | lazy var tapGesture: UITapGestureRecognizer = { [unowned self] in 7 | let gesture = UITapGestureRecognizer() 8 | gesture.addTarget(self, action: #selector(handleTapGesture)) 9 | 10 | return gesture 11 | }() 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | view.backgroundColor = UIColor(red:0.12, green:0.57, blue:0.96, alpha:1.00) 17 | view.addGestureRecognizer(tapGesture) 18 | } 19 | 20 | // MARK: - Action methods 21 | 22 | func handleTapGesture() { 23 | let location = tapGesture.location(in: view) 24 | 25 | ripple(location, view: view, times: 5) 26 | } 27 | 28 | // MARK: - Helper methods 29 | 30 | override var preferredStatusBarStyle : UIStatusBarStyle { 31 | return .lightContent 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Example/Ripple/RippleDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 292533A11CA5681E00D6C911 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2925339B1CA5681E00D6C911 /* AppDelegate.swift */; }; 11 | 292533A21CA5681E00D6C911 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2925339C1CA5681E00D6C911 /* Assets.xcassets */; }; 12 | 292533A31CA5681E00D6C911 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2925339D1CA5681E00D6C911 /* LaunchScreen.storyboard */; }; 13 | 292533A51CA5681E00D6C911 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 292533A01CA5681E00D6C911 /* ViewController.swift */; }; 14 | A11F573AFCC71133DAE866A5 /* Pods_RippleDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A0384135F538EFA62641959 /* Pods_RippleDemo.framework */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 285503F76B2B12E5D15FA430 /* Pods-RippleDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RippleDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RippleDemo/Pods-RippleDemo.debug.xcconfig"; sourceTree = ""; }; 19 | 2925339B1CA5681E00D6C911 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 20 | 2925339C1CA5681E00D6C911 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 21 | 2925339E1CA5681E00D6C911 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 22 | 2925339F1CA5681E00D6C911 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 23 | 292533A01CA5681E00D6C911 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 24 | 2A0384135F538EFA62641959 /* Pods_RippleDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RippleDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 95915A97637700EA780F9630 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | BE62182ACEA0755F74D4546B /* Pods-RippleDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RippleDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-RippleDemo/Pods-RippleDemo.release.xcconfig"; sourceTree = ""; }; 27 | D5C7F7401C3BC9CE008CDDBA /* RippleDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RippleDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | D5C7F73D1C3BC9CE008CDDBA /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | A11F573AFCC71133DAE866A5 /* Pods_RippleDemo.framework in Frameworks */, 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 2925339A1CA5681E00D6C911 /* Ripple */ = { 43 | isa = PBXGroup; 44 | children = ( 45 | 2925339B1CA5681E00D6C911 /* AppDelegate.swift */, 46 | 292533A01CA5681E00D6C911 /* ViewController.swift */, 47 | 292533A61CA5685100D6C911 /* Supporting files */, 48 | ); 49 | path = Ripple; 50 | sourceTree = ""; 51 | }; 52 | 292533A61CA5685100D6C911 /* Supporting files */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 2925339C1CA5681E00D6C911 /* Assets.xcassets */, 56 | 2925339D1CA5681E00D6C911 /* LaunchScreen.storyboard */, 57 | 2925339F1CA5681E00D6C911 /* Info.plist */, 58 | ); 59 | name = "Supporting files"; 60 | sourceTree = ""; 61 | }; 62 | D5C7F7371C3BC9CE008CDDBA = { 63 | isa = PBXGroup; 64 | children = ( 65 | 2925339A1CA5681E00D6C911 /* Ripple */, 66 | D5C7F7411C3BC9CE008CDDBA /* Products */, 67 | D93DB8FF61C25956F41F7EC0 /* Frameworks */, 68 | EEF6C30590301B64EE79941C /* Pods */, 69 | ); 70 | sourceTree = ""; 71 | }; 72 | D5C7F7411C3BC9CE008CDDBA /* Products */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | D5C7F7401C3BC9CE008CDDBA /* RippleDemo.app */, 76 | ); 77 | name = Products; 78 | sourceTree = ""; 79 | }; 80 | D93DB8FF61C25956F41F7EC0 /* Frameworks */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 95915A97637700EA780F9630 /* Pods.framework */, 84 | 2A0384135F538EFA62641959 /* Pods_RippleDemo.framework */, 85 | ); 86 | name = Frameworks; 87 | sourceTree = ""; 88 | }; 89 | EEF6C30590301B64EE79941C /* Pods */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 285503F76B2B12E5D15FA430 /* Pods-RippleDemo.debug.xcconfig */, 93 | BE62182ACEA0755F74D4546B /* Pods-RippleDemo.release.xcconfig */, 94 | ); 95 | name = Pods; 96 | sourceTree = ""; 97 | }; 98 | /* End PBXGroup section */ 99 | 100 | /* Begin PBXNativeTarget section */ 101 | D5C7F73F1C3BC9CE008CDDBA /* RippleDemo */ = { 102 | isa = PBXNativeTarget; 103 | buildConfigurationList = D5C7F7521C3BC9CE008CDDBA /* Build configuration list for PBXNativeTarget "RippleDemo" */; 104 | buildPhases = ( 105 | 570FC52FB58D696289A9C659 /* [CP] Check Pods Manifest.lock */, 106 | D5C7F73C1C3BC9CE008CDDBA /* Sources */, 107 | D5C7F73D1C3BC9CE008CDDBA /* Frameworks */, 108 | D5C7F73E1C3BC9CE008CDDBA /* Resources */, 109 | 9BFFBA338A10516A68CB152E /* [CP] Embed Pods Frameworks */, 110 | 3D05643E6A604B425CD4C9B5 /* [CP] Copy Pods Resources */, 111 | ); 112 | buildRules = ( 113 | ); 114 | dependencies = ( 115 | ); 116 | name = RippleDemo; 117 | productName = RippleDemo; 118 | productReference = D5C7F7401C3BC9CE008CDDBA /* RippleDemo.app */; 119 | productType = "com.apple.product-type.application"; 120 | }; 121 | /* End PBXNativeTarget section */ 122 | 123 | /* Begin PBXProject section */ 124 | D5C7F7381C3BC9CE008CDDBA /* Project object */ = { 125 | isa = PBXProject; 126 | attributes = { 127 | LastSwiftUpdateCheck = 0720; 128 | LastUpgradeCheck = 0800; 129 | ORGANIZATIONNAME = "Hyper Interaktiv AS"; 130 | TargetAttributes = { 131 | D5C7F73F1C3BC9CE008CDDBA = { 132 | CreatedOnToolsVersion = 7.2; 133 | LastSwiftMigration = 0800; 134 | }; 135 | }; 136 | }; 137 | buildConfigurationList = D5C7F73B1C3BC9CE008CDDBA /* Build configuration list for PBXProject "RippleDemo" */; 138 | compatibilityVersion = "Xcode 3.2"; 139 | developmentRegion = English; 140 | hasScannedForEncodings = 0; 141 | knownRegions = ( 142 | en, 143 | Base, 144 | ); 145 | mainGroup = D5C7F7371C3BC9CE008CDDBA; 146 | productRefGroup = D5C7F7411C3BC9CE008CDDBA /* Products */; 147 | projectDirPath = ""; 148 | projectRoot = ""; 149 | targets = ( 150 | D5C7F73F1C3BC9CE008CDDBA /* RippleDemo */, 151 | ); 152 | }; 153 | /* End PBXProject section */ 154 | 155 | /* Begin PBXResourcesBuildPhase section */ 156 | D5C7F73E1C3BC9CE008CDDBA /* Resources */ = { 157 | isa = PBXResourcesBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | 292533A21CA5681E00D6C911 /* Assets.xcassets in Resources */, 161 | 292533A31CA5681E00D6C911 /* LaunchScreen.storyboard in Resources */, 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | /* End PBXResourcesBuildPhase section */ 166 | 167 | /* Begin PBXShellScriptBuildPhase section */ 168 | 3D05643E6A604B425CD4C9B5 /* [CP] Copy Pods Resources */ = { 169 | isa = PBXShellScriptBuildPhase; 170 | buildActionMask = 2147483647; 171 | files = ( 172 | ); 173 | inputPaths = ( 174 | ); 175 | name = "[CP] Copy Pods Resources"; 176 | outputPaths = ( 177 | ); 178 | runOnlyForDeploymentPostprocessing = 0; 179 | shellPath = /bin/sh; 180 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RippleDemo/Pods-RippleDemo-resources.sh\"\n"; 181 | showEnvVarsInLog = 0; 182 | }; 183 | 570FC52FB58D696289A9C659 /* [CP] Check Pods Manifest.lock */ = { 184 | isa = PBXShellScriptBuildPhase; 185 | buildActionMask = 2147483647; 186 | files = ( 187 | ); 188 | inputPaths = ( 189 | ); 190 | name = "[CP] Check Pods Manifest.lock"; 191 | outputPaths = ( 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | shellPath = /bin/sh; 195 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 196 | showEnvVarsInLog = 0; 197 | }; 198 | 9BFFBA338A10516A68CB152E /* [CP] Embed Pods Frameworks */ = { 199 | isa = PBXShellScriptBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | ); 203 | inputPaths = ( 204 | ); 205 | name = "[CP] Embed Pods Frameworks"; 206 | outputPaths = ( 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | shellPath = /bin/sh; 210 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RippleDemo/Pods-RippleDemo-frameworks.sh\"\n"; 211 | showEnvVarsInLog = 0; 212 | }; 213 | /* End PBXShellScriptBuildPhase section */ 214 | 215 | /* Begin PBXSourcesBuildPhase section */ 216 | D5C7F73C1C3BC9CE008CDDBA /* Sources */ = { 217 | isa = PBXSourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 292533A51CA5681E00D6C911 /* ViewController.swift in Sources */, 221 | 292533A11CA5681E00D6C911 /* AppDelegate.swift in Sources */, 222 | ); 223 | runOnlyForDeploymentPostprocessing = 0; 224 | }; 225 | /* End PBXSourcesBuildPhase section */ 226 | 227 | /* Begin PBXVariantGroup section */ 228 | 2925339D1CA5681E00D6C911 /* LaunchScreen.storyboard */ = { 229 | isa = PBXVariantGroup; 230 | children = ( 231 | 2925339E1CA5681E00D6C911 /* Base */, 232 | ); 233 | name = LaunchScreen.storyboard; 234 | sourceTree = ""; 235 | }; 236 | /* End PBXVariantGroup section */ 237 | 238 | /* Begin XCBuildConfiguration section */ 239 | D5C7F7501C3BC9CE008CDDBA /* Debug */ = { 240 | isa = XCBuildConfiguration; 241 | buildSettings = { 242 | ALWAYS_SEARCH_USER_PATHS = NO; 243 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 244 | CLANG_CXX_LIBRARY = "libc++"; 245 | CLANG_ENABLE_MODULES = YES; 246 | CLANG_ENABLE_OBJC_ARC = YES; 247 | CLANG_WARN_BOOL_CONVERSION = YES; 248 | CLANG_WARN_CONSTANT_CONVERSION = YES; 249 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 250 | CLANG_WARN_EMPTY_BODY = YES; 251 | CLANG_WARN_ENUM_CONVERSION = YES; 252 | CLANG_WARN_INFINITE_RECURSION = YES; 253 | CLANG_WARN_INT_CONVERSION = YES; 254 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 255 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 256 | CLANG_WARN_UNREACHABLE_CODE = YES; 257 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 258 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 259 | COPY_PHASE_STRIP = NO; 260 | DEBUG_INFORMATION_FORMAT = dwarf; 261 | ENABLE_STRICT_OBJC_MSGSEND = YES; 262 | ENABLE_TESTABILITY = YES; 263 | GCC_C_LANGUAGE_STANDARD = gnu99; 264 | GCC_DYNAMIC_NO_PIC = NO; 265 | GCC_NO_COMMON_BLOCKS = YES; 266 | GCC_OPTIMIZATION_LEVEL = 0; 267 | GCC_PREPROCESSOR_DEFINITIONS = ( 268 | "DEBUG=1", 269 | "$(inherited)", 270 | ); 271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 273 | GCC_WARN_UNDECLARED_SELECTOR = YES; 274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 275 | GCC_WARN_UNUSED_FUNCTION = YES; 276 | GCC_WARN_UNUSED_VARIABLE = YES; 277 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 278 | MTL_ENABLE_DEBUG_INFO = YES; 279 | ONLY_ACTIVE_ARCH = YES; 280 | SDKROOT = iphoneos; 281 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 282 | }; 283 | name = Debug; 284 | }; 285 | D5C7F7511C3BC9CE008CDDBA /* Release */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ALWAYS_SEARCH_USER_PATHS = NO; 289 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 290 | CLANG_CXX_LIBRARY = "libc++"; 291 | CLANG_ENABLE_MODULES = YES; 292 | CLANG_ENABLE_OBJC_ARC = YES; 293 | CLANG_WARN_BOOL_CONVERSION = YES; 294 | CLANG_WARN_CONSTANT_CONVERSION = YES; 295 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 296 | CLANG_WARN_EMPTY_BODY = YES; 297 | CLANG_WARN_ENUM_CONVERSION = YES; 298 | CLANG_WARN_INFINITE_RECURSION = YES; 299 | CLANG_WARN_INT_CONVERSION = YES; 300 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 301 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 302 | CLANG_WARN_UNREACHABLE_CODE = YES; 303 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 304 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 305 | COPY_PHASE_STRIP = NO; 306 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 307 | ENABLE_NS_ASSERTIONS = NO; 308 | ENABLE_STRICT_OBJC_MSGSEND = YES; 309 | GCC_C_LANGUAGE_STANDARD = gnu99; 310 | GCC_NO_COMMON_BLOCKS = YES; 311 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 312 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 313 | GCC_WARN_UNDECLARED_SELECTOR = YES; 314 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 315 | GCC_WARN_UNUSED_FUNCTION = YES; 316 | GCC_WARN_UNUSED_VARIABLE = YES; 317 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 318 | MTL_ENABLE_DEBUG_INFO = NO; 319 | SDKROOT = iphoneos; 320 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 321 | VALIDATE_PRODUCT = YES; 322 | }; 323 | name = Release; 324 | }; 325 | D5C7F7531C3BC9CE008CDDBA /* Debug */ = { 326 | isa = XCBuildConfiguration; 327 | baseConfigurationReference = 285503F76B2B12E5D15FA430 /* Pods-RippleDemo.debug.xcconfig */; 328 | buildSettings = { 329 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 330 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 331 | INFOPLIST_FILE = Ripple/Info.plist; 332 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 333 | PRODUCT_BUNDLE_IDENTIFIER = com.RamonGilabert.RippleDemo; 334 | PRODUCT_NAME = "$(TARGET_NAME)"; 335 | SWIFT_VERSION = 3.0; 336 | }; 337 | name = Debug; 338 | }; 339 | D5C7F7541C3BC9CE008CDDBA /* Release */ = { 340 | isa = XCBuildConfiguration; 341 | baseConfigurationReference = BE62182ACEA0755F74D4546B /* Pods-RippleDemo.release.xcconfig */; 342 | buildSettings = { 343 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 344 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 345 | INFOPLIST_FILE = Ripple/Info.plist; 346 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 347 | PRODUCT_BUNDLE_IDENTIFIER = com.RamonGilabert.RippleDemo; 348 | PRODUCT_NAME = "$(TARGET_NAME)"; 349 | SWIFT_VERSION = 3.0; 350 | }; 351 | name = Release; 352 | }; 353 | /* End XCBuildConfiguration section */ 354 | 355 | /* Begin XCConfigurationList section */ 356 | D5C7F73B1C3BC9CE008CDDBA /* Build configuration list for PBXProject "RippleDemo" */ = { 357 | isa = XCConfigurationList; 358 | buildConfigurations = ( 359 | D5C7F7501C3BC9CE008CDDBA /* Debug */, 360 | D5C7F7511C3BC9CE008CDDBA /* Release */, 361 | ); 362 | defaultConfigurationIsVisible = 0; 363 | defaultConfigurationName = Release; 364 | }; 365 | D5C7F7521C3BC9CE008CDDBA /* Build configuration list for PBXNativeTarget "RippleDemo" */ = { 366 | isa = XCConfigurationList; 367 | buildConfigurations = ( 368 | D5C7F7531C3BC9CE008CDDBA /* Debug */, 369 | D5C7F7541C3BC9CE008CDDBA /* Release */, 370 | ); 371 | defaultConfigurationIsVisible = 0; 372 | defaultConfigurationName = Release; 373 | }; 374 | /* End XCConfigurationList section */ 375 | }; 376 | rootObject = D5C7F7381C3BC9CE008CDDBA /* Project object */; 377 | } 378 | -------------------------------------------------------------------------------- /Example/Ripple/RippleDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Ripple/RippleDemo.xcodeproj/xcshareddata/xcschemes/RippleDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Example/Ripple/RippleDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Licensed under the **MIT** license 2 | 3 | > Copyright (c) 2015 Ramon Gilabert 4 | > 5 | > Permission is hereby granted, free of charge, to any person obtaining 6 | > a copy of this software and associated documentation files (the 7 | > "Software"), to deal in the Software without restriction, including 8 | > without limitation the rights to use, copy, modify, merge, publish, 9 | > distribute, sublicense, and/or sell copies of the Software, and to 10 | > permit persons to whom the Software is furnished to do so, subject to 11 | > the following conditions: 12 | > 13 | > The above copyright notice and this permission notice shall be 14 | > included in all copies or substantial portions of the Software. 15 | > 16 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Others/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Ripple](https://github.com/RamonGilabert/Ripple/blob/master/Resources/cover.png) 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |

11 |
12 | 13 | Ripple is a small convenience to create ripples in your app. With just a line of code, you can do beautiful things. 14 | 15 | ## Code 16 | 17 | There are two types of ripples, the one times ones, or the repeated ones: 18 | 19 | ![Ripple](https://github.com/RamonGilabert/Ripple/blob/master/Resources/example.png) 20 | 21 | #### Droplets 22 | 23 | By just setting the center and the view the droplet should be added to, you are going to have a droplet effect. 24 | 25 | ```swift 26 | droplet(center: CGPoint, view: UIView) 27 | ``` 28 | 29 | #### Ripples 30 | 31 | There are many ways to customize the ripple effect, the simplest one of all is just calling the following lines, which will repeat infinite times. 32 | 33 | ```swift 34 | ripple(center: CGPoint, view: UIView) 35 | ``` 36 | 37 | There is, in both cases some configuration you can find, read the documentation for more information. :) Here's the gif of the demo for you to have an idea of what Ripple is: 38 | 39 | ![Ripple](https://github.com/RamonGilabert/Ripple/blob/master/Resources/demo.gif) 40 | 41 | ## Installation 42 | 43 | **Ripple** is available through [CocoaPods](http://cocoapods.org). To install 44 | it, simply add the following line to your Podfile: 45 | 46 | ```ruby 47 | pod 'Ripple' 48 | ``` 49 | 50 | **Ripple** is also available through [Carthage](https://github.com/Carthage/Carthage). To install just write into your Cartfile: 51 | 52 | ```ruby 53 | github 'RamonGilabert/Ripple' 54 | ``` 55 | 56 | ## Author 57 | 58 | Ramon Gilabert with ♥️ 59 | 60 | ## Contribute 61 | 62 | I would love you to contribute to **Ripple**, check the [CONTRIBUTING](https://github.com/RamonGilabert/Ripple/blob/master/CONTRIBUTING.md) file for more information. 63 | 64 | ## License 65 | 66 | **Ripple** is available under the MIT license. See the [LICENSE](https://github.com/RamonGilabert/Ripple/blob/master/LICENSE.md) file for more info. 67 | -------------------------------------------------------------------------------- /Resources/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Resources/cover.png -------------------------------------------------------------------------------- /Resources/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Resources/demo.gif -------------------------------------------------------------------------------- /Resources/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamonGilabert/Ripple/6fa57386f81e1418adef8a08aca30ea0601218f9/Resources/example.png -------------------------------------------------------------------------------- /Ripple.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Ripple" 3 | s.summary = "Remember there's no such thing as a small act of kindness. Every act creates a ripple with no logical end." 4 | s.version = "3.0" 5 | s.homepage = "https://github.com/RamonGilabert/Ripple" 6 | s.license = 'MIT' 7 | s.author = { "Ramon Gilabert" => "ramon.gilabert.llop@gmail.com" } 8 | s.source = { 9 | :git => "https://github.com/RamonGilabert/Ripple.git", 10 | :tag => s.version.to_s 11 | } 12 | s.social_media_url = 'https://twitter.com/RamonGilabert' 13 | 14 | s.ios.deployment_target = '8.0' 15 | 16 | s.requires_arc = true 17 | s.ios.source_files = 'Sources/*' 18 | end 19 | -------------------------------------------------------------------------------- /Ripple.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 295F59841DACFBCA00726D50 /* Ripple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 295F59831DACFBCA00726D50 /* Ripple.swift */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXFileReference section */ 14 | 292533791CA5634400D6C911 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 15 | 295F59831DACFBCA00726D50 /* Ripple.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Ripple.swift; sourceTree = ""; }; 16 | D5B2E89F1C3A780C00C0327D /* Ripple.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Ripple.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 17 | /* End PBXFileReference section */ 18 | 19 | /* Begin PBXFrameworksBuildPhase section */ 20 | D5B2E89B1C3A780C00C0327D /* Frameworks */ = { 21 | isa = PBXFrameworksBuildPhase; 22 | buildActionMask = 2147483647; 23 | files = ( 24 | ); 25 | runOnlyForDeploymentPostprocessing = 0; 26 | }; 27 | /* End PBXFrameworksBuildPhase section */ 28 | 29 | /* Begin PBXGroup section */ 30 | 292533781CA5634400D6C911 /* Others */ = { 31 | isa = PBXGroup; 32 | children = ( 33 | 292533791CA5634400D6C911 /* Info.plist */, 34 | ); 35 | path = Others; 36 | sourceTree = ""; 37 | }; 38 | 295F59821DACFBCA00726D50 /* Sources */ = { 39 | isa = PBXGroup; 40 | children = ( 41 | 295F59831DACFBCA00726D50 /* Ripple.swift */, 42 | ); 43 | path = Sources; 44 | sourceTree = ""; 45 | }; 46 | D5B2E8951C3A780C00C0327D = { 47 | isa = PBXGroup; 48 | children = ( 49 | 295F59821DACFBCA00726D50 /* Sources */, 50 | 292533781CA5634400D6C911 /* Others */, 51 | D5B2E8A01C3A780C00C0327D /* Products */, 52 | ); 53 | sourceTree = ""; 54 | }; 55 | D5B2E8A01C3A780C00C0327D /* Products */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | D5B2E89F1C3A780C00C0327D /* Ripple.framework */, 59 | ); 60 | name = Products; 61 | sourceTree = ""; 62 | }; 63 | /* End PBXGroup section */ 64 | 65 | /* Begin PBXHeadersBuildPhase section */ 66 | D5B2E89C1C3A780C00C0327D /* Headers */ = { 67 | isa = PBXHeadersBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | /* End PBXHeadersBuildPhase section */ 74 | 75 | /* Begin PBXNativeTarget section */ 76 | D5B2E89E1C3A780C00C0327D /* Ripple */ = { 77 | isa = PBXNativeTarget; 78 | buildConfigurationList = D5B2E8B31C3A780C00C0327D /* Build configuration list for PBXNativeTarget "Ripple" */; 79 | buildPhases = ( 80 | D5B2E89A1C3A780C00C0327D /* Sources */, 81 | D5B2E89B1C3A780C00C0327D /* Frameworks */, 82 | D5B2E89C1C3A780C00C0327D /* Headers */, 83 | D5B2E89D1C3A780C00C0327D /* Resources */, 84 | ); 85 | buildRules = ( 86 | ); 87 | dependencies = ( 88 | ); 89 | name = Ripple; 90 | productName = Ripple; 91 | productReference = D5B2E89F1C3A780C00C0327D /* Ripple.framework */; 92 | productType = "com.apple.product-type.framework"; 93 | }; 94 | /* End PBXNativeTarget section */ 95 | 96 | /* Begin PBXProject section */ 97 | D5B2E8961C3A780C00C0327D /* Project object */ = { 98 | isa = PBXProject; 99 | attributes = { 100 | LastSwiftUpdateCheck = 0720; 101 | LastUpgradeCheck = 0800; 102 | ORGANIZATIONNAME = "Hyper Interaktiv AS"; 103 | TargetAttributes = { 104 | D5B2E89E1C3A780C00C0327D = { 105 | CreatedOnToolsVersion = 7.2; 106 | LastSwiftMigration = 0800; 107 | }; 108 | }; 109 | }; 110 | buildConfigurationList = D5B2E8991C3A780C00C0327D /* Build configuration list for PBXProject "Ripple" */; 111 | compatibilityVersion = "Xcode 3.2"; 112 | developmentRegion = English; 113 | hasScannedForEncodings = 0; 114 | knownRegions = ( 115 | en, 116 | ); 117 | mainGroup = D5B2E8951C3A780C00C0327D; 118 | productRefGroup = D5B2E8A01C3A780C00C0327D /* Products */; 119 | projectDirPath = ""; 120 | projectRoot = ""; 121 | targets = ( 122 | D5B2E89E1C3A780C00C0327D /* Ripple */, 123 | ); 124 | }; 125 | /* End PBXProject section */ 126 | 127 | /* Begin PBXResourcesBuildPhase section */ 128 | D5B2E89D1C3A780C00C0327D /* Resources */ = { 129 | isa = PBXResourcesBuildPhase; 130 | buildActionMask = 2147483647; 131 | files = ( 132 | ); 133 | runOnlyForDeploymentPostprocessing = 0; 134 | }; 135 | /* End PBXResourcesBuildPhase section */ 136 | 137 | /* Begin PBXSourcesBuildPhase section */ 138 | D5B2E89A1C3A780C00C0327D /* Sources */ = { 139 | isa = PBXSourcesBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | 295F59841DACFBCA00726D50 /* Ripple.swift in Sources */, 143 | ); 144 | runOnlyForDeploymentPostprocessing = 0; 145 | }; 146 | /* End PBXSourcesBuildPhase section */ 147 | 148 | /* Begin XCBuildConfiguration section */ 149 | D5B2E8B11C3A780C00C0327D /* Debug */ = { 150 | isa = XCBuildConfiguration; 151 | buildSettings = { 152 | ALWAYS_SEARCH_USER_PATHS = NO; 153 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 154 | CLANG_CXX_LIBRARY = "libc++"; 155 | CLANG_ENABLE_MODULES = YES; 156 | CLANG_ENABLE_OBJC_ARC = YES; 157 | CLANG_WARN_BOOL_CONVERSION = YES; 158 | CLANG_WARN_CONSTANT_CONVERSION = YES; 159 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 160 | CLANG_WARN_EMPTY_BODY = YES; 161 | CLANG_WARN_ENUM_CONVERSION = YES; 162 | CLANG_WARN_INFINITE_RECURSION = YES; 163 | CLANG_WARN_INT_CONVERSION = YES; 164 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 165 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 166 | CLANG_WARN_UNREACHABLE_CODE = YES; 167 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 168 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 169 | COPY_PHASE_STRIP = NO; 170 | CURRENT_PROJECT_VERSION = 1; 171 | DEBUG_INFORMATION_FORMAT = dwarf; 172 | ENABLE_STRICT_OBJC_MSGSEND = YES; 173 | ENABLE_TESTABILITY = YES; 174 | GCC_C_LANGUAGE_STANDARD = gnu99; 175 | GCC_DYNAMIC_NO_PIC = NO; 176 | GCC_NO_COMMON_BLOCKS = YES; 177 | GCC_OPTIMIZATION_LEVEL = 0; 178 | GCC_PREPROCESSOR_DEFINITIONS = ( 179 | "DEBUG=1", 180 | "$(inherited)", 181 | ); 182 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 183 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 184 | GCC_WARN_UNDECLARED_SELECTOR = YES; 185 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 186 | GCC_WARN_UNUSED_FUNCTION = YES; 187 | GCC_WARN_UNUSED_VARIABLE = YES; 188 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 189 | MTL_ENABLE_DEBUG_INFO = YES; 190 | ONLY_ACTIVE_ARCH = YES; 191 | SDKROOT = iphoneos; 192 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 193 | SWIFT_VERSION = 3.0; 194 | TARGETED_DEVICE_FAMILY = "1,2"; 195 | VERSIONING_SYSTEM = "apple-generic"; 196 | VERSION_INFO_PREFIX = ""; 197 | }; 198 | name = Debug; 199 | }; 200 | D5B2E8B21C3A780C00C0327D /* Release */ = { 201 | isa = XCBuildConfiguration; 202 | buildSettings = { 203 | ALWAYS_SEARCH_USER_PATHS = NO; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_WARN_BOOL_CONVERSION = YES; 209 | CLANG_WARN_CONSTANT_CONVERSION = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INFINITE_RECURSION = YES; 214 | CLANG_WARN_INT_CONVERSION = YES; 215 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 216 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 217 | CLANG_WARN_UNREACHABLE_CODE = YES; 218 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 219 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 220 | COPY_PHASE_STRIP = NO; 221 | CURRENT_PROJECT_VERSION = 1; 222 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 223 | ENABLE_NS_ASSERTIONS = NO; 224 | ENABLE_STRICT_OBJC_MSGSEND = YES; 225 | GCC_C_LANGUAGE_STANDARD = gnu99; 226 | GCC_NO_COMMON_BLOCKS = YES; 227 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 228 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 229 | GCC_WARN_UNDECLARED_SELECTOR = YES; 230 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 231 | GCC_WARN_UNUSED_FUNCTION = YES; 232 | GCC_WARN_UNUSED_VARIABLE = YES; 233 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 234 | MTL_ENABLE_DEBUG_INFO = NO; 235 | SDKROOT = iphoneos; 236 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 237 | SWIFT_VERSION = 3.0; 238 | TARGETED_DEVICE_FAMILY = "1,2"; 239 | VALIDATE_PRODUCT = YES; 240 | VERSIONING_SYSTEM = "apple-generic"; 241 | VERSION_INFO_PREFIX = ""; 242 | }; 243 | name = Release; 244 | }; 245 | D5B2E8B41C3A780C00C0327D /* Debug */ = { 246 | isa = XCBuildConfiguration; 247 | buildSettings = { 248 | CLANG_ENABLE_MODULES = YES; 249 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 250 | DEFINES_MODULE = YES; 251 | DYLIB_COMPATIBILITY_VERSION = 1; 252 | DYLIB_CURRENT_VERSION = 1; 253 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 254 | INFOPLIST_FILE = "$(SRCROOT)/Others/Info.plist"; 255 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 256 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 257 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 258 | PRODUCT_BUNDLE_IDENTIFIER = "com.RamonGilabert.Ripple-iOS"; 259 | PRODUCT_NAME = Ripple; 260 | SKIP_INSTALL = YES; 261 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 262 | SWIFT_VERSION = 3.0; 263 | }; 264 | name = Debug; 265 | }; 266 | D5B2E8B51C3A780C00C0327D /* Release */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | CLANG_ENABLE_MODULES = YES; 270 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 271 | DEFINES_MODULE = YES; 272 | DYLIB_COMPATIBILITY_VERSION = 1; 273 | DYLIB_CURRENT_VERSION = 1; 274 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 275 | INFOPLIST_FILE = "$(SRCROOT)/Others/Info.plist"; 276 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 277 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 278 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 279 | PRODUCT_BUNDLE_IDENTIFIER = "com.RamonGilabert.Ripple-iOS"; 280 | PRODUCT_NAME = Ripple; 281 | SKIP_INSTALL = YES; 282 | SWIFT_VERSION = 3.0; 283 | }; 284 | name = Release; 285 | }; 286 | /* End XCBuildConfiguration section */ 287 | 288 | /* Begin XCConfigurationList section */ 289 | D5B2E8991C3A780C00C0327D /* Build configuration list for PBXProject "Ripple" */ = { 290 | isa = XCConfigurationList; 291 | buildConfigurations = ( 292 | D5B2E8B11C3A780C00C0327D /* Debug */, 293 | D5B2E8B21C3A780C00C0327D /* Release */, 294 | ); 295 | defaultConfigurationIsVisible = 0; 296 | defaultConfigurationName = Release; 297 | }; 298 | D5B2E8B31C3A780C00C0327D /* Build configuration list for PBXNativeTarget "Ripple" */ = { 299 | isa = XCConfigurationList; 300 | buildConfigurations = ( 301 | D5B2E8B41C3A780C00C0327D /* Debug */, 302 | D5B2E8B51C3A780C00C0327D /* Release */, 303 | ); 304 | defaultConfigurationIsVisible = 0; 305 | defaultConfigurationName = Release; 306 | }; 307 | /* End XCConfigurationList section */ 308 | }; 309 | rootObject = D5B2E8961C3A780C00C0327D /* Project object */; 310 | } 311 | -------------------------------------------------------------------------------- /Ripple.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Ripple.xcodeproj/xcshareddata/xcschemes/Ripple.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Sources/Ripple.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /** 4 | Ripple makes a ripple effect like when you drop a droplet in the water. 5 | 6 | - Parameter center: The center point where the ripple should start. 7 | - Parameter view: The view the ripple should be applied to. 8 | - Parameter times: (Optional) The number of times the ripple should repeat, Infinity by default. 9 | - Parameter duration: (Optional) The duration of each ripple effect, 2 by default. 10 | - Parameter size: (Optional) The initial size of the ripple, 50 by default. 11 | - Parameter multiplier: (Optional) The multiplier that should apply to know the end size, 4 by default. 12 | - Parameter divider: (Optional) The divider for the timer to apply the next ripple, 2 by default. 13 | - Parameter color: (Optional) The color of the ripple, white by default. 14 | - Parameter border: (Optional) The border width of the ripple, 2.25 by default. 15 | */ 16 | public func ripple(_ center: CGPoint, view: UIView, times: Float = Float.infinity, 17 | duration: TimeInterval = 2, 18 | size: CGFloat = 50, 19 | multiplier: CGFloat = 4, 20 | divider: CGFloat = 2, 21 | color: UIColor = UIColor.white, 22 | border: CGFloat = 2.25) { 23 | 24 | let ripple = droplet(center, view: view, duration: duration, 25 | size: size, multiplier: multiplier, color: color, border: border) 26 | let timer = Timer.scheduledTimer(timeInterval: duration / Double(divider), 27 | target: ripple, 28 | selector: #selector(Ripple.timerDidFire), 29 | userInfo: nil, repeats: true) 30 | 31 | timers.append(timer) 32 | 33 | guard times != Float.infinity && times > 0 else { return } 34 | 35 | let denominator = Double(times - 1) * Double(duration) / Double(divider) * Double(NSEC_PER_SEC) 36 | let deadline = DispatchTime.now() + denominator 37 | DispatchQueue.main.asyncAfter(deadline: deadline) { 38 | timer.invalidate() 39 | } 40 | } 41 | 42 | /** 43 | Droplet makes a just once ripple effect like when you drop a droplet in the water. 44 | 45 | - Parameter center: The center point where the ripple should start. 46 | - Parameter view: The view the ripple should be applied to. 47 | - Parameter duration: (Optional) The duration of each ripple effect, 2 by default. 48 | - Parameter size: (Optional) The initial size of the ripple, 50 by default. 49 | - Parameter multiplier: (Optional) The multiplier that should apply to know the end size, 4 by default. 50 | - Parameter color: (Optional) The color of the ripple, white by default. 51 | - Parameter border: (Optional) The border width of the ripple, 2.25 by default. 52 | 53 | - Returns: A ripple object, you can't do much with it though, it's just for internal use. 54 | */ 55 | public func droplet(_ center: CGPoint, view: UIView, 56 | duration: TimeInterval = 2, 57 | size: CGFloat = 50, multiplier: CGFloat = 4, 58 | color: UIColor = UIColor.white, border: CGFloat = 2.25) -> Ripple { 59 | 60 | let ripple = Ripple(center: center, view: view, 61 | duration: duration, 62 | size: CGSize(width: size, height: size), 63 | multiplier: multiplier, 64 | color: color, 65 | border: border) 66 | 67 | ripple.activate() 68 | 69 | return ripple 70 | } 71 | 72 | /** 73 | Calm stops all your current timers. 74 | */ 75 | public func calm() { 76 | timers.forEach { $0.invalidate() } 77 | timers.removeAll() 78 | } 79 | 80 | var timers: [Timer] = [] 81 | 82 | /** 83 | The ripple creator 84 | */ 85 | open class Ripple: NSObject { 86 | 87 | var center: CGPoint 88 | var view: UIView 89 | var duration: TimeInterval 90 | var size: CGSize 91 | var multiplier: CGFloat 92 | var color: UIColor 93 | var border: CGFloat 94 | var ripples: [UIView] = [] 95 | 96 | init(center: CGPoint, view: UIView, 97 | duration: TimeInterval, size: CGSize, 98 | multiplier: CGFloat, color: UIColor, border: CGFloat) { 99 | 100 | self.center = center 101 | self.view = view 102 | self.duration = duration 103 | self.size = size 104 | self.multiplier = multiplier 105 | self.color = color 106 | self.border = border 107 | } 108 | 109 | func activate() { 110 | let ripple = UIView() 111 | 112 | if let subview = view.subviews.first { 113 | view.insertSubview(ripple, aboveSubview: subview) 114 | } else { 115 | view.insertSubview(ripple, at: 0) 116 | } 117 | 118 | ripple.frame.origin = CGPoint(x: center.x - size.width / 2, 119 | y: center.y - size.height / 2) 120 | ripple.frame.size = size 121 | ripple.layer.borderColor = color.cgColor 122 | ripple.layer.borderWidth = border 123 | ripple.layer.cornerRadius = ripple.bounds.width / 2 124 | 125 | let animation = CABasicAnimation(keyPath: "cornerRadius") 126 | animation.fromValue = ripple.layer.cornerRadius 127 | animation.toValue = size.width * multiplier / 2 128 | 129 | let boundsAnimation = CABasicAnimation(keyPath: "bounds.size") 130 | boundsAnimation.fromValue = NSValue(cgSize: ripple.layer.bounds.size) 131 | boundsAnimation.toValue = NSValue(cgSize: CGSize(width: size.width * multiplier, height: size.height * multiplier)) 132 | 133 | let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity") 134 | opacityAnimation.values = [0, 1, 1, 1, 0] 135 | 136 | let animationGroup = CAAnimationGroup() 137 | animationGroup.animations = [animation, boundsAnimation, opacityAnimation] 138 | animationGroup.duration = duration 139 | animationGroup.delegate = self 140 | animationGroup.timingFunction = CAMediaTimingFunction(controlPoints: 0.22, 0.54, 0.2, 0.47) 141 | animationGroup.isRemovedOnCompletion = false 142 | animationGroup.fillMode = kCAFillModeForwards 143 | 144 | ripples.append(ripple) 145 | ripple.layer.add(animationGroup, forKey: "ripple") 146 | } 147 | 148 | func timerDidFire() { 149 | activate() 150 | } 151 | } 152 | 153 | extension Ripple: CAAnimationDelegate { 154 | 155 | /** 156 | The animation delegate method that helps to do better ripples. 157 | */ 158 | open func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { 159 | guard let ripple = ripples.first else { return } 160 | 161 | ripple.alpha = 0 162 | ripple.removeFromSuperview() 163 | ripple.layer.removeAnimation(forKey: "ripple") 164 | 165 | ripples.removeFirst() 166 | } 167 | } 168 | --------------------------------------------------------------------------------