├── .gitignore ├── KKGestureLockView.podspec ├── KKGestureLockView.xcodeproj └── project.pbxproj ├── KKGestureLockView ├── Default-568h@2x.png ├── Default.png ├── Default@2x.png ├── KKAppDelegate.h ├── KKAppDelegate.m ├── KKGestureLockView-Info.plist ├── KKGestureLockView-Prefix.pch ├── KKViewController.h ├── KKViewController.m ├── Source │ ├── KKGestureLockPreviewView.h │ ├── KKGestureLockPreviewView.m │ ├── KKGestureLockView.h │ └── KKGestureLockView.m ├── en.lproj │ ├── InfoPlist.strings │ └── KKViewController.xib ├── gesture_background.png ├── gesture_node_normal.png ├── gesture_node_normal@2x.png ├── gesture_node_selected.png ├── gesture_node_selected@2x.png └── main.m ├── README.md ├── pic.png ├── screenshot.png └── screenshot2.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .hgignore 3 | 4 | build/* 5 | .hg/* 6 | docs/* 7 | .svn/ 8 | 9 | # Xcode 10 | *.pbxuser 11 | *.mode1v3 12 | *.mode2v3 13 | *.perspectivev3 14 | *.xcuserstate 15 | project.xcworkspace/ 16 | xcuserdata/ 17 | 18 | .idea/ -------------------------------------------------------------------------------- /KKGestureLockView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "KKGestureLockView" 3 | s.version = "1.0.0" 4 | s.summary = "A Gesture Lock View For iOS." 5 | s.homepage = "https://github.com/kejinlu/KKGestureLockView" 6 | s.authors = { "Luke" => "kejinlu@gmail.com" } 7 | s.source = { :git => "https://github.com/kejinlu/KKGestureLockView.git", :tag => "1.0.0" } 8 | s.source_files = 'KKGestureLockView/Source/*.{h,m}' 9 | s.requires_arc = true 10 | s.platform = :ios 11 | s.ios.deployment_target = '5.0' 12 | s.license = { 13 | :type => 'Modified BSD', 14 | :text => <<-LICENSE 15 | Copyright (c) 2012 Luke. All rights reserved. 16 | 17 | Redistribution and use in source and binary forms, with or without 18 | modification, are permitted provided that the following conditions 19 | are met: 20 | 1. Redistributions of source code must retain the above copyright 21 | notice, this list of conditions and the following disclaimer. 22 | 2. Redistributions in binary form must reproduce the above copyright 23 | notice, this list of conditions and the following disclaimer in the 24 | documentation and/or other materials provided with the distribution. 25 | 3. The name of the author may not be used to endorse or promote products 26 | derived from this software without specific prior written permission. 27 | 28 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 29 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 30 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 31 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 32 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 33 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 37 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | LICENSE 39 | } 40 | end 41 | -------------------------------------------------------------------------------- /KKGestureLockView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A338823818CE1D2400CEF8D1 /* KKGestureLockPreviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = A338823718CE1D2400CEF8D1 /* KKGestureLockPreviewView.m */; }; 11 | A399B43D17AED01800ADF304 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A399B43C17AED01800ADF304 /* UIKit.framework */; }; 12 | A399B43F17AED01800ADF304 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A399B43E17AED01800ADF304 /* Foundation.framework */; }; 13 | A399B44117AED01800ADF304 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A399B44017AED01800ADF304 /* CoreGraphics.framework */; }; 14 | A399B44717AED01800ADF304 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A399B44517AED01800ADF304 /* InfoPlist.strings */; }; 15 | A399B44917AED01800ADF304 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A399B44817AED01800ADF304 /* main.m */; }; 16 | A399B44D17AED01800ADF304 /* KKAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A399B44C17AED01800ADF304 /* KKAppDelegate.m */; }; 17 | A399B44F17AED01800ADF304 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = A399B44E17AED01800ADF304 /* Default.png */; }; 18 | A399B45117AED01800ADF304 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A399B45017AED01800ADF304 /* Default@2x.png */; }; 19 | A399B45317AED01800ADF304 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A399B45217AED01800ADF304 /* Default-568h@2x.png */; }; 20 | A399B45617AED01800ADF304 /* KKViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A399B45517AED01800ADF304 /* KKViewController.m */; }; 21 | A399B45917AED01800ADF304 /* KKViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A399B45717AED01800ADF304 /* KKViewController.xib */; }; 22 | A399B46717AF507400ADF304 /* gesture_node_normal@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A399B46317AF507400ADF304 /* gesture_node_normal@2x.png */; }; 23 | A399B46817AF507400ADF304 /* gesture_node_normal.png in Resources */ = {isa = PBXBuildFile; fileRef = A399B46417AF507400ADF304 /* gesture_node_normal.png */; }; 24 | A399B46917AF507400ADF304 /* gesture_node_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A399B46517AF507400ADF304 /* gesture_node_selected@2x.png */; }; 25 | A399B46A17AF507400ADF304 /* gesture_node_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = A399B46617AF507400ADF304 /* gesture_node_selected.png */; }; 26 | A399B46C17AF8FD300ADF304 /* gesture_background.png in Resources */ = {isa = PBXBuildFile; fileRef = A399B46B17AF8FD300ADF304 /* gesture_background.png */; }; 27 | A399B47017AF997100ADF304 /* KKGestureLockView.m in Sources */ = {isa = PBXBuildFile; fileRef = A399B46F17AF997100ADF304 /* KKGestureLockView.m */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | A338823618CE1D2400CEF8D1 /* KKGestureLockPreviewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KKGestureLockPreviewView.h; sourceTree = ""; }; 32 | A338823718CE1D2400CEF8D1 /* KKGestureLockPreviewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KKGestureLockPreviewView.m; sourceTree = ""; }; 33 | A399B43917AED01800ADF304 /* KKGestureLockView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KKGestureLockView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | A399B43C17AED01800ADF304 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 35 | A399B43E17AED01800ADF304 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 36 | A399B44017AED01800ADF304 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 37 | A399B44417AED01800ADF304 /* KKGestureLockView-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "KKGestureLockView-Info.plist"; sourceTree = ""; }; 38 | A399B44617AED01800ADF304 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 39 | A399B44817AED01800ADF304 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 40 | A399B44A17AED01800ADF304 /* KKGestureLockView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KKGestureLockView-Prefix.pch"; sourceTree = ""; }; 41 | A399B44B17AED01800ADF304 /* KKAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KKAppDelegate.h; sourceTree = ""; }; 42 | A399B44C17AED01800ADF304 /* KKAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KKAppDelegate.m; sourceTree = ""; }; 43 | A399B44E17AED01800ADF304 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 44 | A399B45017AED01800ADF304 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 45 | A399B45217AED01800ADF304 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 46 | A399B45417AED01800ADF304 /* KKViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KKViewController.h; sourceTree = ""; }; 47 | A399B45517AED01800ADF304 /* KKViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KKViewController.m; sourceTree = ""; }; 48 | A399B45817AED01800ADF304 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/KKViewController.xib; sourceTree = ""; }; 49 | A399B46317AF507400ADF304 /* gesture_node_normal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "gesture_node_normal@2x.png"; sourceTree = ""; }; 50 | A399B46417AF507400ADF304 /* gesture_node_normal.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gesture_node_normal.png; sourceTree = ""; }; 51 | A399B46517AF507400ADF304 /* gesture_node_selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "gesture_node_selected@2x.png"; sourceTree = ""; }; 52 | A399B46617AF507400ADF304 /* gesture_node_selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gesture_node_selected.png; sourceTree = ""; }; 53 | A399B46B17AF8FD300ADF304 /* gesture_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gesture_background.png; sourceTree = ""; }; 54 | A399B46E17AF997100ADF304 /* KKGestureLockView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KKGestureLockView.h; sourceTree = ""; }; 55 | A399B46F17AF997100ADF304 /* KKGestureLockView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KKGestureLockView.m; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | A399B43617AED01800ADF304 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | A399B43D17AED01800ADF304 /* UIKit.framework in Frameworks */, 64 | A399B43F17AED01800ADF304 /* Foundation.framework in Frameworks */, 65 | A399B44117AED01800ADF304 /* CoreGraphics.framework in Frameworks */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | A399B43017AED01800ADF304 = { 73 | isa = PBXGroup; 74 | children = ( 75 | A399B44217AED01800ADF304 /* KKGestureLockView */, 76 | A399B43B17AED01800ADF304 /* Frameworks */, 77 | A399B43A17AED01800ADF304 /* Products */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | A399B43A17AED01800ADF304 /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | A399B43917AED01800ADF304 /* KKGestureLockView.app */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | A399B43B17AED01800ADF304 /* Frameworks */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | A399B43C17AED01800ADF304 /* UIKit.framework */, 93 | A399B43E17AED01800ADF304 /* Foundation.framework */, 94 | A399B44017AED01800ADF304 /* CoreGraphics.framework */, 95 | ); 96 | name = Frameworks; 97 | sourceTree = ""; 98 | }; 99 | A399B44217AED01800ADF304 /* KKGestureLockView */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | A399B46D17AF997100ADF304 /* Source */, 103 | A399B44B17AED01800ADF304 /* KKAppDelegate.h */, 104 | A399B44C17AED01800ADF304 /* KKAppDelegate.m */, 105 | A399B45417AED01800ADF304 /* KKViewController.h */, 106 | A399B45517AED01800ADF304 /* KKViewController.m */, 107 | A399B45717AED01800ADF304 /* KKViewController.xib */, 108 | A399B44317AED01800ADF304 /* Supporting Files */, 109 | ); 110 | path = KKGestureLockView; 111 | sourceTree = ""; 112 | }; 113 | A399B44317AED01800ADF304 /* Supporting Files */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | A399B46B17AF8FD300ADF304 /* gesture_background.png */, 117 | A399B46317AF507400ADF304 /* gesture_node_normal@2x.png */, 118 | A399B46417AF507400ADF304 /* gesture_node_normal.png */, 119 | A399B46517AF507400ADF304 /* gesture_node_selected@2x.png */, 120 | A399B46617AF507400ADF304 /* gesture_node_selected.png */, 121 | A399B44417AED01800ADF304 /* KKGestureLockView-Info.plist */, 122 | A399B44517AED01800ADF304 /* InfoPlist.strings */, 123 | A399B44817AED01800ADF304 /* main.m */, 124 | A399B44A17AED01800ADF304 /* KKGestureLockView-Prefix.pch */, 125 | A399B44E17AED01800ADF304 /* Default.png */, 126 | A399B45017AED01800ADF304 /* Default@2x.png */, 127 | A399B45217AED01800ADF304 /* Default-568h@2x.png */, 128 | ); 129 | name = "Supporting Files"; 130 | sourceTree = ""; 131 | }; 132 | A399B46D17AF997100ADF304 /* Source */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | A399B46E17AF997100ADF304 /* KKGestureLockView.h */, 136 | A399B46F17AF997100ADF304 /* KKGestureLockView.m */, 137 | A338823618CE1D2400CEF8D1 /* KKGestureLockPreviewView.h */, 138 | A338823718CE1D2400CEF8D1 /* KKGestureLockPreviewView.m */, 139 | ); 140 | path = Source; 141 | sourceTree = ""; 142 | }; 143 | /* End PBXGroup section */ 144 | 145 | /* Begin PBXNativeTarget section */ 146 | A399B43817AED01800ADF304 /* KKGestureLockView */ = { 147 | isa = PBXNativeTarget; 148 | buildConfigurationList = A399B45C17AED01800ADF304 /* Build configuration list for PBXNativeTarget "KKGestureLockView" */; 149 | buildPhases = ( 150 | A399B43517AED01800ADF304 /* Sources */, 151 | A399B43617AED01800ADF304 /* Frameworks */, 152 | A399B43717AED01800ADF304 /* Resources */, 153 | ); 154 | buildRules = ( 155 | ); 156 | dependencies = ( 157 | ); 158 | name = KKGestureLockView; 159 | productName = KKGestureLockView; 160 | productReference = A399B43917AED01800ADF304 /* KKGestureLockView.app */; 161 | productType = "com.apple.product-type.application"; 162 | }; 163 | /* End PBXNativeTarget section */ 164 | 165 | /* Begin PBXProject section */ 166 | A399B43117AED01800ADF304 /* Project object */ = { 167 | isa = PBXProject; 168 | attributes = { 169 | CLASSPREFIX = KK; 170 | LastUpgradeCheck = 0460; 171 | ORGANIZATIONNAME = geeklu; 172 | }; 173 | buildConfigurationList = A399B43417AED01800ADF304 /* Build configuration list for PBXProject "KKGestureLockView" */; 174 | compatibilityVersion = "Xcode 3.2"; 175 | developmentRegion = English; 176 | hasScannedForEncodings = 0; 177 | knownRegions = ( 178 | en, 179 | ); 180 | mainGroup = A399B43017AED01800ADF304; 181 | productRefGroup = A399B43A17AED01800ADF304 /* Products */; 182 | projectDirPath = ""; 183 | projectRoot = ""; 184 | targets = ( 185 | A399B43817AED01800ADF304 /* KKGestureLockView */, 186 | ); 187 | }; 188 | /* End PBXProject section */ 189 | 190 | /* Begin PBXResourcesBuildPhase section */ 191 | A399B43717AED01800ADF304 /* Resources */ = { 192 | isa = PBXResourcesBuildPhase; 193 | buildActionMask = 2147483647; 194 | files = ( 195 | A399B44717AED01800ADF304 /* InfoPlist.strings in Resources */, 196 | A399B44F17AED01800ADF304 /* Default.png in Resources */, 197 | A399B45117AED01800ADF304 /* Default@2x.png in Resources */, 198 | A399B45317AED01800ADF304 /* Default-568h@2x.png in Resources */, 199 | A399B45917AED01800ADF304 /* KKViewController.xib in Resources */, 200 | A399B46717AF507400ADF304 /* gesture_node_normal@2x.png in Resources */, 201 | A399B46817AF507400ADF304 /* gesture_node_normal.png in Resources */, 202 | A399B46917AF507400ADF304 /* gesture_node_selected@2x.png in Resources */, 203 | A399B46A17AF507400ADF304 /* gesture_node_selected.png in Resources */, 204 | A399B46C17AF8FD300ADF304 /* gesture_background.png in Resources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | /* End PBXResourcesBuildPhase section */ 209 | 210 | /* Begin PBXSourcesBuildPhase section */ 211 | A399B43517AED01800ADF304 /* Sources */ = { 212 | isa = PBXSourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | A399B44917AED01800ADF304 /* main.m in Sources */, 216 | A399B44D17AED01800ADF304 /* KKAppDelegate.m in Sources */, 217 | A338823818CE1D2400CEF8D1 /* KKGestureLockPreviewView.m in Sources */, 218 | A399B45617AED01800ADF304 /* KKViewController.m in Sources */, 219 | A399B47017AF997100ADF304 /* KKGestureLockView.m in Sources */, 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | }; 223 | /* End PBXSourcesBuildPhase section */ 224 | 225 | /* Begin PBXVariantGroup section */ 226 | A399B44517AED01800ADF304 /* InfoPlist.strings */ = { 227 | isa = PBXVariantGroup; 228 | children = ( 229 | A399B44617AED01800ADF304 /* en */, 230 | ); 231 | name = InfoPlist.strings; 232 | sourceTree = ""; 233 | }; 234 | A399B45717AED01800ADF304 /* KKViewController.xib */ = { 235 | isa = PBXVariantGroup; 236 | children = ( 237 | A399B45817AED01800ADF304 /* en */, 238 | ); 239 | name = KKViewController.xib; 240 | sourceTree = ""; 241 | }; 242 | /* End PBXVariantGroup section */ 243 | 244 | /* Begin XCBuildConfiguration section */ 245 | A399B45A17AED01800ADF304 /* Debug */ = { 246 | isa = XCBuildConfiguration; 247 | buildSettings = { 248 | ALWAYS_SEARCH_USER_PATHS = NO; 249 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 250 | CLANG_CXX_LIBRARY = "libc++"; 251 | CLANG_ENABLE_OBJC_ARC = YES; 252 | CLANG_WARN_CONSTANT_CONVERSION = YES; 253 | CLANG_WARN_EMPTY_BODY = YES; 254 | CLANG_WARN_ENUM_CONVERSION = YES; 255 | CLANG_WARN_INT_CONVERSION = YES; 256 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 257 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 258 | COPY_PHASE_STRIP = NO; 259 | GCC_C_LANGUAGE_STANDARD = gnu99; 260 | GCC_DYNAMIC_NO_PIC = NO; 261 | GCC_OPTIMIZATION_LEVEL = 0; 262 | GCC_PREPROCESSOR_DEFINITIONS = ( 263 | "DEBUG=1", 264 | "$(inherited)", 265 | ); 266 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 267 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 268 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 269 | GCC_WARN_UNUSED_VARIABLE = YES; 270 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 271 | ONLY_ACTIVE_ARCH = YES; 272 | SDKROOT = iphoneos; 273 | }; 274 | name = Debug; 275 | }; 276 | A399B45B17AED01800ADF304 /* Release */ = { 277 | isa = XCBuildConfiguration; 278 | buildSettings = { 279 | ALWAYS_SEARCH_USER_PATHS = NO; 280 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 281 | CLANG_CXX_LIBRARY = "libc++"; 282 | CLANG_ENABLE_OBJC_ARC = YES; 283 | CLANG_WARN_CONSTANT_CONVERSION = YES; 284 | CLANG_WARN_EMPTY_BODY = YES; 285 | CLANG_WARN_ENUM_CONVERSION = YES; 286 | CLANG_WARN_INT_CONVERSION = YES; 287 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 288 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 289 | COPY_PHASE_STRIP = YES; 290 | GCC_C_LANGUAGE_STANDARD = gnu99; 291 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 295 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 296 | SDKROOT = iphoneos; 297 | VALIDATE_PRODUCT = YES; 298 | }; 299 | name = Release; 300 | }; 301 | A399B45D17AED01800ADF304 /* Debug */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 305 | GCC_PREFIX_HEADER = "KKGestureLockView/KKGestureLockView-Prefix.pch"; 306 | INFOPLIST_FILE = "KKGestureLockView/KKGestureLockView-Info.plist"; 307 | PRODUCT_NAME = "$(TARGET_NAME)"; 308 | WRAPPER_EXTENSION = app; 309 | }; 310 | name = Debug; 311 | }; 312 | A399B45E17AED01800ADF304 /* Release */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 316 | GCC_PREFIX_HEADER = "KKGestureLockView/KKGestureLockView-Prefix.pch"; 317 | INFOPLIST_FILE = "KKGestureLockView/KKGestureLockView-Info.plist"; 318 | PRODUCT_NAME = "$(TARGET_NAME)"; 319 | WRAPPER_EXTENSION = app; 320 | }; 321 | name = Release; 322 | }; 323 | /* End XCBuildConfiguration section */ 324 | 325 | /* Begin XCConfigurationList section */ 326 | A399B43417AED01800ADF304 /* Build configuration list for PBXProject "KKGestureLockView" */ = { 327 | isa = XCConfigurationList; 328 | buildConfigurations = ( 329 | A399B45A17AED01800ADF304 /* Debug */, 330 | A399B45B17AED01800ADF304 /* Release */, 331 | ); 332 | defaultConfigurationIsVisible = 0; 333 | defaultConfigurationName = Release; 334 | }; 335 | A399B45C17AED01800ADF304 /* Build configuration list for PBXNativeTarget "KKGestureLockView" */ = { 336 | isa = XCConfigurationList; 337 | buildConfigurations = ( 338 | A399B45D17AED01800ADF304 /* Debug */, 339 | A399B45E17AED01800ADF304 /* Release */, 340 | ); 341 | defaultConfigurationIsVisible = 0; 342 | defaultConfigurationName = Release; 343 | }; 344 | /* End XCConfigurationList section */ 345 | }; 346 | rootObject = A399B43117AED01800ADF304 /* Project object */; 347 | } 348 | -------------------------------------------------------------------------------- /KKGestureLockView/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/KKGestureLockView/Default-568h@2x.png -------------------------------------------------------------------------------- /KKGestureLockView/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/KKGestureLockView/Default.png -------------------------------------------------------------------------------- /KKGestureLockView/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/KKGestureLockView/Default@2x.png -------------------------------------------------------------------------------- /KKGestureLockView/KKAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // KKAppDelegate.h 3 | // KKGestureLockView 4 | // 5 | // Created by Luke on 8/5/13. 6 | // Copyright (c) 2013 geeklu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class KKViewController; 12 | 13 | @interface KKAppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @property (strong, nonatomic) KKViewController *viewController; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /KKGestureLockView/KKAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // KKAppDelegate.m 3 | // KKGestureLockView 4 | // 5 | // Created by Luke on 8/5/13. 6 | // Copyright (c) 2013 geeklu. All rights reserved. 7 | // 8 | 9 | #import "KKAppDelegate.h" 10 | 11 | #import "KKViewController.h" 12 | 13 | @implementation KKAppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | // Override point for customization after application launch. 19 | self.viewController = [[KKViewController alloc] initWithNibName:@"KKViewController" bundle:nil]; 20 | self.window.rootViewController = self.viewController; 21 | [self.window makeKeyAndVisible]; 22 | return YES; 23 | } 24 | 25 | - (void)applicationWillResignActive:(UIApplication *)application 26 | { 27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 28 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 29 | } 30 | 31 | - (void)applicationDidEnterBackground:(UIApplication *)application 32 | { 33 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | - (void)applicationWillEnterForeground:(UIApplication *)application 38 | { 39 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 40 | } 41 | 42 | - (void)applicationDidBecomeActive:(UIApplication *)application 43 | { 44 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 45 | } 46 | 47 | - (void)applicationWillTerminate:(UIApplication *)application 48 | { 49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /KKGestureLockView/KKGestureLockView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.geeklu.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /KKGestureLockView/KKGestureLockView-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'KKGestureLockView' target in the 'KKGestureLockView' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /KKGestureLockView/KKViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // KKViewController.h 3 | // KKGestureLockView 4 | // 5 | // Created by Luke on 8/5/13. 6 | // Copyright (c) 2013 geeklu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "KKGestureLockView.h" 11 | 12 | @interface KKViewController : UIViewController 13 | 14 | @property (nonatomic, strong) IBOutlet KKGestureLockView *lockView; 15 | @end 16 | -------------------------------------------------------------------------------- /KKGestureLockView/KKViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // KKViewController.m 3 | // KKGestureLockView 4 | // 5 | // Created by Luke on 8/5/13. 6 | // Copyright (c) 2013 geeklu. All rights reserved. 7 | // 8 | 9 | #import "KKViewController.h" 10 | @interface KKViewController () 11 | 12 | @end 13 | 14 | @implementation KKViewController 15 | 16 | - (void)viewDidLoad 17 | { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view, typically from a nib. 20 | self.view.backgroundColor = [UIColor whiteColor]; 21 | self.lockView.normalGestureNodeImage = [UIImage imageNamed:@"gesture_node_normal.png"]; 22 | self.lockView.selectedGestureNodeImage = [UIImage imageNamed:@"gesture_node_selected.png"]; 23 | self.lockView.lineColor = [[UIColor orangeColor] colorWithAlphaComponent:0.3]; 24 | self.lockView.lineWidth = 12; 25 | self.lockView.delegate = self; 26 | self.lockView.contentInsets = UIEdgeInsetsMake(150, 20, 100, 20); 27 | } 28 | 29 | - (void)didReceiveMemoryWarning 30 | { 31 | [super didReceiveMemoryWarning]; 32 | // Dispose of any resources that can be recreated. 33 | } 34 | 35 | 36 | - (void)gestureLockView:(KKGestureLockView *)gestureLockView didBeginWithPasscode:(NSString *)passcode{ 37 | NSLog(@"%@",passcode); 38 | } 39 | 40 | - (void)gestureLockView:(KKGestureLockView *)gestureLockView didEndWithPasscode:(NSString *)passcode{ 41 | NSLog(@"%@",passcode); 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /KKGestureLockView/Source/KKGestureLockPreviewView.h: -------------------------------------------------------------------------------- 1 | // 2 | // KKGestureLockPreviewView.h 3 | // KKGestureLockView 4 | // 5 | // Created by Luke on 3/11/14. 6 | // Copyright (c) 2014 geeklu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "KKGestureLockView.h" 11 | 12 | @interface KKGestureLockPreviewView : KKGestureLockView 13 | 14 | @property (nonatomic, strong) NSString *passcode; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /KKGestureLockView/Source/KKGestureLockPreviewView.m: -------------------------------------------------------------------------------- 1 | // 2 | // KKGestureLockPreviewView.m 3 | // KKGestureLockView 4 | // 5 | // Created by Luke on 3/11/14. 6 | // Copyright (c) 2014 geeklu. All rights reserved. 7 | // 8 | 9 | #import "KKGestureLockPreviewView.h" 10 | 11 | @implementation KKGestureLockPreviewView 12 | 13 | - (id)initWithFrame:(CGRect)frame{ 14 | self = [super initWithFrame:frame]; 15 | if (self != nil) { 16 | self.userInteractionEnabled = NO; 17 | } 18 | return self; 19 | } 20 | 21 | - (id)initWithCoder:(NSCoder *)aDecoder{ 22 | self = [super initWithCoder:aDecoder]; 23 | if (self != nil) { 24 | self.userInteractionEnabled = NO; 25 | } 26 | return self; 27 | } 28 | 29 | 30 | - (void)setPasscode:(NSString *)passcode{ 31 | _passcode = passcode; 32 | 33 | 34 | for (UIButton *button in self.buttons) { 35 | if (button.selected) { 36 | button.selected = NO; 37 | } 38 | } 39 | [self.selectedButtons removeAllObjects]; 40 | 41 | NSArray *passcodeComponents = [passcode componentsSeparatedByString:@","]; 42 | for (NSString *indexString in passcodeComponents) { 43 | NSInteger index = [indexString integerValue]; 44 | if (index < [self.buttons count]) { 45 | UIButton *button = [self.buttons objectAtIndex:index]; 46 | button.selected = YES; 47 | [self.selectedButtons addObject:button]; 48 | } 49 | } 50 | 51 | [self setNeedsDisplay]; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /KKGestureLockView/Source/KKGestureLockView.h: -------------------------------------------------------------------------------- 1 | // 2 | // KKGestureLockView.h 3 | // KKGestureLockView 4 | // 5 | // Created by Luke on 8/5/13. 6 | // Copyright (c) 2013 geeklu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class KKGestureLockView; 12 | 13 | @protocol KKGestureLockViewDelegate 14 | @optional 15 | - (void)gestureLockView:(KKGestureLockView *)gestureLockView didBeginWithPasscode:(NSString *)passcode; 16 | 17 | - (void)gestureLockView:(KKGestureLockView *)gestureLockView didEndWithPasscode:(NSString *)passcode; 18 | 19 | - (void)gestureLockView:(KKGestureLockView *)gestureLockView didCanceledWithPasscode:(NSString *)passcode; 20 | @end 21 | 22 | @interface KKGestureLockView : UIView 23 | 24 | @property (nonatomic, strong, readonly) NSArray *buttons; 25 | @property (nonatomic, strong, readonly) NSMutableArray *selectedButtons; 26 | 27 | @property (nonatomic, assign) NSUInteger numberOfGestureNodes; 28 | @property (nonatomic, assign) NSUInteger gestureNodesPerRow; 29 | 30 | @property (nonatomic, strong) UIImage *normalGestureNodeImage; 31 | @property (nonatomic, strong) UIImage *selectedGestureNodeImage; 32 | 33 | @property (nonatomic, strong) UIColor *lineColor; 34 | @property (nonatomic, assign) CGFloat lineWidth; 35 | 36 | @property (nonatomic, strong, readonly) UIView *contentView;//the container of the gesture notes 37 | @property (nonatomic, assign) UIEdgeInsets contentInsets; 38 | 39 | @property (nonatomic, weak) id delegate; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /KKGestureLockView/Source/KKGestureLockView.m: -------------------------------------------------------------------------------- 1 | // 2 | // KKGestureLockView.m 3 | // KKGestureLockView 4 | // 5 | // Created by Luke on 8/5/13. 6 | // Copyright (c) 2013 geeklu. All rights reserved. 7 | // 8 | 9 | #import "KKGestureLockView.h" 10 | const static NSUInteger kNumberOfNodes = 9; 11 | const static NSUInteger kNodesPerRow = 3; 12 | const static CGFloat kNodeDefaultWidth = 60; 13 | const static CGFloat kNodeDefaultHeight = 60; 14 | const static CGFloat kLineDefaultWidth = 16; 15 | 16 | const static CGFloat kTrackedLocationInvalidInContentView = -1.0; 17 | 18 | 19 | @interface KKGestureLockView (){ 20 | struct { 21 | unsigned int didBeginWithPasscode :1; 22 | unsigned int didEndWithPasscode : 1; 23 | unsigned int didCanceled : 1; 24 | } _delegateFlags; 25 | } 26 | 27 | @property (nonatomic, strong) UIView *contentView; 28 | 29 | //Implement nodes with buttons 30 | @property (nonatomic, assign) CGSize buttonSize; 31 | @property (nonatomic, strong) NSArray *buttons; 32 | @property (nonatomic, strong) NSMutableArray *selectedButtons; 33 | 34 | @property (nonatomic, assign) CGPoint trackedLocationInContentView; 35 | 36 | @end 37 | 38 | @implementation KKGestureLockView 39 | 40 | #pragma mark - 41 | #pragma mark Private Methods 42 | 43 | - (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size{ 44 | CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height); 45 | UIGraphicsBeginImageContext(rect.size); 46 | CGContextRef context = UIGraphicsGetCurrentContext(); 47 | 48 | CGContextSetFillColorWithColor(context, [color CGColor]); 49 | CGContextFillRect(context, rect); 50 | 51 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 52 | UIGraphicsEndImageContext(); 53 | 54 | return image; 55 | } 56 | 57 | - (UIButton *)_buttonContainsThePoint:(CGPoint)point{ 58 | for (UIButton *button in self.buttons) { 59 | if (CGRectContainsPoint(button.frame, point)) { 60 | return button; 61 | } 62 | } 63 | return nil; 64 | } 65 | 66 | - (void)_lockViewInitialize{ 67 | self.backgroundColor = [UIColor clearColor]; 68 | 69 | self.lineColor = [[UIColor blackColor] colorWithAlphaComponent:0.3]; 70 | self.lineWidth = kLineDefaultWidth; 71 | 72 | self.contentInsets = UIEdgeInsetsMake(0, 0, 0, 0); 73 | self.contentView = [[UIView alloc] initWithFrame:UIEdgeInsetsInsetRect(self.bounds, self.contentInsets)]; 74 | self.contentView.backgroundColor = [UIColor clearColor]; 75 | [self addSubview:self.contentView]; 76 | 77 | self.buttonSize = CGSizeMake(kNodeDefaultWidth, kNodeDefaultHeight); 78 | 79 | self.normalGestureNodeImage = [self imageWithColor:[UIColor greenColor] size:self.buttonSize]; 80 | self.selectedGestureNodeImage = [self imageWithColor:[UIColor redColor] size:self.buttonSize]; 81 | 82 | self.numberOfGestureNodes = kNumberOfNodes; 83 | self.gestureNodesPerRow = kNodesPerRow; 84 | 85 | self.selectedButtons = [NSMutableArray array]; 86 | 87 | self.trackedLocationInContentView = CGPointMake(kTrackedLocationInvalidInContentView, kTrackedLocationInvalidInContentView); 88 | } 89 | 90 | 91 | #pragma mark - 92 | #pragma mark UIView Overrides 93 | - (id)initWithFrame:(CGRect)frame{ 94 | self = [super initWithFrame:frame]; 95 | if (self != nil) { 96 | [self _lockViewInitialize]; 97 | } 98 | return self; 99 | } 100 | 101 | - (id)initWithCoder:(NSCoder *)aDecoder{ 102 | self = [super initWithCoder:aDecoder]; 103 | if (self != nil) { 104 | [self _lockViewInitialize]; 105 | } 106 | return self; 107 | } 108 | 109 | - (void)layoutSubviews{ 110 | [super layoutSubviews]; 111 | 112 | self.contentView.frame = UIEdgeInsetsInsetRect(self.bounds, self.contentInsets); 113 | CGFloat horizontalNodeMargin = (self.contentView.bounds.size.width - self.buttonSize.width * self.gestureNodesPerRow)/(self.gestureNodesPerRow - 1); 114 | NSUInteger numberOfRows = ceilf((self.numberOfGestureNodes * 1.0 / self.gestureNodesPerRow)); 115 | CGFloat verticalNodeMargin = (self.contentView.bounds.size.height - self.buttonSize.height *numberOfRows)/(numberOfRows - 1); 116 | 117 | for (int i = 0; i < self.numberOfGestureNodes ; i++) { 118 | int row = i / self.gestureNodesPerRow; 119 | int column = i % self.gestureNodesPerRow; 120 | UIButton *button = [self.buttons objectAtIndex:i]; 121 | button.frame = CGRectMake(floorf((self.buttonSize.width + horizontalNodeMargin) * column), floorf((self.buttonSize.height + verticalNodeMargin) * row), self.buttonSize.width, self.buttonSize.height); 122 | } 123 | } 124 | 125 | - (void)drawRect:(CGRect)rect{ 126 | [super drawRect:rect]; 127 | 128 | if ([self.selectedButtons count] > 0) { 129 | UIBezierPath *bezierPath = [UIBezierPath bezierPath]; 130 | UIButton *firstButton = [self.selectedButtons objectAtIndex:0]; 131 | [bezierPath moveToPoint:[self convertPoint:firstButton.center fromView:self.contentView]]; 132 | 133 | for (int i = 1; i < [self.selectedButtons count]; i++) { 134 | UIButton *button = [self.selectedButtons objectAtIndex:i]; 135 | [bezierPath addLineToPoint:[self convertPoint:button.center fromView:self.contentView]]; 136 | } 137 | 138 | if (self.trackedLocationInContentView.x != kTrackedLocationInvalidInContentView && 139 | self.trackedLocationInContentView.y != kTrackedLocationInvalidInContentView) { 140 | [bezierPath addLineToPoint:[self convertPoint:self.trackedLocationInContentView fromView:self.contentView]]; 141 | } 142 | [bezierPath setLineWidth:self.lineWidth]; 143 | [bezierPath setLineJoinStyle:kCGLineJoinRound]; 144 | [self.lineColor setStroke]; 145 | [bezierPath stroke]; 146 | } 147 | } 148 | 149 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 150 | UITouch *touch = [touches anyObject]; 151 | CGPoint locationInContentView = [touch locationInView:self.contentView]; 152 | UIButton *touchedButton = [self _buttonContainsThePoint:locationInContentView]; 153 | if (touchedButton != nil) { 154 | touchedButton.selected = YES; 155 | [self.selectedButtons addObject:touchedButton]; 156 | self.trackedLocationInContentView = locationInContentView; 157 | 158 | if (_delegateFlags.didBeginWithPasscode) { 159 | [self.delegate gestureLockView:self didBeginWithPasscode:[NSString stringWithFormat:@"%d",touchedButton.tag]]; 160 | } 161 | } 162 | } 163 | 164 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ 165 | UITouch *touch = [touches anyObject]; 166 | CGPoint locationInContentView = [touch locationInView:self.contentView]; 167 | if (CGRectContainsPoint(self.contentView.bounds, locationInContentView)) { 168 | UIButton *touchedButton = [self _buttonContainsThePoint:locationInContentView]; 169 | if (touchedButton != nil && [self.selectedButtons indexOfObject:touchedButton]==NSNotFound) { 170 | touchedButton.selected = YES; 171 | [self.selectedButtons addObject:touchedButton]; 172 | if ([self.selectedButtons count] == 1) { 173 | //If the touched button is the first button in the selected buttons, 174 | //It's the beginning of the passcode creation 175 | if (_delegateFlags.didBeginWithPasscode) { 176 | [self.delegate gestureLockView:self didBeginWithPasscode:[NSString stringWithFormat:@"%d",touchedButton.tag]]; 177 | } 178 | } 179 | } 180 | self.trackedLocationInContentView = locationInContentView; 181 | [self setNeedsDisplay]; 182 | } 183 | } 184 | 185 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ 186 | if ([self.selectedButtons count] > 0) { 187 | if (_delegateFlags.didEndWithPasscode) { 188 | NSMutableArray *passcodeArray = [NSMutableArray array]; 189 | for (UIButton *button in self.selectedButtons) { 190 | [passcodeArray addObject:[NSString stringWithFormat:@"%d",button.tag]]; 191 | } 192 | 193 | [self.delegate gestureLockView:self didEndWithPasscode:[passcodeArray componentsJoinedByString:@","]]; 194 | } 195 | } 196 | 197 | for (UIButton *button in self.selectedButtons) { 198 | button.selected = NO; 199 | } 200 | [self.selectedButtons removeAllObjects]; 201 | self.trackedLocationInContentView = CGPointMake(kTrackedLocationInvalidInContentView, kTrackedLocationInvalidInContentView); 202 | [self setNeedsDisplay]; 203 | 204 | 205 | } 206 | 207 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{ 208 | if ([self.selectedButtons count] > 0) { 209 | if (_delegateFlags.didCanceled) { 210 | NSMutableArray *passcodeArray = [NSMutableArray array]; 211 | for (UIButton *button in self.selectedButtons) { 212 | [passcodeArray addObject:[NSString stringWithFormat:@"%d",button.tag]]; 213 | } 214 | 215 | [self.delegate gestureLockView:self didCanceledWithPasscode:[passcodeArray componentsJoinedByString:@","]]; 216 | } 217 | } 218 | 219 | for (UIButton *button in self.selectedButtons) { 220 | button.selected = NO; 221 | } 222 | [self.selectedButtons removeAllObjects]; 223 | self.trackedLocationInContentView = CGPointMake(kTrackedLocationInvalidInContentView, kTrackedLocationInvalidInContentView); 224 | [self setNeedsDisplay]; 225 | } 226 | 227 | #pragma mark - 228 | #pragma mark Accessors 229 | - (void)setNormalGestureNodeImage:(UIImage *)normalGestureNodeImage{ 230 | if (_normalGestureNodeImage != normalGestureNodeImage) { 231 | _normalGestureNodeImage = normalGestureNodeImage; 232 | CGSize buttonSize = self.buttonSize; 233 | buttonSize.width = self.buttonSize.width > normalGestureNodeImage.size.width ? self.buttonSize.width : normalGestureNodeImage.size.width; 234 | buttonSize.height = self.buttonSize.height > normalGestureNodeImage.size.height ? self.buttonSize.height : normalGestureNodeImage.size.height; 235 | self.buttonSize = buttonSize; 236 | 237 | if (self.buttons != nil && [self.buttons count] > 0) { 238 | for (UIButton *button in self.buttons) { 239 | [button setImage:normalGestureNodeImage forState:UIControlStateNormal]; 240 | } 241 | } 242 | } 243 | } 244 | 245 | - (void)setSelectedGestureNodeImage:(UIImage *)selectedGestureNodeImage{ 246 | if (_selectedGestureNodeImage != selectedGestureNodeImage) { 247 | _selectedGestureNodeImage = selectedGestureNodeImage; 248 | 249 | CGSize buttonSize = self.buttonSize; 250 | buttonSize.width = self.buttonSize.width > selectedGestureNodeImage.size.width ? self.buttonSize.width : selectedGestureNodeImage.size.width; 251 | buttonSize.height = self.buttonSize.height > selectedGestureNodeImage.size.height ? self.buttonSize.height : selectedGestureNodeImage.size.height; 252 | self.buttonSize = buttonSize; 253 | 254 | if (self.buttons != nil && [self.buttons count] > 0) { 255 | for (UIButton *button in self.buttons) { 256 | [button setImage:selectedGestureNodeImage forState:UIControlStateSelected]; 257 | } 258 | } 259 | } 260 | } 261 | 262 | - (void)setDelegate:(id)delegate{ 263 | _delegate = delegate; 264 | 265 | _delegateFlags.didBeginWithPasscode = [delegate respondsToSelector:@selector(gestureLockView:didBeginWithPasscode:)]; 266 | _delegateFlags.didEndWithPasscode = [delegate respondsToSelector:@selector(gestureLockView:didEndWithPasscode:)]; 267 | _delegateFlags.didCanceled = [delegate respondsToSelector:@selector(gestureLockViewCanceled:)]; 268 | } 269 | 270 | - (void)setNumberOfGestureNodes:(NSUInteger)numberOfGestureNodes{ 271 | if (_numberOfGestureNodes != numberOfGestureNodes) { 272 | _numberOfGestureNodes = numberOfGestureNodes; 273 | 274 | if (self.buttons != nil && [self.buttons count] > 0) { 275 | for (UIButton *button in self.buttons) { 276 | [button removeFromSuperview]; 277 | } 278 | } 279 | 280 | NSMutableArray *buttonArray = [NSMutableArray arrayWithCapacity:numberOfGestureNodes]; 281 | for (NSUInteger i = 0; i < numberOfGestureNodes; i++) { 282 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 283 | button.tag = i; 284 | button.userInteractionEnabled = NO; 285 | button.frame = CGRectMake(0, 0, self.buttonSize.width, self.buttonSize.height); 286 | button.backgroundColor = [UIColor clearColor]; 287 | if (self.normalGestureNodeImage != nil) { 288 | [button setImage:self.normalGestureNodeImage forState:UIControlStateNormal]; 289 | } 290 | 291 | if (self.selectedGestureNodeImage != nil) { 292 | [button setImage:self.selectedGestureNodeImage forState:UIControlStateSelected]; 293 | } 294 | 295 | [buttonArray addObject:button]; 296 | [self.contentView addSubview:button]; 297 | } 298 | self.buttons = [buttonArray copy]; 299 | } 300 | } 301 | @end 302 | -------------------------------------------------------------------------------- /KKGestureLockView/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /KKGestureLockView/en.lproj/KKViewController.xib: -------------------------------------------------------------------------------- 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 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /KKGestureLockView/gesture_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/KKGestureLockView/gesture_background.png -------------------------------------------------------------------------------- /KKGestureLockView/gesture_node_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/KKGestureLockView/gesture_node_normal.png -------------------------------------------------------------------------------- /KKGestureLockView/gesture_node_normal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/KKGestureLockView/gesture_node_normal@2x.png -------------------------------------------------------------------------------- /KKGestureLockView/gesture_node_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/KKGestureLockView/gesture_node_selected.png -------------------------------------------------------------------------------- /KKGestureLockView/gesture_node_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/KKGestureLockView/gesture_node_selected@2x.png -------------------------------------------------------------------------------- /KKGestureLockView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // KKGestureLockView 4 | // 5 | // Created by Luke on 8/5/13. 6 | // Copyright (c) 2013 geeklu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "KKAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([KKAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | KKGestureLockView是一个非常方便使用的Gesture Lock控件,只需要简单的几步便可以在你的app中实现如安卓那样的手势解锁的效果。其实之前并不看好这种解锁的方式,不过上次发现支付宝iOS新版app中使用了这样的形式来进行功能的解锁,觉得也还方便。此控件有几个概念先说明一下: 3 | 4 | 5 | 6 | * 在控件中,每一个节点叫做一个gesture node,当手势经过某个节点的时候,那么这个节点便进入选中状态,成为最终passcode序列中的一部分 7 | * 每一个节点可以有两种状态,一种是普通状态,一种是选中状态,可以分别为这两种状态设置节点的图片:`normalGestureNodeImage`和`selectedGestureNodeImage` 8 | * 连线也是可以自定义的,可以通过`lineColor`和`lineWidth`来设置连线的颜色和宽度 9 | * 节点所在的容器称之为`contentView`,contentView到KKGestureLockView的四边距离使用`contentInsets`来描述,手势在KKGestureLockView的区域内是不会被结束的,但是Line连线的绘制只会在contentView的区域内 10 | * 节点的个数以及每行的节点数都是可以自定义的,分别通过`numberOfGestureNodes`和`gestureNodesPerRow`进行设置;每一个节点按照从左到右从上到下的方式进行编号,编号从0开始;为了支持多于10个节点的情况,所以passcode并没有使用节点序号直接串联,而是使用半角逗号分隔所有选中节点的序号, 比如上图中的passcode即为 `0,1,4` 11 | * 提供了三个delegate方法,用于通知delegate相关的事件 12 | 13 | 14 | ##用法 15 | 控件的源码在`KKGestureLockView/Source`目录下,且自带了一个仿支付宝解锁界面的例子(例子的图片资源取自支付宝app解压缩后的资源图片): 16 | 17 | self.lockView.normalGestureNodeImage = [UIImage imageNamed:@"gesture_node_normal.png"]; 18 | self.lockView.selectedGestureNodeImage = [UIImage imageNamed:@"gesture_node_selected.png"]; 19 | self.lockView.lineColor = [[UIColor orangeColor] colorWithAlphaComponent:0.3]; 20 | self.lockView.lineWidth = 12; 21 | self.lockView.delegate = self; 22 | self.lockView.contentInsets = UIEdgeInsetsMake(150, 20, 100, 20); 23 | 24 | 25 | 26 | 一般情况下9个节点便够用了,当然如果你想多弄些节点也不是不可以: 27 | 28 | -------------------------------------------------------------------------------- /pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/pic.png -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/screenshot.png -------------------------------------------------------------------------------- /screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kejinlu/KKGestureLockView/a76b4e0e91ea0df50962ed43c9ff2bf6f124b82d/screenshot2.png --------------------------------------------------------------------------------