├── PCGestureUnlock.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── PCGestureUnlock.xccheckout │ └── xcuserdata │ │ ├── PanC.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── suhe1.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── PanC.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── PCGestureUnlock.xcscheme │ │ └── xcschememanagement.plist │ └── suhe1.xcuserdatad │ └── xcschemes │ ├── PCGestureUnlock.xcscheme │ └── xcschememanagement.plist ├── PCGestureUnlock ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── Controller │ ├── GestureVerifyViewController.h │ ├── GestureVerifyViewController.m │ ├── GestureViewController.h │ ├── GestureViewController.m │ ├── HomeViewController.h │ └── HomeViewController.m ├── ErrorDisplay.gif ├── FrameWork │ ├── PCCircle.h │ ├── PCCircle.m │ ├── PCCircleView.h │ ├── PCCircleView.m │ ├── PCCircleViewConst.h │ └── PCCircleViewConst.m ├── Gategory │ ├── CALayer+Anim.h │ └── CALayer+Anim.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── head.imageset │ │ ├── Contents.json │ │ └── head@3x.png │ └── head@3x.png ├── Info.plist ├── JumpConnect.gif ├── View │ ├── PCCircleInfoView.h │ ├── PCCircleInfoView.m │ ├── PCLockLabel.h │ └── PCLockLabel.m ├── arrowDirctions.gif ├── main.m └── settingGesture.gif ├── PCGestureUnlockTests ├── Info.plist └── PCGestureUnlockTests.m └── README.md /PCGestureUnlock.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3AB26F3C1EFA0C38005F6EF8 /* HomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AB26F3B1EFA0C38005F6EF8 /* HomeViewController.m */; }; 11 | 3ABFF5B01B288D75008190C6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5AF1B288D75008190C6 /* main.m */; }; 12 | 3ABFF5B31B288D75008190C6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5B21B288D75008190C6 /* AppDelegate.m */; }; 13 | 3ABFF5BB1B288D75008190C6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3ABFF5BA1B288D75008190C6 /* Images.xcassets */; }; 14 | 3ABFF5BE1B288D75008190C6 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3ABFF5BC1B288D75008190C6 /* LaunchScreen.xib */; }; 15 | 3ABFF5CA1B288D75008190C6 /* PCGestureUnlockTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5C91B288D75008190C6 /* PCGestureUnlockTests.m */; }; 16 | 3ABFF5E71B288F54008190C6 /* GestureVerifyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5D51B288F54008190C6 /* GestureVerifyViewController.m */; }; 17 | 3ABFF5E81B288F54008190C6 /* GestureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5D71B288F54008190C6 /* GestureViewController.m */; }; 18 | 3ABFF5EA1B288F54008190C6 /* PCCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5DC1B288F54008190C6 /* PCCircle.m */; }; 19 | 3ABFF5EB1B288F54008190C6 /* PCCircleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5DE1B288F54008190C6 /* PCCircleView.m */; }; 20 | 3ABFF5EC1B288F54008190C6 /* PCCircleViewConst.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5E01B288F54008190C6 /* PCCircleViewConst.m */; }; 21 | 3ABFF5ED1B288F54008190C6 /* CALayer+Anim.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5E31B288F54008190C6 /* CALayer+Anim.m */; }; 22 | 3ABFF5EE1B288F54008190C6 /* PCLockLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5E61B288F54008190C6 /* PCLockLabel.m */; }; 23 | 3ABFF5F11B288F80008190C6 /* PCCircleInfoView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ABFF5F01B288F80008190C6 /* PCCircleInfoView.m */; }; 24 | 3ABFF5F41B288FBE008190C6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3ABFF5F21B288FBE008190C6 /* Main.storyboard */; }; 25 | 3AE570F41B2DE18F008B3CBD /* arrowDirctions.gif in Resources */ = {isa = PBXBuildFile; fileRef = 3AE570F01B2DE18F008B3CBD /* arrowDirctions.gif */; }; 26 | 3AE570F51B2DE18F008B3CBD /* ErrorDisplay.gif in Resources */ = {isa = PBXBuildFile; fileRef = 3AE570F11B2DE18F008B3CBD /* ErrorDisplay.gif */; }; 27 | 3AE570F61B2DE18F008B3CBD /* JumpConnect.gif in Resources */ = {isa = PBXBuildFile; fileRef = 3AE570F21B2DE18F008B3CBD /* JumpConnect.gif */; }; 28 | 3AE570F71B2DE18F008B3CBD /* settingGesture.gif in Resources */ = {isa = PBXBuildFile; fileRef = 3AE570F31B2DE18F008B3CBD /* settingGesture.gif */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 3ABFF5C41B288D75008190C6 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 3ABFF5A21B288D75008190C6 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 3ABFF5A91B288D75008190C6; 37 | remoteInfo = PCGestureUnlock; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 3AB26F3A1EFA0C38005F6EF8 /* HomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeViewController.h; sourceTree = ""; }; 43 | 3AB26F3B1EFA0C38005F6EF8 /* HomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeViewController.m; sourceTree = ""; }; 44 | 3ABFF5AA1B288D75008190C6 /* PCGestureUnlock.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PCGestureUnlock.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 3ABFF5AE1B288D75008190C6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | 3ABFF5AF1B288D75008190C6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 3ABFF5B11B288D75008190C6 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 3ABFF5B21B288D75008190C6 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 3ABFF5BA1B288D75008190C6 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 50 | 3ABFF5BD1B288D75008190C6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 51 | 3ABFF5C31B288D75008190C6 /* PCGestureUnlockTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PCGestureUnlockTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 3ABFF5C81B288D75008190C6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | 3ABFF5C91B288D75008190C6 /* PCGestureUnlockTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PCGestureUnlockTests.m; sourceTree = ""; }; 54 | 3ABFF5D41B288F54008190C6 /* GestureVerifyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GestureVerifyViewController.h; sourceTree = ""; }; 55 | 3ABFF5D51B288F54008190C6 /* GestureVerifyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GestureVerifyViewController.m; sourceTree = ""; }; 56 | 3ABFF5D61B288F54008190C6 /* GestureViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GestureViewController.h; sourceTree = ""; }; 57 | 3ABFF5D71B288F54008190C6 /* GestureViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GestureViewController.m; sourceTree = ""; }; 58 | 3ABFF5DB1B288F54008190C6 /* PCCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCCircle.h; sourceTree = ""; }; 59 | 3ABFF5DC1B288F54008190C6 /* PCCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCCircle.m; sourceTree = ""; }; 60 | 3ABFF5DD1B288F54008190C6 /* PCCircleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCCircleView.h; sourceTree = ""; }; 61 | 3ABFF5DE1B288F54008190C6 /* PCCircleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCCircleView.m; sourceTree = ""; }; 62 | 3ABFF5DF1B288F54008190C6 /* PCCircleViewConst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCCircleViewConst.h; sourceTree = ""; }; 63 | 3ABFF5E01B288F54008190C6 /* PCCircleViewConst.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCCircleViewConst.m; sourceTree = ""; }; 64 | 3ABFF5E21B288F54008190C6 /* CALayer+Anim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CALayer+Anim.h"; sourceTree = ""; }; 65 | 3ABFF5E31B288F54008190C6 /* CALayer+Anim.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CALayer+Anim.m"; sourceTree = ""; }; 66 | 3ABFF5E51B288F54008190C6 /* PCLockLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCLockLabel.h; sourceTree = ""; }; 67 | 3ABFF5E61B288F54008190C6 /* PCLockLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCLockLabel.m; sourceTree = ""; }; 68 | 3ABFF5EF1B288F80008190C6 /* PCCircleInfoView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCCircleInfoView.h; sourceTree = ""; }; 69 | 3ABFF5F01B288F80008190C6 /* PCCircleInfoView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCCircleInfoView.m; sourceTree = ""; }; 70 | 3ABFF5F31B288FBE008190C6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 71 | 3AE570F01B2DE18F008B3CBD /* arrowDirctions.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = arrowDirctions.gif; sourceTree = ""; }; 72 | 3AE570F11B2DE18F008B3CBD /* ErrorDisplay.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = ErrorDisplay.gif; sourceTree = ""; }; 73 | 3AE570F21B2DE18F008B3CBD /* JumpConnect.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = JumpConnect.gif; sourceTree = ""; }; 74 | 3AE570F31B2DE18F008B3CBD /* settingGesture.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = settingGesture.gif; sourceTree = ""; }; 75 | /* End PBXFileReference section */ 76 | 77 | /* Begin PBXFrameworksBuildPhase section */ 78 | 3ABFF5A71B288D75008190C6 /* Frameworks */ = { 79 | isa = PBXFrameworksBuildPhase; 80 | buildActionMask = 2147483647; 81 | files = ( 82 | ); 83 | runOnlyForDeploymentPostprocessing = 0; 84 | }; 85 | 3ABFF5C01B288D75008190C6 /* Frameworks */ = { 86 | isa = PBXFrameworksBuildPhase; 87 | buildActionMask = 2147483647; 88 | files = ( 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | /* End PBXFrameworksBuildPhase section */ 93 | 94 | /* Begin PBXGroup section */ 95 | 3ABFF5A11B288D75008190C6 = { 96 | isa = PBXGroup; 97 | children = ( 98 | 3ABFF5AC1B288D75008190C6 /* PCGestureUnlock */, 99 | 3ABFF5C61B288D75008190C6 /* PCGestureUnlockTests */, 100 | 3ABFF5AB1B288D75008190C6 /* Products */, 101 | ); 102 | sourceTree = ""; 103 | }; 104 | 3ABFF5AB1B288D75008190C6 /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 3ABFF5AA1B288D75008190C6 /* PCGestureUnlock.app */, 108 | 3ABFF5C31B288D75008190C6 /* PCGestureUnlockTests.xctest */, 109 | ); 110 | name = Products; 111 | sourceTree = ""; 112 | }; 113 | 3ABFF5AC1B288D75008190C6 /* PCGestureUnlock */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 3ABFF5D31B288F54008190C6 /* Controller */, 117 | 3ABFF5DA1B288F54008190C6 /* FrameWork */, 118 | 3ABFF5E11B288F54008190C6 /* Gategory */, 119 | 3ABFF5E41B288F54008190C6 /* View */, 120 | 3ABFF5B11B288D75008190C6 /* AppDelegate.h */, 121 | 3ABFF5B21B288D75008190C6 /* AppDelegate.m */, 122 | 3ABFF5BA1B288D75008190C6 /* Images.xcassets */, 123 | 3ABFF5BC1B288D75008190C6 /* LaunchScreen.xib */, 124 | 3ABFF5F21B288FBE008190C6 /* Main.storyboard */, 125 | 3ABFF5AD1B288D75008190C6 /* Supporting Files */, 126 | ); 127 | path = PCGestureUnlock; 128 | sourceTree = ""; 129 | }; 130 | 3ABFF5AD1B288D75008190C6 /* Supporting Files */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 3AE570F01B2DE18F008B3CBD /* arrowDirctions.gif */, 134 | 3AE570F11B2DE18F008B3CBD /* ErrorDisplay.gif */, 135 | 3AE570F21B2DE18F008B3CBD /* JumpConnect.gif */, 136 | 3AE570F31B2DE18F008B3CBD /* settingGesture.gif */, 137 | 3ABFF5AE1B288D75008190C6 /* Info.plist */, 138 | 3ABFF5AF1B288D75008190C6 /* main.m */, 139 | ); 140 | name = "Supporting Files"; 141 | sourceTree = ""; 142 | }; 143 | 3ABFF5C61B288D75008190C6 /* PCGestureUnlockTests */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 3ABFF5C91B288D75008190C6 /* PCGestureUnlockTests.m */, 147 | 3ABFF5C71B288D75008190C6 /* Supporting Files */, 148 | ); 149 | path = PCGestureUnlockTests; 150 | sourceTree = ""; 151 | }; 152 | 3ABFF5C71B288D75008190C6 /* Supporting Files */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 3ABFF5C81B288D75008190C6 /* Info.plist */, 156 | ); 157 | name = "Supporting Files"; 158 | sourceTree = ""; 159 | }; 160 | 3ABFF5D31B288F54008190C6 /* Controller */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 3ABFF5D41B288F54008190C6 /* GestureVerifyViewController.h */, 164 | 3ABFF5D51B288F54008190C6 /* GestureVerifyViewController.m */, 165 | 3ABFF5D61B288F54008190C6 /* GestureViewController.h */, 166 | 3ABFF5D71B288F54008190C6 /* GestureViewController.m */, 167 | 3AB26F3A1EFA0C38005F6EF8 /* HomeViewController.h */, 168 | 3AB26F3B1EFA0C38005F6EF8 /* HomeViewController.m */, 169 | ); 170 | path = Controller; 171 | sourceTree = ""; 172 | }; 173 | 3ABFF5DA1B288F54008190C6 /* FrameWork */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | 3ABFF5DB1B288F54008190C6 /* PCCircle.h */, 177 | 3ABFF5DC1B288F54008190C6 /* PCCircle.m */, 178 | 3ABFF5DD1B288F54008190C6 /* PCCircleView.h */, 179 | 3ABFF5DE1B288F54008190C6 /* PCCircleView.m */, 180 | 3ABFF5DF1B288F54008190C6 /* PCCircleViewConst.h */, 181 | 3ABFF5E01B288F54008190C6 /* PCCircleViewConst.m */, 182 | ); 183 | path = FrameWork; 184 | sourceTree = ""; 185 | }; 186 | 3ABFF5E11B288F54008190C6 /* Gategory */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | 3ABFF5E21B288F54008190C6 /* CALayer+Anim.h */, 190 | 3ABFF5E31B288F54008190C6 /* CALayer+Anim.m */, 191 | ); 192 | path = Gategory; 193 | sourceTree = ""; 194 | }; 195 | 3ABFF5E41B288F54008190C6 /* View */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 3ABFF5EF1B288F80008190C6 /* PCCircleInfoView.h */, 199 | 3ABFF5F01B288F80008190C6 /* PCCircleInfoView.m */, 200 | 3ABFF5E51B288F54008190C6 /* PCLockLabel.h */, 201 | 3ABFF5E61B288F54008190C6 /* PCLockLabel.m */, 202 | ); 203 | path = View; 204 | sourceTree = ""; 205 | }; 206 | /* End PBXGroup section */ 207 | 208 | /* Begin PBXNativeTarget section */ 209 | 3ABFF5A91B288D75008190C6 /* PCGestureUnlock */ = { 210 | isa = PBXNativeTarget; 211 | buildConfigurationList = 3ABFF5CD1B288D75008190C6 /* Build configuration list for PBXNativeTarget "PCGestureUnlock" */; 212 | buildPhases = ( 213 | 3ABFF5A61B288D75008190C6 /* Sources */, 214 | 3ABFF5A71B288D75008190C6 /* Frameworks */, 215 | 3ABFF5A81B288D75008190C6 /* Resources */, 216 | ); 217 | buildRules = ( 218 | ); 219 | dependencies = ( 220 | ); 221 | name = PCGestureUnlock; 222 | productName = PCGestureUnlock; 223 | productReference = 3ABFF5AA1B288D75008190C6 /* PCGestureUnlock.app */; 224 | productType = "com.apple.product-type.application"; 225 | }; 226 | 3ABFF5C21B288D75008190C6 /* PCGestureUnlockTests */ = { 227 | isa = PBXNativeTarget; 228 | buildConfigurationList = 3ABFF5D01B288D75008190C6 /* Build configuration list for PBXNativeTarget "PCGestureUnlockTests" */; 229 | buildPhases = ( 230 | 3ABFF5BF1B288D75008190C6 /* Sources */, 231 | 3ABFF5C01B288D75008190C6 /* Frameworks */, 232 | 3ABFF5C11B288D75008190C6 /* Resources */, 233 | ); 234 | buildRules = ( 235 | ); 236 | dependencies = ( 237 | 3ABFF5C51B288D75008190C6 /* PBXTargetDependency */, 238 | ); 239 | name = PCGestureUnlockTests; 240 | productName = PCGestureUnlockTests; 241 | productReference = 3ABFF5C31B288D75008190C6 /* PCGestureUnlockTests.xctest */; 242 | productType = "com.apple.product-type.bundle.unit-test"; 243 | }; 244 | /* End PBXNativeTarget section */ 245 | 246 | /* Begin PBXProject section */ 247 | 3ABFF5A21B288D75008190C6 /* Project object */ = { 248 | isa = PBXProject; 249 | attributes = { 250 | LastUpgradeCheck = 0830; 251 | ORGANIZATIONNAME = coderMonkey; 252 | TargetAttributes = { 253 | 3ABFF5A91B288D75008190C6 = { 254 | CreatedOnToolsVersion = 6.2; 255 | DevelopmentTeam = BGV8643Z67; 256 | }; 257 | 3ABFF5C21B288D75008190C6 = { 258 | CreatedOnToolsVersion = 6.2; 259 | TestTargetID = 3ABFF5A91B288D75008190C6; 260 | }; 261 | }; 262 | }; 263 | buildConfigurationList = 3ABFF5A51B288D75008190C6 /* Build configuration list for PBXProject "PCGestureUnlock" */; 264 | compatibilityVersion = "Xcode 3.2"; 265 | developmentRegion = English; 266 | hasScannedForEncodings = 0; 267 | knownRegions = ( 268 | en, 269 | Base, 270 | ); 271 | mainGroup = 3ABFF5A11B288D75008190C6; 272 | productRefGroup = 3ABFF5AB1B288D75008190C6 /* Products */; 273 | projectDirPath = ""; 274 | projectRoot = ""; 275 | targets = ( 276 | 3ABFF5A91B288D75008190C6 /* PCGestureUnlock */, 277 | 3ABFF5C21B288D75008190C6 /* PCGestureUnlockTests */, 278 | ); 279 | }; 280 | /* End PBXProject section */ 281 | 282 | /* Begin PBXResourcesBuildPhase section */ 283 | 3ABFF5A81B288D75008190C6 /* Resources */ = { 284 | isa = PBXResourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | 3AE570F41B2DE18F008B3CBD /* arrowDirctions.gif in Resources */, 288 | 3ABFF5F41B288FBE008190C6 /* Main.storyboard in Resources */, 289 | 3ABFF5BE1B288D75008190C6 /* LaunchScreen.xib in Resources */, 290 | 3AE570F61B2DE18F008B3CBD /* JumpConnect.gif in Resources */, 291 | 3ABFF5BB1B288D75008190C6 /* Images.xcassets in Resources */, 292 | 3AE570F71B2DE18F008B3CBD /* settingGesture.gif in Resources */, 293 | 3AE570F51B2DE18F008B3CBD /* ErrorDisplay.gif in Resources */, 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | 3ABFF5C11B288D75008190C6 /* Resources */ = { 298 | isa = PBXResourcesBuildPhase; 299 | buildActionMask = 2147483647; 300 | files = ( 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | /* End PBXResourcesBuildPhase section */ 305 | 306 | /* Begin PBXSourcesBuildPhase section */ 307 | 3ABFF5A61B288D75008190C6 /* Sources */ = { 308 | isa = PBXSourcesBuildPhase; 309 | buildActionMask = 2147483647; 310 | files = ( 311 | 3ABFF5E81B288F54008190C6 /* GestureViewController.m in Sources */, 312 | 3ABFF5E71B288F54008190C6 /* GestureVerifyViewController.m in Sources */, 313 | 3ABFF5EE1B288F54008190C6 /* PCLockLabel.m in Sources */, 314 | 3ABFF5B31B288D75008190C6 /* AppDelegate.m in Sources */, 315 | 3ABFF5B01B288D75008190C6 /* main.m in Sources */, 316 | 3ABFF5EB1B288F54008190C6 /* PCCircleView.m in Sources */, 317 | 3ABFF5F11B288F80008190C6 /* PCCircleInfoView.m in Sources */, 318 | 3ABFF5EC1B288F54008190C6 /* PCCircleViewConst.m in Sources */, 319 | 3ABFF5ED1B288F54008190C6 /* CALayer+Anim.m in Sources */, 320 | 3ABFF5EA1B288F54008190C6 /* PCCircle.m in Sources */, 321 | 3AB26F3C1EFA0C38005F6EF8 /* HomeViewController.m in Sources */, 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | }; 325 | 3ABFF5BF1B288D75008190C6 /* Sources */ = { 326 | isa = PBXSourcesBuildPhase; 327 | buildActionMask = 2147483647; 328 | files = ( 329 | 3ABFF5CA1B288D75008190C6 /* PCGestureUnlockTests.m in Sources */, 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | }; 333 | /* End PBXSourcesBuildPhase section */ 334 | 335 | /* Begin PBXTargetDependency section */ 336 | 3ABFF5C51B288D75008190C6 /* PBXTargetDependency */ = { 337 | isa = PBXTargetDependency; 338 | target = 3ABFF5A91B288D75008190C6 /* PCGestureUnlock */; 339 | targetProxy = 3ABFF5C41B288D75008190C6 /* PBXContainerItemProxy */; 340 | }; 341 | /* End PBXTargetDependency section */ 342 | 343 | /* Begin PBXVariantGroup section */ 344 | 3ABFF5BC1B288D75008190C6 /* LaunchScreen.xib */ = { 345 | isa = PBXVariantGroup; 346 | children = ( 347 | 3ABFF5BD1B288D75008190C6 /* Base */, 348 | ); 349 | name = LaunchScreen.xib; 350 | sourceTree = ""; 351 | }; 352 | 3ABFF5F21B288FBE008190C6 /* Main.storyboard */ = { 353 | isa = PBXVariantGroup; 354 | children = ( 355 | 3ABFF5F31B288FBE008190C6 /* Base */, 356 | ); 357 | name = Main.storyboard; 358 | sourceTree = ""; 359 | }; 360 | /* End PBXVariantGroup section */ 361 | 362 | /* Begin XCBuildConfiguration section */ 363 | 3ABFF5CB1B288D75008190C6 /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ALWAYS_SEARCH_USER_PATHS = NO; 367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 368 | CLANG_CXX_LIBRARY = "libc++"; 369 | CLANG_ENABLE_MODULES = YES; 370 | CLANG_ENABLE_OBJC_ARC = YES; 371 | CLANG_WARN_BOOL_CONVERSION = YES; 372 | CLANG_WARN_CONSTANT_CONVERSION = YES; 373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 374 | CLANG_WARN_EMPTY_BODY = YES; 375 | CLANG_WARN_ENUM_CONVERSION = YES; 376 | CLANG_WARN_INFINITE_RECURSION = YES; 377 | CLANG_WARN_INT_CONVERSION = YES; 378 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 379 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 380 | CLANG_WARN_UNREACHABLE_CODE = YES; 381 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 382 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 383 | COPY_PHASE_STRIP = NO; 384 | ENABLE_STRICT_OBJC_MSGSEND = YES; 385 | ENABLE_TESTABILITY = YES; 386 | GCC_C_LANGUAGE_STANDARD = gnu99; 387 | GCC_DYNAMIC_NO_PIC = NO; 388 | GCC_NO_COMMON_BLOCKS = YES; 389 | GCC_OPTIMIZATION_LEVEL = 0; 390 | GCC_PREPROCESSOR_DEFINITIONS = ( 391 | "DEBUG=1", 392 | "$(inherited)", 393 | ); 394 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 397 | GCC_WARN_UNDECLARED_SELECTOR = YES; 398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 399 | GCC_WARN_UNUSED_FUNCTION = YES; 400 | GCC_WARN_UNUSED_VARIABLE = YES; 401 | IPHONEOS_DEPLOYMENT_TARGET = 8.2; 402 | MTL_ENABLE_DEBUG_INFO = YES; 403 | ONLY_ACTIVE_ARCH = YES; 404 | SDKROOT = iphoneos; 405 | }; 406 | name = Debug; 407 | }; 408 | 3ABFF5CC1B288D75008190C6 /* Release */ = { 409 | isa = XCBuildConfiguration; 410 | buildSettings = { 411 | ALWAYS_SEARCH_USER_PATHS = NO; 412 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 413 | CLANG_CXX_LIBRARY = "libc++"; 414 | CLANG_ENABLE_MODULES = YES; 415 | CLANG_ENABLE_OBJC_ARC = YES; 416 | CLANG_WARN_BOOL_CONVERSION = YES; 417 | CLANG_WARN_CONSTANT_CONVERSION = YES; 418 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 419 | CLANG_WARN_EMPTY_BODY = YES; 420 | CLANG_WARN_ENUM_CONVERSION = YES; 421 | CLANG_WARN_INFINITE_RECURSION = YES; 422 | CLANG_WARN_INT_CONVERSION = YES; 423 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 424 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 425 | CLANG_WARN_UNREACHABLE_CODE = YES; 426 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 427 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 428 | COPY_PHASE_STRIP = NO; 429 | ENABLE_NS_ASSERTIONS = NO; 430 | ENABLE_STRICT_OBJC_MSGSEND = YES; 431 | GCC_C_LANGUAGE_STANDARD = gnu99; 432 | GCC_NO_COMMON_BLOCKS = YES; 433 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 434 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 435 | GCC_WARN_UNDECLARED_SELECTOR = YES; 436 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 437 | GCC_WARN_UNUSED_FUNCTION = YES; 438 | GCC_WARN_UNUSED_VARIABLE = YES; 439 | IPHONEOS_DEPLOYMENT_TARGET = 8.2; 440 | MTL_ENABLE_DEBUG_INFO = NO; 441 | SDKROOT = iphoneos; 442 | VALIDATE_PRODUCT = YES; 443 | }; 444 | name = Release; 445 | }; 446 | 3ABFF5CE1B288D75008190C6 /* Debug */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 450 | DEVELOPMENT_TEAM = BGV8643Z67; 451 | INFOPLIST_FILE = PCGestureUnlock/Info.plist; 452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 453 | PRODUCT_BUNDLE_IDENTIFIER = com.coderMonkey.PCGestureUnlock.test; 454 | PRODUCT_NAME = "$(TARGET_NAME)"; 455 | }; 456 | name = Debug; 457 | }; 458 | 3ABFF5CF1B288D75008190C6 /* Release */ = { 459 | isa = XCBuildConfiguration; 460 | buildSettings = { 461 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 462 | DEVELOPMENT_TEAM = BGV8643Z67; 463 | INFOPLIST_FILE = PCGestureUnlock/Info.plist; 464 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 465 | PRODUCT_BUNDLE_IDENTIFIER = com.coderMonkey.PCGestureUnlock.test; 466 | PRODUCT_NAME = "$(TARGET_NAME)"; 467 | }; 468 | name = Release; 469 | }; 470 | 3ABFF5D11B288D75008190C6 /* Debug */ = { 471 | isa = XCBuildConfiguration; 472 | buildSettings = { 473 | BUNDLE_LOADER = "$(TEST_HOST)"; 474 | FRAMEWORK_SEARCH_PATHS = ( 475 | "$(SDKROOT)/Developer/Library/Frameworks", 476 | "$(inherited)", 477 | ); 478 | GCC_PREPROCESSOR_DEFINITIONS = ( 479 | "DEBUG=1", 480 | "$(inherited)", 481 | ); 482 | INFOPLIST_FILE = PCGestureUnlockTests/Info.plist; 483 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 484 | PRODUCT_BUNDLE_IDENTIFIER = "com.coderMonkey.$(PRODUCT_NAME:rfc1034identifier)"; 485 | PRODUCT_NAME = "$(TARGET_NAME)"; 486 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PCGestureUnlock.app/PCGestureUnlock"; 487 | }; 488 | name = Debug; 489 | }; 490 | 3ABFF5D21B288D75008190C6 /* Release */ = { 491 | isa = XCBuildConfiguration; 492 | buildSettings = { 493 | BUNDLE_LOADER = "$(TEST_HOST)"; 494 | FRAMEWORK_SEARCH_PATHS = ( 495 | "$(SDKROOT)/Developer/Library/Frameworks", 496 | "$(inherited)", 497 | ); 498 | INFOPLIST_FILE = PCGestureUnlockTests/Info.plist; 499 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 500 | PRODUCT_BUNDLE_IDENTIFIER = "com.coderMonkey.$(PRODUCT_NAME:rfc1034identifier)"; 501 | PRODUCT_NAME = "$(TARGET_NAME)"; 502 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PCGestureUnlock.app/PCGestureUnlock"; 503 | }; 504 | name = Release; 505 | }; 506 | /* End XCBuildConfiguration section */ 507 | 508 | /* Begin XCConfigurationList section */ 509 | 3ABFF5A51B288D75008190C6 /* Build configuration list for PBXProject "PCGestureUnlock" */ = { 510 | isa = XCConfigurationList; 511 | buildConfigurations = ( 512 | 3ABFF5CB1B288D75008190C6 /* Debug */, 513 | 3ABFF5CC1B288D75008190C6 /* Release */, 514 | ); 515 | defaultConfigurationIsVisible = 0; 516 | defaultConfigurationName = Release; 517 | }; 518 | 3ABFF5CD1B288D75008190C6 /* Build configuration list for PBXNativeTarget "PCGestureUnlock" */ = { 519 | isa = XCConfigurationList; 520 | buildConfigurations = ( 521 | 3ABFF5CE1B288D75008190C6 /* Debug */, 522 | 3ABFF5CF1B288D75008190C6 /* Release */, 523 | ); 524 | defaultConfigurationIsVisible = 0; 525 | defaultConfigurationName = Release; 526 | }; 527 | 3ABFF5D01B288D75008190C6 /* Build configuration list for PBXNativeTarget "PCGestureUnlockTests" */ = { 528 | isa = XCConfigurationList; 529 | buildConfigurations = ( 530 | 3ABFF5D11B288D75008190C6 /* Debug */, 531 | 3ABFF5D21B288D75008190C6 /* Release */, 532 | ); 533 | defaultConfigurationIsVisible = 0; 534 | defaultConfigurationName = Release; 535 | }; 536 | /* End XCConfigurationList section */ 537 | }; 538 | rootObject = 3ABFF5A21B288D75008190C6 /* Project object */; 539 | } 540 | -------------------------------------------------------------------------------- /PCGestureUnlock.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PCGestureUnlock.xcodeproj/project.xcworkspace/xcshareddata/PCGestureUnlock.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 0BED3AC3-4264-4A65-919C-961C84B08D8A 9 | IDESourceControlProjectName 10 | PCGestureUnlock 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 455E44A692076E6531DD10A439C3C057828D16DE 14 | https://github.com/iosdeveloperpanc/PCGestureUnlock.git 15 | 16 | IDESourceControlProjectPath 17 | PCGestureUnlock.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 455E44A692076E6531DD10A439C3C057828D16DE 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/iosdeveloperpanc/PCGestureUnlock.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 455E44A692076E6531DD10A439C3C057828D16DE 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 455E44A692076E6531DD10A439C3C057828D16DE 36 | IDESourceControlWCCName 37 | PCGestureUnlock 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /PCGestureUnlock.xcodeproj/project.xcworkspace/xcuserdata/PanC.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iosdeveloperpanc/PCGestureUnlock/666798b8095878b9824ab9351ca62075f1cd86e9/PCGestureUnlock.xcodeproj/project.xcworkspace/xcuserdata/PanC.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PCGestureUnlock.xcodeproj/project.xcworkspace/xcuserdata/suhe1.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iosdeveloperpanc/PCGestureUnlock/666798b8095878b9824ab9351ca62075f1cd86e9/PCGestureUnlock.xcodeproj/project.xcworkspace/xcuserdata/suhe1.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PCGestureUnlock.xcodeproj/xcuserdata/PanC.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /PCGestureUnlock.xcodeproj/xcuserdata/PanC.xcuserdatad/xcschemes/PCGestureUnlock.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /PCGestureUnlock.xcodeproj/xcuserdata/PanC.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PCGestureUnlock.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 3ABFF5A91B288D75008190C6 16 | 17 | primary 18 | 19 | 20 | 3ABFF5C21B288D75008190C6 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PCGestureUnlock.xcodeproj/xcuserdata/suhe1.xcuserdatad/xcschemes/PCGestureUnlock.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /PCGestureUnlock.xcodeproj/xcuserdata/suhe1.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PCGestureUnlock.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 3ABFF5A91B288D75008190C6 16 | 17 | primary 18 | 19 | 20 | 3ABFF5C21B288D75008190C6 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PCGestureUnlock/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PCGestureUnlock 4 | // 5 | // Created by panchao on 15/6/10. 6 | // Copyright (c) 2015年 coderMonkey. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /PCGestureUnlock/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PCGestureUnlock 4 | // 5 | // Created by panchao on 15/6/10. 6 | // Copyright (c) 2015年 coderMonkey. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /PCGestureUnlock/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /PCGestureUnlock/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /PCGestureUnlock/Controller/GestureVerifyViewController.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | @interface GestureVerifyViewController : UIViewController 5 | 6 | @property (nonatomic, assign) BOOL isToSetNewGesture; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /PCGestureUnlock/Controller/GestureVerifyViewController.m: -------------------------------------------------------------------------------- 1 | 2 | #import "GestureVerifyViewController.h" 3 | #import "PCCircleViewConst.h" 4 | #import "PCCircleView.h" 5 | #import "PCLockLabel.h" 6 | #import "GestureViewController.h" 7 | 8 | @interface GestureVerifyViewController () 9 | 10 | /** 11 | * 文字提示Label 12 | */ 13 | @property (nonatomic, strong) PCLockLabel *msgLabel; 14 | 15 | @end 16 | 17 | @implementation GestureVerifyViewController 18 | 19 | - (instancetype)init 20 | { 21 | self = [super init]; 22 | if (self) { 23 | [self.view setBackgroundColor:CircleViewBackgroundColor]; 24 | } 25 | return self; 26 | } 27 | 28 | - (void)viewDidLoad { 29 | [super viewDidLoad]; 30 | // Do any additional setup after loading the view. 31 | 32 | self.title = @"验证手势解锁"; 33 | 34 | PCCircleView *lockView = [[PCCircleView alloc] init]; 35 | lockView.delegate = self; 36 | [lockView setType:CircleViewTypeVerify]; 37 | [self.view addSubview:lockView]; 38 | 39 | PCLockLabel *msgLabel = [[PCLockLabel alloc] init]; 40 | msgLabel.frame = CGRectMake(0, 0, kScreenW, 14); 41 | msgLabel.center = CGPointMake(kScreenW/2, CGRectGetMinY(lockView.frame) - 30); 42 | [msgLabel showNormalMsg:gestureTextOldGesture]; 43 | self.msgLabel = msgLabel; 44 | [self.view addSubview:msgLabel]; 45 | } 46 | 47 | #pragma mark - login or verify gesture 48 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteLoginGesture:(NSString *)gesture result:(BOOL)equal 49 | { 50 | if (type == CircleViewTypeVerify) { 51 | 52 | if (equal) { 53 | NSLog(@"验证成功"); 54 | 55 | if (self.isToSetNewGesture) { 56 | GestureViewController *gestureVc = [[GestureViewController alloc] init]; 57 | [gestureVc setType:GestureViewControllerTypeSetting]; 58 | [self.navigationController pushViewController:gestureVc animated:YES]; 59 | } else { 60 | [self.navigationController popToRootViewControllerAnimated:YES]; 61 | } 62 | 63 | } else { 64 | NSLog(@"密码错误!"); 65 | [self.msgLabel showWarnMsgAndShake:gestureTextGestureVerifyError]; 66 | } 67 | } 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /PCGestureUnlock/Controller/GestureViewController.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | typedef enum{ 5 | GestureViewControllerTypeSetting = 1, 6 | GestureViewControllerTypeLogin 7 | }GestureViewControllerType; 8 | 9 | typedef enum{ 10 | buttonTagReset = 1, 11 | buttonTagManager, 12 | buttonTagForget 13 | 14 | }buttonTag; 15 | 16 | @interface GestureViewController : UIViewController 17 | 18 | /** 19 | * 控制器来源类型 20 | */ 21 | @property (nonatomic, assign) GestureViewControllerType type; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /PCGestureUnlock/Controller/GestureViewController.m: -------------------------------------------------------------------------------- 1 | 2 | #import "GestureViewController.h" 3 | #import "PCCircleView.h" 4 | #import "PCCircleViewConst.h" 5 | #import "PCLockLabel.h" 6 | #import "PCCircleInfoView.h" 7 | #import "PCCircle.h" 8 | 9 | @interface GestureViewController () 10 | 11 | /** 12 | * 提示Label 13 | */ 14 | @property (nonatomic, strong) PCLockLabel *msgLabel; 15 | 16 | /** 17 | * 解锁界面 18 | */ 19 | @property (nonatomic, strong) PCCircleView *lockView; 20 | 21 | /** 22 | * infoView 23 | */ 24 | @property (nonatomic, strong) PCCircleInfoView *infoView; 25 | 26 | @end 27 | 28 | @implementation GestureViewController 29 | 30 | - (void)viewWillAppear:(BOOL)animated 31 | { 32 | [super viewWillAppear:animated]; 33 | 34 | // 进来先清空存的第一个密码 35 | [PCCircleViewConst saveGesture:nil Key:gestureOneSaveKey]; 36 | } 37 | 38 | - (void)viewDidLoad { 39 | [super viewDidLoad]; 40 | // Do any additional setup after loading the view. 41 | 42 | [self.view setBackgroundColor:CircleViewBackgroundColor]; 43 | 44 | self.navigationController.delegate = self; 45 | 46 | // 1.界面相同部分生成器 47 | [self setupSameUI]; 48 | 49 | // 2.界面不同部分生成器 50 | [self setupDifferentUI]; 51 | } 52 | 53 | #pragma mark - 界面不同部分生成器 54 | - (void)setupDifferentUI 55 | { 56 | switch (self.type) { 57 | case GestureViewControllerTypeSetting: 58 | [self setupSubViewsSettingVc]; 59 | break; 60 | case GestureViewControllerTypeLogin: 61 | [self setupSubViewsLoginVc]; 62 | break; 63 | default: 64 | break; 65 | } 66 | } 67 | 68 | #pragma mark - 界面相同部分生成器 69 | - (void)setupSameUI 70 | { 71 | // 解锁界面 72 | PCCircleView *lockView = [[PCCircleView alloc] init]; 73 | lockView.delegate = self; 74 | self.lockView = lockView; 75 | [self.view addSubview:lockView]; 76 | 77 | PCLockLabel *msgLabel = [[PCLockLabel alloc] init]; 78 | msgLabel.frame = CGRectMake(0, 0, kScreenW, 14); 79 | msgLabel.center = CGPointMake(kScreenW/2, CGRectGetMinY(lockView.frame) - 30); 80 | self.msgLabel = msgLabel; 81 | [self.view addSubview:msgLabel]; 82 | } 83 | 84 | #pragma mark - 设置手势密码界面 85 | - (void)setupSubViewsSettingVc 86 | { 87 | [self.lockView setType:CircleViewTypeSetting]; 88 | 89 | self.title = @"设置手势密码"; 90 | 91 | [self.msgLabel showNormalMsg:gestureTextBeforeSet]; 92 | 93 | PCCircleInfoView *infoView = [[PCCircleInfoView alloc] init]; 94 | infoView.frame = CGRectMake(0, 0, CircleRadius * 2 * 0.6, CircleRadius * 2 * 0.6); 95 | infoView.center = CGPointMake(kScreenW/2, CGRectGetMinY(self.msgLabel.frame) - CGRectGetHeight(infoView.frame)/2 - 10); 96 | self.infoView = infoView; 97 | [self.view addSubview:infoView]; 98 | } 99 | 100 | #pragma mark - 登陆手势密码界面 101 | - (void)setupSubViewsLoginVc 102 | { 103 | [self.lockView setType:CircleViewTypeLogin]; 104 | 105 | // 头像 106 | UIImageView *imageView = [[UIImageView alloc] init]; 107 | imageView.frame = CGRectMake(0, 0, 65, 65); 108 | imageView.center = CGPointMake(kScreenW/2, kScreenH/5); 109 | [imageView setImage:[UIImage imageNamed:@"head"]]; 110 | [self.view addSubview:imageView]; 111 | 112 | // 管理手势密码 113 | UIButton *leftBtn = [UIButton new]; 114 | [self creatButton:leftBtn frame:CGRectMake(CircleViewEdgeMargin + 20, kScreenH - 60, kScreenW/2, 20) title:@"管理手势密码" alignment:UIControlContentHorizontalAlignmentLeft tag:buttonTagManager]; 115 | 116 | // 登录其他账户 117 | UIButton *rightBtn = [UIButton new]; 118 | [self creatButton:rightBtn frame:CGRectMake(kScreenW/2 - CircleViewEdgeMargin - 20, kScreenH - 60, kScreenW/2, 20) title:@"登陆其他账户" alignment:UIControlContentHorizontalAlignmentRight tag:buttonTagForget]; 119 | } 120 | 121 | #pragma mark - 创建UIButton 122 | - (void)creatButton:(UIButton *)btn frame:(CGRect)frame title:(NSString *)title alignment:(UIControlContentHorizontalAlignment)alignment tag:(NSInteger)tag 123 | { 124 | btn.frame = frame; 125 | btn.tag = tag; 126 | [btn setTitle:title forState:UIControlStateNormal]; 127 | [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 128 | [btn setContentHorizontalAlignment:alignment]; 129 | [btn.titleLabel setFont:[UIFont systemFontOfSize:14.0f]]; 130 | [btn addTarget:self action:@selector(didClickBtn:) forControlEvents:UIControlEventTouchUpInside]; 131 | [self.view addSubview:btn]; 132 | } 133 | 134 | - (void)didClickRightItem { 135 | NSLog(@"点击了重设按钮"); 136 | // 1.隐藏按钮 137 | self.navigationItem.rightBarButtonItem.title = nil; 138 | 139 | // 2.infoView取消选中 140 | [self infoViewDeselectedSubviews]; 141 | 142 | // 3.msgLabel提示文字复位 143 | [self.msgLabel showNormalMsg:gestureTextBeforeSet]; 144 | 145 | // 4.清除之前存储的密码 146 | [PCCircleViewConst saveGesture:nil Key:gestureOneSaveKey]; 147 | } 148 | 149 | #pragma mark - button点击事件 150 | - (void)didClickBtn:(UIButton *)sender 151 | { 152 | NSLog(@"%ld", (long)sender.tag); 153 | switch (sender.tag) { 154 | case buttonTagManager: 155 | { 156 | NSLog(@"点击了管理手势密码按钮"); 157 | 158 | } 159 | break; 160 | case buttonTagForget: 161 | NSLog(@"点击了登录其他账户按钮"); 162 | 163 | break; 164 | default: 165 | break; 166 | } 167 | } 168 | 169 | #pragma mark - circleView - delegate 170 | #pragma mark - circleView - delegate - setting 171 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type connectCirclesLessThanNeedWithGesture:(NSString *)gesture 172 | { 173 | NSString *gestureOne = [PCCircleViewConst getGestureWithKey:gestureOneSaveKey]; 174 | 175 | // 看是否存在第一个密码 176 | if ([gestureOne length]) { 177 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"重设" style:UIBarButtonItemStylePlain target:self action:@selector(didClickRightItem)]; 178 | [self.msgLabel showWarnMsgAndShake:gestureTextDrawAgainError]; 179 | } else { 180 | NSLog(@"密码长度不合法%@", gesture); 181 | [self.msgLabel showWarnMsgAndShake:gestureTextConnectLess]; 182 | } 183 | } 184 | 185 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteSetFirstGesture:(NSString *)gesture 186 | { 187 | NSLog(@"获得第一个手势密码%@", gesture); 188 | [self.msgLabel showWarnMsg:gestureTextDrawAgain]; 189 | 190 | // infoView展示对应选中的圆 191 | [self infoViewSelectedSubviewsSameAsCircleView:view]; 192 | } 193 | 194 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteSetSecondGesture:(NSString *)gesture result:(BOOL)equal 195 | { 196 | NSLog(@"获得第二个手势密码%@",gesture); 197 | 198 | if (equal) { 199 | 200 | NSLog(@"两次手势匹配!可以进行本地化保存了"); 201 | 202 | [self.msgLabel showWarnMsg:gestureTextSetSuccess]; 203 | [PCCircleViewConst saveGesture:gesture Key:gestureFinalSaveKey]; 204 | [self.navigationController popToRootViewControllerAnimated:YES]; 205 | 206 | } else { 207 | NSLog(@"两次手势不匹配!"); 208 | 209 | [self.msgLabel showWarnMsgAndShake:gestureTextDrawAgainError]; 210 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"重设" style:UIBarButtonItemStylePlain target:self action:@selector(didClickRightItem)]; 211 | } 212 | } 213 | 214 | #pragma mark - circleView - delegate - login or verify gesture 215 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteLoginGesture:(NSString *)gesture result:(BOOL)equal 216 | { 217 | // 此时的type有两种情况 Login or verify 218 | if (type == CircleViewTypeLogin) { 219 | 220 | if (equal) { 221 | NSLog(@"登陆成功!"); 222 | [self.navigationController popToRootViewControllerAnimated:YES]; 223 | } else { 224 | NSLog(@"密码错误!"); 225 | [self.msgLabel showWarnMsgAndShake:gestureTextGestureVerifyError]; 226 | } 227 | } else if (type == CircleViewTypeVerify) { 228 | 229 | if (equal) { 230 | NSLog(@"验证成功,跳转到设置手势界面"); 231 | 232 | } else { 233 | NSLog(@"原手势密码输入错误!"); 234 | 235 | } 236 | } 237 | } 238 | 239 | #pragma mark - infoView展示方法 240 | #pragma mark - 让infoView对应按钮选中 241 | - (void)infoViewSelectedSubviewsSameAsCircleView:(PCCircleView *)circleView { 242 | for (PCCircle *circle in circleView.subviews) { 243 | 244 | if (circle.state == CircleStateSelected || circle.state == CircleStateLastOneSelected) { 245 | 246 | for (PCCircle *infoCircle in self.infoView.subviews) { 247 | if (infoCircle.tag == circle.tag) { 248 | [infoCircle setState:CircleStateSelected]; 249 | } 250 | } 251 | } 252 | } 253 | } 254 | 255 | #pragma mark - 让infoView对应按钮取消选中 256 | 257 | - (void)infoViewDeselectedSubviews { 258 | [self.infoView.subviews enumerateObjectsUsingBlock:^(PCCircle *obj, NSUInteger idx, BOOL *stop) { 259 | [obj setState:CircleStateNormal]; 260 | }]; 261 | } 262 | 263 | #pragma mark - UINavigationControllerDelegate 264 | 265 | - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { 266 | 267 | BOOL isLoginType = [viewController isKindOfClass:[self class]]; 268 | 269 | if (self.type == GestureViewControllerTypeLogin) { 270 | [self.navigationController setNavigationBarHidden:isLoginType animated:YES]; 271 | } 272 | } 273 | 274 | @end 275 | -------------------------------------------------------------------------------- /PCGestureUnlock/Controller/HomeViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HomeViewController.h 3 | // PCGestureUnlock 4 | // 5 | // Created by panchao on 2017/6/21. 6 | // Copyright © 2017年 coderMonkey. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HomeViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PCGestureUnlock/Controller/HomeViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HomeViewController.m 3 | // PCGestureUnlock 4 | // 5 | // Created by panchao on 2017/6/21. 6 | // Copyright © 2017年 coderMonkey. All rights reserved. 7 | // 8 | 9 | #import "HomeViewController.h" 10 | #import "GestureViewController.h" 11 | #import "GestureVerifyViewController.h" 12 | #import "PCCircleViewConst.h" 13 | 14 | @interface HomeViewController () 15 | 16 | @end 17 | 18 | @implementation HomeViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | 23 | } 24 | 25 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 26 | switch (indexPath.row) { 27 | case 0: 28 | { 29 | GestureViewController *gestureVc = [[GestureViewController alloc] init]; 30 | gestureVc.type = GestureViewControllerTypeSetting; 31 | [self.navigationController pushViewController:gestureVc animated:YES]; 32 | } 33 | break; 34 | case 1: 35 | { 36 | if ([[PCCircleViewConst getGestureWithKey:gestureFinalSaveKey] length]) { 37 | GestureViewController *gestureVc = [[GestureViewController alloc] init]; 38 | [gestureVc setType:GestureViewControllerTypeLogin]; 39 | [self.navigationController pushViewController:gestureVc animated:YES]; 40 | } else { 41 | 42 | UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:@"提示" message:@"暂未设置手势密码,是否前往设置?" preferredStyle:UIAlertControllerStyleAlert]; 43 | UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]; 44 | UIAlertAction *set = [UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 45 | GestureViewController *gestureVc = [[GestureViewController alloc] init]; 46 | gestureVc.type = GestureViewControllerTypeSetting; 47 | [self.navigationController pushViewController:gestureVc animated:YES]; 48 | }]; 49 | [alertVc addAction:cancel]; 50 | [alertVc addAction:set]; 51 | [self presentViewController:alertVc animated:YES 52 | completion:nil]; 53 | } 54 | } 55 | break; 56 | case 2: 57 | { 58 | GestureVerifyViewController *gestureVerifyVc = [[GestureVerifyViewController alloc] init]; 59 | [self.navigationController pushViewController:gestureVerifyVc animated:YES]; 60 | } 61 | break; 62 | 63 | case 3: 64 | { 65 | GestureVerifyViewController *gestureVerifyVc = [[GestureVerifyViewController alloc] init]; 66 | gestureVerifyVc.isToSetNewGesture = YES; 67 | [self.navigationController pushViewController:gestureVerifyVc animated:YES]; 68 | } 69 | break; 70 | default: 71 | break; 72 | } 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /PCGestureUnlock/ErrorDisplay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iosdeveloperpanc/PCGestureUnlock/666798b8095878b9824ab9351ca62075f1cd86e9/PCGestureUnlock/ErrorDisplay.gif -------------------------------------------------------------------------------- /PCGestureUnlock/FrameWork/PCCircle.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | /** 5 | * 单个圆的各种状态 6 | */ 7 | typedef enum{ 8 | CircleStateNormal = 1, 9 | CircleStateSelected, 10 | CircleStateError, 11 | CircleStateLastOneSelected, 12 | CircleStateLastOneError 13 | }CircleState; 14 | 15 | /** 16 | * 单个圆的用途类型 17 | */ 18 | typedef enum 19 | { 20 | CircleTypeInfo = 1, 21 | CircleTypeGesture 22 | }CircleType; 23 | 24 | @interface PCCircle : UIView 25 | 26 | /** 27 | * 所处的状态 28 | */ 29 | @property (nonatomic, assign) CircleState state; 30 | 31 | /** 32 | * 类型 33 | */ 34 | @property (nonatomic, assign) CircleType type; 35 | 36 | /** 37 | * 是否有箭头 default is YES 38 | */ 39 | @property (nonatomic, assign) BOOL arrow; 40 | 41 | /** 角度 */ 42 | @property (nonatomic,assign) CGFloat angle; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /PCGestureUnlock/FrameWork/PCCircle.m: -------------------------------------------------------------------------------- 1 | 2 | #import "PCCircle.h" 3 | #import "PCCircleViewConst.h" 4 | 5 | @interface PCCircle() 6 | 7 | /** 8 | * 外环颜色 9 | */ 10 | @property (nonatomic, strong) UIColor *outCircleColor; 11 | 12 | /** 13 | * 实心圆颜色 14 | */ 15 | @property (nonatomic, strong) UIColor *inCircleColor; 16 | 17 | /** 18 | * 三角形颜色 19 | */ 20 | @property (nonatomic, strong) UIColor *trangleColor; 21 | 22 | @end 23 | 24 | @implementation PCCircle 25 | 26 | - (instancetype)init 27 | { 28 | if (self = [super init]) { 29 | self.backgroundColor = CircleBackgroundColor; 30 | } 31 | return self; 32 | } 33 | 34 | - (id)initWithCoder:(NSCoder *)aDecoder 35 | { 36 | if (self = [super initWithCoder:aDecoder]) { 37 | self.backgroundColor = CircleBackgroundColor; 38 | } 39 | return self; 40 | } 41 | 42 | 43 | - (void)drawRect:(CGRect)rect { 44 | 45 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 46 | 47 | CGFloat radio; 48 | CGRect circleRect = CGRectMake(CircleEdgeWidth, CircleEdgeWidth, rect.size.width - 2 * CircleEdgeWidth, rect.size.height - 2 * CircleEdgeWidth); 49 | 50 | if (self.type == CircleTypeGesture) { 51 | radio = CircleRadio; 52 | } else { 53 | radio = 1; 54 | } 55 | 56 | // 上下文旋转 57 | [self transFormCtx:ctx rect:rect]; 58 | 59 | // 画圆环 60 | [self drawEmptyCircleWithContext:ctx rect:circleRect color:self.outCircleColor]; 61 | 62 | // 画实心圆 63 | [self drawSolidCircleWithContext:ctx rect:rect radio:radio color:self.inCircleColor]; 64 | 65 | if (self.arrow) { 66 | 67 | // 画三角形箭头 68 | [self drawTrangleWithContext:ctx topPoint:CGPointMake(rect.size.width/2, 10) length:kTrangleLength color:self.trangleColor]; 69 | } 70 | } 71 | 72 | #pragma mark - 画外圆环 73 | /** 74 | * 画外圆环 75 | * 76 | * @param ctx 图形上下文 77 | * @param rect 绘画范围 78 | * @param color 绘制颜色 79 | */ 80 | - (void)drawEmptyCircleWithContext:(CGContextRef)ctx rect:(CGRect)rect color:(UIColor *)color 81 | { 82 | CGMutablePathRef circlePath = CGPathCreateMutable(); 83 | CGPathAddEllipseInRect(circlePath, NULL, rect); 84 | CGContextAddPath(ctx, circlePath); 85 | [color set]; 86 | CGContextSetLineWidth(ctx, CircleEdgeWidth); 87 | CGContextStrokePath(ctx); 88 | CGPathRelease(circlePath); 89 | } 90 | 91 | #pragma mark - 画实心圆 92 | /** 93 | * 画实心圆 94 | * 95 | * @param ctx 图形上下文 96 | * @param rect 绘制范围 97 | * @param radio 占大圆比例 98 | * @param color 绘制颜色 99 | */ 100 | - (void)drawSolidCircleWithContext:(CGContextRef)ctx rect:(CGRect)rect radio:(CGFloat)radio color:(UIColor *)color 101 | { 102 | CGMutablePathRef circlePath = CGPathCreateMutable(); 103 | CGPathAddEllipseInRect(circlePath, NULL, CGRectMake(rect.size.width/2 * (1 - radio) + CircleEdgeWidth, rect.size.height/2 * (1 - radio) + CircleEdgeWidth, rect.size.width * radio - CircleEdgeWidth * 2, rect.size.height * radio - CircleEdgeWidth * 2)); 104 | [color set]; 105 | CGContextAddPath(ctx, circlePath); 106 | CGContextFillPath(ctx); 107 | CGPathRelease(circlePath); 108 | } 109 | 110 | #pragma mark - 画三角形 111 | /** 112 | * 画三角形 113 | * 114 | * @param ctx 图形上下文 115 | * @param point 顶点 116 | * @param length 边长 117 | * @param color 绘制颜色 118 | */ 119 | - (void)drawTrangleWithContext:(CGContextRef)ctx topPoint:(CGPoint)point length:(CGFloat)length color:(UIColor *)color 120 | { 121 | CGMutablePathRef trianglePathM = CGPathCreateMutable(); 122 | CGPathMoveToPoint(trianglePathM, NULL, point.x, point.y); 123 | CGPathAddLineToPoint(trianglePathM, NULL, point.x - length/2, point.y + length/2); 124 | CGPathAddLineToPoint(trianglePathM, NULL, point.x + length/2, point.y + length/2); 125 | CGContextAddPath(ctx, trianglePathM); 126 | [color set]; 127 | CGContextFillPath(ctx); 128 | CGPathRelease(trianglePathM); 129 | } 130 | 131 | /* 132 | * 上下文旋转 133 | */ 134 | -(void)transFormCtx:(CGContextRef)ctx rect:(CGRect)rect{ 135 | // if(self.angle == 0) return; 136 | CGFloat translateXY = rect.size.width * .5f; 137 | //平移 138 | CGContextTranslateCTM(ctx, translateXY, translateXY); 139 | CGContextRotateCTM(ctx, self.angle); 140 | //再平移回来 141 | CGContextTranslateCTM(ctx, -translateXY, -translateXY); 142 | } 143 | 144 | - (UIColor *)outCircleColor 145 | { 146 | UIColor *color; 147 | switch (self.state) { 148 | case CircleStateNormal: 149 | color = CircleStateNormalOutsideColor; 150 | break; 151 | case CircleStateSelected: 152 | color = CircleStateSelectedOutsideColor; 153 | break; 154 | case CircleStateError: 155 | color = CircleStateErrorOutsideColor; 156 | break; 157 | case CircleStateLastOneSelected: 158 | color = CircleStateSelectedOutsideColor; 159 | break; 160 | case CircleStateLastOneError: 161 | color = CircleStateErrorOutsideColor; 162 | break; 163 | default: 164 | color = CircleStateNormalOutsideColor; 165 | break; 166 | } 167 | return color; 168 | } 169 | 170 | - (UIColor *)inCircleColor 171 | { 172 | UIColor *color; 173 | switch (self.state) { 174 | case CircleStateNormal: 175 | color = CircleStateNormalInsideColor; 176 | break; 177 | case CircleStateSelected: 178 | color = CircleStateSelectedInsideColor; 179 | break; 180 | case CircleStateError: 181 | color = CircleStateErrorInsideColor; 182 | break; 183 | case CircleStateLastOneSelected: 184 | color = CircleStateSelectedInsideColor; 185 | break; 186 | case CircleStateLastOneError: 187 | color = CircleStateErrorInsideColor; 188 | break; 189 | default: 190 | color = CircleStateNormalInsideColor; 191 | break; 192 | } 193 | return color; 194 | } 195 | 196 | - (UIColor *)trangleColor 197 | { 198 | UIColor *color; 199 | switch (self.state) { 200 | case CircleStateNormal: 201 | color = CircleStateNormalTrangleColor; 202 | break; 203 | case CircleStateSelected: 204 | color = CircleStateSelectedTrangleColor; 205 | break; 206 | case CircleStateError: 207 | color = CircleStateErrorTrangleColor; 208 | break; 209 | case CircleStateLastOneSelected: 210 | color = CircleStateNormalTrangleColor; 211 | break; 212 | case CircleStateLastOneError: 213 | color = CircleStateNormalTrangleColor; 214 | break; 215 | default: 216 | color = CircleStateNormalTrangleColor; 217 | break; 218 | } 219 | return color; 220 | } 221 | 222 | - (void)setAngle:(CGFloat)angle 223 | { 224 | _angle = angle; 225 | 226 | [self setNeedsDisplay]; 227 | } 228 | 229 | - (void)setState:(CircleState)state 230 | { 231 | _state = state; 232 | 233 | [self setNeedsDisplay]; 234 | } 235 | 236 | @end 237 | -------------------------------------------------------------------------------- /PCGestureUnlock/FrameWork/PCCircleView.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | /** 5 | * 手势密码界面用途类型 6 | */ 7 | typedef enum{ 8 | CircleViewTypeSetting = 1, // 设置手势密码 9 | CircleViewTypeLogin, // 登陆手势密码 10 | CircleViewTypeVerify // 验证旧手势密码 11 | 12 | }CircleViewType; 13 | 14 | @class PCCircleView; 15 | 16 | @protocol CircleViewDelegate 17 | 18 | @optional 19 | 20 | #pragma mark - 设置手势密码代理方法 21 | /** 22 | * 连线个数少于4个时,通知代理 23 | * 24 | * @param view circleView 25 | * @param type type 26 | * @param gesture 手势结果 27 | */ 28 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type connectCirclesLessThanNeedWithGesture:(NSString *)gesture; 29 | 30 | /** 31 | * 连线个数多于或等于4个,获取到第一个手势密码时通知代理 32 | * 33 | * @param view circleView 34 | * @param type type 35 | * @param gesture 第一个次保存的密码 36 | */ 37 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteSetFirstGesture:(NSString *)gesture; 38 | 39 | /** 40 | * 获取到第二个手势密码时通知代理 41 | * 42 | * @param view circleView 43 | * @param type type 44 | * @param gesture 第二次手势密码 45 | * @param equal 第二次和第一次获得的手势密码匹配结果 46 | */ 47 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteSetSecondGesture:(NSString *)gesture result:(BOOL)equal; 48 | 49 | #pragma mark - 登录手势密码代理方法 50 | /** 51 | * 登陆或者验证手势密码输入完成时的代理方法 52 | * 53 | * @param view circleView 54 | * @param type type 55 | * @param gesture 登陆时的手势密码 56 | */ 57 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteLoginGesture:(NSString *)gesture result:(BOOL)equal; 58 | 59 | @end 60 | 61 | @interface PCCircleView : UIView 62 | 63 | /** 64 | * 是否剪裁 default is YES 65 | */ 66 | @property (nonatomic, assign) BOOL clip; 67 | 68 | /** 69 | * 是否有箭头 default is YES 70 | */ 71 | @property (nonatomic, assign) BOOL arrow; 72 | 73 | /** 74 | * 解锁类型 75 | */ 76 | @property (nonatomic, assign) CircleViewType type; 77 | 78 | // 代理 79 | @property (nonatomic, weak) id delegate; 80 | 81 | // 初始化方法(设置view的相关类型、参数) 82 | - (instancetype)initWithType:(CircleViewType)type clip:(BOOL)clip arrow:(BOOL)arrow; 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /PCGestureUnlock/FrameWork/PCCircleView.m: -------------------------------------------------------------------------------- 1 | 2 | #import "PCCircleView.h" 3 | #import "PCCircle.h" 4 | #import "PCCircleViewConst.h" 5 | 6 | @interface PCCircleView() 7 | 8 | // 选中的圆的集合 9 | @property (nonatomic, strong) NSMutableArray *circleSet; 10 | 11 | // 当前点 12 | @property (nonatomic, assign) CGPoint currentPoint; 13 | 14 | // 数组清空标志 15 | @property (nonatomic, assign) BOOL hasClean; 16 | 17 | @end 18 | 19 | @implementation PCCircleView 20 | 21 | #pragma mark - 重写arrow的setter 22 | - (void)setArrow:(BOOL)arrow 23 | { 24 | _arrow = arrow; 25 | 26 | // 遍历子控件,改变其是否有箭头 27 | [self.subviews enumerateObjectsUsingBlock:^(PCCircle *circle, NSUInteger idx, BOOL *stop) { 28 | [circle setArrow:arrow]; 29 | }]; 30 | } 31 | 32 | - (NSMutableArray *)circleSet 33 | { 34 | if (_circleSet == nil) { 35 | _circleSet = [NSMutableArray array]; 36 | } 37 | return _circleSet; 38 | } 39 | 40 | #pragma mark - 初始化方法:初始化type、clip、arrow 41 | /** 42 | * 初始化方法 43 | * 44 | * @param type 类型 45 | * @param clip 是否剪裁 46 | * @param arrow 三角形箭头 47 | */ 48 | - (instancetype)initWithType:(CircleViewType)type clip:(BOOL)clip arrow:(BOOL)arrow 49 | { 50 | if (self = [super init]) { 51 | // 解锁视图准备 52 | [self lockViewPrepare]; 53 | 54 | self.type = type; 55 | self.clip = clip; 56 | self.arrow = arrow; 57 | } 58 | return self; 59 | } 60 | 61 | - (instancetype)init 62 | { 63 | if (self = [super init]) { 64 | // 解锁视图准备 65 | [self lockViewPrepare]; 66 | } 67 | return self; 68 | } 69 | 70 | - (id)initWithCoder:(NSCoder *)aDecoder 71 | { 72 | if (self = [super initWithCoder:aDecoder]) { 73 | // 解锁视图准备 74 | [self lockViewPrepare]; 75 | } 76 | return self; 77 | } 78 | 79 | #pragma mark - 解锁视图准备 80 | /* 81 | * 解锁视图准备 82 | */ 83 | -(void)lockViewPrepare{ 84 | 85 | [self setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width - CircleViewEdgeMargin * 2, [UIScreen mainScreen].bounds.size.width - CircleViewEdgeMargin * 2)]; 86 | [self setCenter:CGPointMake([UIScreen mainScreen].bounds.size.width/2, CircleViewCenterY)]; 87 | 88 | // 默认剪裁子控件 89 | [self setClip:YES]; 90 | 91 | // 默认有箭头 92 | [self setArrow:YES]; 93 | 94 | self.backgroundColor = CircleBackgroundColor; 95 | 96 | for (NSUInteger i=0; i<9; i++) { 97 | 98 | PCCircle *circle = [[PCCircle alloc] init]; 99 | circle.type = CircleTypeGesture; 100 | circle.arrow = self.arrow; 101 | [self addSubview:circle]; 102 | } 103 | } 104 | 105 | -(void)layoutSubviews{ 106 | 107 | [super layoutSubviews]; 108 | 109 | CGFloat itemViewWH = CircleRadius * 2; 110 | CGFloat marginValue = (self.frame.size.width - 3 * itemViewWH) / 3.0f; 111 | 112 | [self.subviews enumerateObjectsUsingBlock:^(UIView *subview, NSUInteger idx, BOOL *stop) { 113 | 114 | NSUInteger row = idx % 3; 115 | 116 | NSUInteger col = idx / 3; 117 | 118 | CGFloat x = marginValue * row + row * itemViewWH + marginValue/2; 119 | 120 | CGFloat y = marginValue * col + col * itemViewWH + marginValue/2; 121 | 122 | CGRect frame = CGRectMake(x, y, itemViewWH, itemViewWH); 123 | 124 | // 设置tag -> 密码记录的单元 125 | subview.tag = idx + 1; 126 | 127 | subview.frame = frame; 128 | }]; 129 | } 130 | 131 | #pragma mark - touch began - moved - end 132 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 133 | { 134 | [self gestureEndResetMembers]; 135 | 136 | self.currentPoint = CGPointZero; 137 | UITouch *touch = [touches anyObject]; 138 | CGPoint point = [touch locationInView:self]; 139 | 140 | [self.subviews enumerateObjectsUsingBlock:^(PCCircle *circle, NSUInteger idx, BOOL *stop) { 141 | if (CGRectContainsPoint(circle.frame, point)) { 142 | [circle setState:CircleStateSelected]; 143 | [self.circleSet addObject:circle]; 144 | } 145 | }]; 146 | 147 | // 数组中最后一个对象的处理 148 | [self circleSetLastObjectWithState:CircleStateLastOneSelected]; 149 | 150 | [self setNeedsDisplay]; 151 | } 152 | 153 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 154 | { 155 | self.currentPoint = CGPointZero; 156 | UITouch *touch = [touches anyObject]; 157 | CGPoint point = [touch locationInView:self]; 158 | 159 | [self.subviews enumerateObjectsUsingBlock:^(PCCircle *circle, NSUInteger idx, BOOL *stop) { 160 | 161 | if (CGRectContainsPoint(circle.frame, point)) { 162 | if ([self.circleSet containsObject:circle]) { 163 | 164 | } else { 165 | [self.circleSet addObject:circle]; 166 | 167 | // move过程中的连线(包含跳跃连线的处理) 168 | [self calAngleAndconnectTheJumpedCircle]; 169 | 170 | } 171 | } else { 172 | 173 | self.currentPoint = point; 174 | } 175 | }]; 176 | 177 | [self.circleSet enumerateObjectsUsingBlock:^(PCCircle *circle, NSUInteger idx, BOOL *stop) { 178 | 179 | [circle setState:CircleStateSelected]; 180 | 181 | // 如果是登录或者验证原手势密码,就改为对应的状态 182 | if (self.type != CircleViewTypeSetting) { 183 | [circle setState:CircleStateLastOneSelected]; 184 | } 185 | }]; 186 | 187 | // 数组中最后一个对象的处理 188 | [self circleSetLastObjectWithState:CircleStateLastOneSelected]; 189 | 190 | [self setNeedsDisplay]; 191 | } 192 | 193 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 194 | { 195 | [self setHasClean:NO]; 196 | 197 | NSString *gesture = [self getGestureResultFromCircleSet:self.circleSet]; 198 | CGFloat length = [gesture length]; 199 | 200 | if (length == 0) { 201 | return; 202 | } 203 | 204 | // 手势绘制结果处理 205 | switch (self.type) { 206 | case CircleViewTypeSetting: 207 | [self gestureEndByTypeSettingWithGesture:gesture length:length]; 208 | break; 209 | case CircleViewTypeLogin: 210 | [self gestureEndByTypeLoginWithGesture:gesture length:length]; 211 | break; 212 | case CircleViewTypeVerify: 213 | [self gestureEndByTypeVerifyWithGesture:gesture length:length]; 214 | break; 215 | default: 216 | [self gestureEndByTypeSettingWithGesture:gesture length:length]; 217 | break; 218 | } 219 | 220 | // 手势结束后是否错误回显重绘,取决于是否延时清空数组和状态复原 221 | [self errorToDisplay]; 222 | } 223 | 224 | #pragma mark - 是否错误回显重绘 225 | /** 226 | * 是否错误回显重绘 227 | */ 228 | - (void)errorToDisplay 229 | { 230 | if ([self getCircleState] == CircleStateError || [self getCircleState] == CircleStateLastOneError) { 231 | 232 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kdisplayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 233 | 234 | [self gestureEndResetMembers]; 235 | 236 | }); 237 | 238 | } else { 239 | 240 | [self gestureEndResetMembers]; 241 | } 242 | } 243 | 244 | #pragma mark - 手势结束时的清空操作 245 | /** 246 | * 手势结束时的清空操作 247 | */ 248 | - (void)gestureEndResetMembers 249 | { 250 | @synchronized(self) { // 保证线程安全 251 | if (!self.hasClean) { 252 | 253 | // 手势完毕,选中的圆回归普通状态 254 | [self changeCircleInCircleSetWithState:CircleStateNormal]; 255 | 256 | // 清空数组 257 | [self.circleSet removeAllObjects]; 258 | 259 | // 清空方向 260 | [self resetAllCirclesDirect]; 261 | 262 | // 完成之后改变clean的状态 263 | [self setHasClean:YES]; 264 | } 265 | } 266 | } 267 | 268 | #pragma mark - 获取当前选中圆的状态 269 | - (CircleState)getCircleState 270 | { 271 | return [(PCCircle *)[self.circleSet firstObject] state]; 272 | } 273 | 274 | #pragma mark - 清空所有子控件的方向 275 | - (void)resetAllCirclesDirect 276 | { 277 | [self.subviews enumerateObjectsUsingBlock:^(PCCircle *obj, NSUInteger idx, BOOL *stop) { 278 | [obj setAngle:0]; 279 | }]; 280 | } 281 | 282 | #pragma mark - 对数组中最后一个对象的处理 283 | - (void)circleSetLastObjectWithState:(CircleState)state 284 | { 285 | [[self.circleSet lastObject] setState:state]; 286 | } 287 | 288 | #pragma mark - 解锁类型:设置 手势路径的处理 289 | /** 290 | * 解锁类型:设置 手势路径的处理 291 | */ 292 | - (void)gestureEndByTypeSettingWithGesture:(NSString *)gesture length:(CGFloat)length 293 | { 294 | if (length < CircleSetCountLeast) { 295 | // 连接少于最少个数 (<4个) 296 | 297 | // 1.通知代理 298 | if ([self.delegate respondsToSelector:@selector(circleView:type:connectCirclesLessThanNeedWithGesture:)]) { 299 | [self.delegate circleView:self type:self.type connectCirclesLessThanNeedWithGesture:gesture]; 300 | } 301 | 302 | // 2.改变状态为error 303 | [self changeCircleInCircleSetWithState:CircleStateError]; 304 | 305 | } else {// 连接多于最少个数 (>=4个) 306 | 307 | NSString *gestureOne = [PCCircleViewConst getGestureWithKey:gestureOneSaveKey]; 308 | 309 | if ([gestureOne length] < CircleSetCountLeast) { // 接收并存储第一个密码 310 | // 记录第一次密码 311 | [PCCircleViewConst saveGesture:gesture Key:gestureOneSaveKey]; 312 | 313 | // 通知代理 314 | if ([self.delegate respondsToSelector:@selector(circleView:type:didCompleteSetFirstGesture:)]) { 315 | [self.delegate circleView:self type:self.type didCompleteSetFirstGesture:gesture]; 316 | } 317 | 318 | } else { // 接受第二个密码并与第一个密码匹配,一致后存储起来 319 | 320 | BOOL equal = [gesture isEqual:[PCCircleViewConst getGestureWithKey:gestureOneSaveKey]]; // 匹配两次手势 321 | 322 | // 通知代理 323 | if ([self.delegate respondsToSelector:@selector(circleView:type:didCompleteSetSecondGesture:result:)]) { 324 | 325 | [self.delegate circleView:self type:self.type didCompleteSetSecondGesture:gesture result:equal]; 326 | 327 | } 328 | 329 | if (equal){ 330 | // 一致,存储密码 331 | [PCCircleViewConst saveGesture:gesture Key:gestureFinalSaveKey]; 332 | 333 | } else { 334 | // 不一致,重绘回显 335 | [self changeCircleInCircleSetWithState:CircleStateError]; 336 | } 337 | } 338 | 339 | } 340 | } 341 | 342 | #pragma mark - 解锁类型:登陆 手势路径的处理 343 | /** 344 | * 解锁类型:登陆 手势路径的处理 345 | */ 346 | - (void)gestureEndByTypeLoginWithGesture:(NSString *)gesture length:(CGFloat)length 347 | { 348 | NSString *password = [PCCircleViewConst getGestureWithKey:gestureFinalSaveKey]; 349 | 350 | BOOL equal = [gesture isEqual:password]; 351 | 352 | if ([self.delegate respondsToSelector:@selector(circleView:type:didCompleteLoginGesture:result:)]) { 353 | [self.delegate circleView:self type:self.type didCompleteLoginGesture:gesture result:equal]; 354 | } 355 | 356 | if (equal) { 357 | 358 | } else { 359 | 360 | [self changeCircleInCircleSetWithState:CircleStateError]; 361 | } 362 | } 363 | 364 | #pragma mark - 解锁类型:验证 手势路径的处理 365 | - (void)gestureEndByTypeVerifyWithGesture:(NSString *)gesture length:(CGFloat)length 366 | { 367 | // NSString *password = [CircleViewConst getGestureWithKey:gestureFinalSaveKey]; 368 | // 369 | // BOOL equal = [gesture isEqual:password]; 370 | // 371 | // if ([self.delegate respondsToSelector:@selector(circleView:type:didCompleteLoginGesture: result:)]) { 372 | // [self.delegate circleView:self type:self.type didCompleteLoginGesture:gesture result:equal]; 373 | // } 374 | // 375 | // if (equal) { 376 | // 377 | // } else { 378 | // [self changeCircleInCircleSetWithState:CircleStateError]; 379 | // } 380 | [self gestureEndByTypeLoginWithGesture:gesture length:length]; 381 | } 382 | 383 | #pragma mark - 改变选中数组CircleSet子控件状态 384 | - (void)changeCircleInCircleSetWithState:(CircleState)state 385 | { 386 | [self.circleSet enumerateObjectsUsingBlock:^(PCCircle *circle, NSUInteger idx, BOOL *stop) { 387 | 388 | [circle setState:state]; 389 | 390 | // 如果是错误状态,那就将最后一个按钮特殊处理 391 | if (state == CircleStateError) { 392 | if (idx == self.circleSet.count - 1) { 393 | [circle setState:CircleStateLastOneError]; 394 | } 395 | } 396 | 397 | }]; 398 | 399 | [self setNeedsDisplay]; 400 | } 401 | 402 | #pragma mark - 将circleSet数组解析遍历,拼手势密码字符串 403 | - (NSString *)getGestureResultFromCircleSet:(NSMutableArray *)circleSet 404 | { 405 | NSMutableString *gesture = [NSMutableString string]; 406 | 407 | for (PCCircle *circle in circleSet) { 408 | // 遍历取tag拼字符串 409 | [gesture appendFormat:@"%@", @(circle.tag)]; 410 | } 411 | 412 | return gesture; 413 | } 414 | 415 | #pragma mark - drawRect 416 | - (void)drawRect:(CGRect)rect 417 | { 418 | // 如果没有任何选中按钮, 直接retrun 419 | if (self.circleSet == nil || self.circleSet.count == 0) return; 420 | 421 | UIColor *color; 422 | if ([self getCircleState] == CircleStateError) { 423 | color = CircleConnectLineErrorColor; 424 | } else { 425 | color = CircleConnectLineNormalColor; 426 | } 427 | 428 | // 绘制图案 429 | [self connectCirclesInRect:rect lineColor:color]; 430 | } 431 | 432 | #pragma mark - 连线绘制图案(以设定颜色绘制) 433 | /** 434 | * 将选中的圆形以color颜色链接起来 435 | * 436 | * @param rect 图形上下文 437 | * @param color 连线颜色 438 | */ 439 | - (void)connectCirclesInRect:(CGRect)rect lineColor:(UIColor *)color 440 | { 441 | //获取上下文 442 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 443 | 444 | //添加路径 445 | CGContextAddRect(ctx, rect); 446 | 447 | //是否剪裁 448 | [self clipSubviewsWhenConnectInContext:ctx clip:self.clip]; 449 | 450 | //剪裁上下文 451 | CGContextEOClip(ctx); 452 | 453 | // 遍历数组中的circle 454 | for (int index = 0; index < self.circleSet.count; index++) { 455 | 456 | // 取出选中按钮 457 | PCCircle *circle = self.circleSet[index]; 458 | 459 | if (index == 0) { // 起点按钮 460 | CGContextMoveToPoint(ctx, circle.center.x, circle.center.y); 461 | }else{ 462 | CGContextAddLineToPoint(ctx, circle.center.x, circle.center.y); // 全部是连线 463 | } 464 | } 465 | 466 | // 连接最后一个按钮到手指当前触摸得点 467 | if (CGPointEqualToPoint(self.currentPoint, CGPointZero) == NO) { 468 | 469 | [self.subviews enumerateObjectsUsingBlock:^(PCCircle *circle, NSUInteger idx, BOOL *stop) { 470 | 471 | if ([self getCircleState] == CircleStateError || [self getCircleState] == CircleStateLastOneError) { 472 | // 如果是错误的状态下不连接到当前点 473 | 474 | } else { 475 | 476 | CGContextAddLineToPoint(ctx, self.currentPoint.x, self.currentPoint.y); 477 | 478 | } 479 | }]; 480 | } 481 | 482 | //线条转角样式 483 | CGContextSetLineCap(ctx, kCGLineCapRound); 484 | CGContextSetLineJoin(ctx, kCGLineJoinRound); 485 | 486 | // 设置绘图的属性 487 | CGContextSetLineWidth(ctx, CircleConnectLineWidth); 488 | 489 | // 线条颜色 490 | [color set]; 491 | 492 | //渲染路径 493 | CGContextStrokePath(ctx); 494 | } 495 | 496 | #pragma mark - 是否剪裁 497 | /** 498 | * 是否剪裁子控件 499 | * 500 | * @param ctx 图形上下文 501 | * @param clip 是否剪裁 502 | */ 503 | - (void)clipSubviewsWhenConnectInContext:(CGContextRef)ctx clip:(BOOL)clip 504 | { 505 | if (clip) { 506 | 507 | // 遍历所有子控件 508 | [self.subviews enumerateObjectsUsingBlock:^(PCCircle *circle, NSUInteger idx, BOOL *stop) { 509 | 510 | CGContextAddEllipseInRect(ctx, circle.frame); // 确定"剪裁"的形状 511 | }]; 512 | } 513 | } 514 | 515 | #pragma mark - 每添加一个圆,就计算一次方向 516 | -(void)calAngleAndconnectTheJumpedCircle{ 517 | 518 | if(self.circleSet == nil || [self.circleSet count] <= 1) return; 519 | 520 | //取出最后一个对象 521 | PCCircle *lastOne = [self.circleSet lastObject]; 522 | 523 | //倒数第二个 524 | PCCircle *lastTwo = [self.circleSet objectAtIndex:(self.circleSet.count -2)]; 525 | 526 | //计算倒数第二个的位置 527 | CGFloat last_1_x = lastOne.center.x; 528 | CGFloat last_1_y = lastOne.center.y; 529 | CGFloat last_2_x = lastTwo.center.x; 530 | CGFloat last_2_y = lastTwo.center.y; 531 | 532 | // 1.计算角度(反正切函数) 533 | CGFloat angle = atan2(last_1_y - last_2_y, last_1_x - last_2_x) + M_PI_2; 534 | [lastTwo setAngle:angle]; 535 | 536 | // 2.处理跳跃连线 537 | CGPoint center = [self centerPointWithPointOne:lastOne.center pointTwo:lastTwo.center]; 538 | 539 | PCCircle *centerCircle = [self enumCircleSetToFindWhichSubviewContainTheCenterPoint:center]; 540 | 541 | if (centerCircle != nil) { 542 | 543 | // 把跳过的圆加到数组中,它的位置是倒数第二个 544 | if (![self.circleSet containsObject:centerCircle]) { 545 | [self.circleSet insertObject:centerCircle atIndex:self.circleSet.count - 1]; 546 | } 547 | } 548 | } 549 | 550 | #pragma mark - 提供两个点,返回一个它们的中点 551 | - (CGPoint)centerPointWithPointOne:(CGPoint)pointOne pointTwo:(CGPoint)pointTwo 552 | { 553 | CGFloat x1 = fmax(pointOne.x, pointTwo.x); 554 | CGFloat x2 = fmin(pointOne.x, pointTwo.x); 555 | CGFloat y1 = fmax(pointOne.y, pointTwo.y); 556 | CGFloat y2 = fmin(pointOne.y, pointTwo.y); 557 | 558 | return CGPointMake((x1+x2)/2, (y1 + y2)/2); 559 | } 560 | 561 | #pragma mark - 给一个点,判断这个点是否被圆包含,如果包含就返回当前圆,如果不包含返回的是nil 562 | /** 563 | * 给一个点,判断这个点是否被圆包含,如果包含就返回当前圆,如果不包含返回的是nil 564 | * 565 | * @param point 当前点 566 | * 567 | * @return 点所在的圆 568 | */ 569 | - (PCCircle *)enumCircleSetToFindWhichSubviewContainTheCenterPoint:(CGPoint)point 570 | { 571 | PCCircle *centerCircle; 572 | for (PCCircle *circle in self.subviews) { 573 | if (CGRectContainsPoint(circle.frame, point)) { 574 | centerCircle = circle; 575 | } 576 | } 577 | 578 | if (![self.circleSet containsObject:centerCircle]) { 579 | // 这个circle的角度和倒数第二个circle的角度一致 580 | centerCircle.angle = [[self.circleSet objectAtIndex:self.circleSet.count - 2] angle]; 581 | } 582 | 583 | return centerCircle; // 注意:可能返回的是nil,就是当前点不在圆内 584 | } 585 | 586 | @end 587 | -------------------------------------------------------------------------------- /PCGestureUnlock/FrameWork/PCCircleViewConst.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | #define rgba(r,g,b,a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a] 5 | 6 | #define kScreenW [UIScreen mainScreen].bounds.size.width 7 | #define kScreenH [UIScreen mainScreen].bounds.size.height 8 | 9 | /** 10 | * 单个圆背景色 11 | */ 12 | #define CircleBackgroundColor [UIColor clearColor] 13 | 14 | /** 15 | * 解锁背景色 16 | */ 17 | #define CircleViewBackgroundColor rgba(13,52,89,1) 18 | 19 | /** 20 | * 普通状态下外空心圆颜色 21 | */ 22 | #define CircleStateNormalOutsideColor rgba(241,241,241,1) 23 | 24 | /** 25 | * 选中状态下外空心圆颜色 26 | */ 27 | #define CircleStateSelectedOutsideColor rgba(34,178,246,1) 28 | 29 | /** 30 | * 错误状态下外空心圆颜色 31 | */ 32 | #define CircleStateErrorOutsideColor rgba(254,82,92,1) 33 | 34 | /** 35 | * 普通状态下内实心圆颜色 36 | */ 37 | #define CircleStateNormalInsideColor [UIColor clearColor] 38 | 39 | /** 40 | * 选中状态下内实心圆颜色 41 | */ 42 | #define CircleStateSelectedInsideColor rgba(34,178,246,1) 43 | 44 | /** 45 | * 错误状态内实心圆颜色 46 | */ 47 | #define CircleStateErrorInsideColor rgba(254,82,92,1) 48 | 49 | /** 50 | * 普通状态下三角形颜色 51 | */ 52 | #define CircleStateNormalTrangleColor [UIColor clearColor] 53 | 54 | /** 55 | * 选中状态下三角形颜色 56 | */ 57 | #define CircleStateSelectedTrangleColor rgba(34,178,246,1) 58 | 59 | /** 60 | * 错误状态三角形颜色 61 | */ 62 | #define CircleStateErrorTrangleColor rgba(254,82,92,1) 63 | 64 | /** 65 | * 三角形边长 66 | */ 67 | #define kTrangleLength 10.0f 68 | 69 | /** 70 | * 普通时连线颜色 71 | */ 72 | #define CircleConnectLineNormalColor rgba(34,178,246,1) 73 | 74 | /** 75 | * 错误时连线颜色 76 | */ 77 | #define CircleConnectLineErrorColor rgba(254,82,92,1) 78 | 79 | /** 80 | * 连线宽度 81 | */ 82 | #define CircleConnectLineWidth 1.0f 83 | 84 | /** 85 | * 单个圆的半径 86 | */ 87 | #define CircleRadius 30.0f 88 | 89 | /** 90 | * 单个圆的圆心 91 | */ 92 | #define CircleCenter CGPointMake(CircleRadius, CircleRadius) 93 | 94 | /** 95 | * 空心圆圆环宽度 96 | */ 97 | #define CircleEdgeWidth 1.0f 98 | 99 | /** 100 | * 九宫格展示infoView 单个圆的半径 101 | */ 102 | #define CircleInfoRadius 5 103 | 104 | /** 105 | * 内部实心圆占空心圆的比例系数 106 | */ 107 | #define CircleRadio 0.4 108 | 109 | /** 110 | * 整个解锁View居中时,距离屏幕左边和右边的距离 111 | */ 112 | #define CircleViewEdgeMargin 30.0f 113 | 114 | /** 115 | * 整个解锁View的Center.y值 在当前屏幕的3/5位置 116 | */ 117 | #define CircleViewCenterY kScreenH * 3/5 118 | 119 | /** 120 | * 连接的圆最少的个数 121 | */ 122 | #define CircleSetCountLeast 4 123 | 124 | /** 125 | * 错误状态下回显的时间 126 | */ 127 | #define kdisplayTime 1.0f 128 | 129 | /** 130 | * 最终的手势密码存储key 131 | */ 132 | #define gestureFinalSaveKey @"gestureFinalSaveKey" 133 | 134 | /** 135 | * 第一个手势密码存储key 136 | */ 137 | #define gestureOneSaveKey @"gestureOneSaveKey" 138 | 139 | /** 140 | * 普通状态下文字提示的颜色 141 | */ 142 | #define textColorNormalState rgba(241,241,241,1) 143 | 144 | /** 145 | * 警告状态下文字提示的颜色 146 | */ 147 | #define textColorWarningState rgba(254,82,92,1) 148 | 149 | /** 150 | * 绘制解锁界面准备好时,提示文字 151 | */ 152 | #define gestureTextBeforeSet @"绘制解锁图案" 153 | 154 | /** 155 | * 设置时,连线个数少,提示文字 156 | */ 157 | #define gestureTextConnectLess [NSString stringWithFormat:@"最少连接%d个点,请重新输入", CircleSetCountLeast] 158 | 159 | /** 160 | * 确认图案,提示再次绘制 161 | */ 162 | #define gestureTextDrawAgain @"再次绘制解锁图案" 163 | 164 | /** 165 | * 再次绘制不一致,提示文字 166 | */ 167 | #define gestureTextDrawAgainError @"与上次绘制不一致,请重新绘制" 168 | 169 | /** 170 | * 设置成功 171 | */ 172 | #define gestureTextSetSuccess @"设置成功" 173 | 174 | /** 175 | * 请输入原手势密码 176 | */ 177 | #define gestureTextOldGesture @"请输入原手势密码" 178 | 179 | /** 180 | * 密码错误 181 | */ 182 | #define gestureTextGestureVerifyError @"密码错误" 183 | 184 | @interface PCCircleViewConst : NSObject 185 | 186 | /** 187 | * 偏好设置:存字符串(手势密码) 188 | * 189 | * @param gesture 字符串对象 190 | * @param key 存储key 191 | */ 192 | + (void)saveGesture:(NSString *)gesture Key:(NSString *)key; 193 | 194 | /** 195 | * 偏好设置:取字符串手势密码 196 | * 197 | * @param key key 198 | * 199 | * @return 字符串对象 200 | */ 201 | + (NSString *)getGestureWithKey:(NSString *)key; 202 | 203 | @end 204 | -------------------------------------------------------------------------------- /PCGestureUnlock/FrameWork/PCCircleViewConst.m: -------------------------------------------------------------------------------- 1 | 2 | #import "PCCircleViewConst.h" 3 | 4 | @implementation PCCircleViewConst 5 | 6 | + (void)saveGesture:(NSString *)gesture Key:(NSString *)key 7 | { 8 | [[NSUserDefaults standardUserDefaults] setObject:gesture forKey:key]; 9 | [[NSUserDefaults standardUserDefaults] synchronize]; 10 | } 11 | 12 | + (NSString *)getGestureWithKey:(NSString *)key 13 | { 14 | 15 | return [[NSUserDefaults standardUserDefaults] objectForKey:key]; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /PCGestureUnlock/Gategory/CALayer+Anim.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | @interface CALayer (Anim) 5 | 6 | /* 7 | * 摇动 8 | */ 9 | -(void)shake; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /PCGestureUnlock/Gategory/CALayer+Anim.m: -------------------------------------------------------------------------------- 1 | 2 | #import "CALayer+Anim.h" 3 | 4 | @implementation CALayer (Anim) 5 | 6 | 7 | /* 8 | * 摇动 9 | */ 10 | -(void)shake{ 11 | 12 | CAKeyframeAnimation *kfa = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"]; 13 | 14 | CGFloat s = 5; 15 | 16 | kfa.values = @[@(-s),@(0),@(s),@(0),@(-s),@(0),@(s),@(0)]; 17 | 18 | //时长 19 | kfa.duration = 0.3f; 20 | 21 | //重复 22 | kfa.repeatCount = 2; 23 | 24 | //移除 25 | kfa.removedOnCompletion = YES; 26 | 27 | [self addAnimation:kfa forKey:@"shake"]; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /PCGestureUnlock/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /PCGestureUnlock/Images.xcassets/head.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "3x", 14 | "filename" : "head@3x.png" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PCGestureUnlock/Images.xcassets/head.imageset/head@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iosdeveloperpanc/PCGestureUnlock/666798b8095878b9824ab9351ca62075f1cd86e9/PCGestureUnlock/Images.xcassets/head.imageset/head@3x.png -------------------------------------------------------------------------------- /PCGestureUnlock/Images.xcassets/head@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iosdeveloperpanc/PCGestureUnlock/666798b8095878b9824ab9351ca62075f1cd86e9/PCGestureUnlock/Images.xcassets/head@3x.png -------------------------------------------------------------------------------- /PCGestureUnlock/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /PCGestureUnlock/JumpConnect.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iosdeveloperpanc/PCGestureUnlock/666798b8095878b9824ab9351ca62075f1cd86e9/PCGestureUnlock/JumpConnect.gif -------------------------------------------------------------------------------- /PCGestureUnlock/View/PCCircleInfoView.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | @interface PCCircleInfoView : UIView 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /PCGestureUnlock/View/PCCircleInfoView.m: -------------------------------------------------------------------------------- 1 | 2 | #import "PCCircleInfoView.h" 3 | #import "PCCircleViewConst.h" 4 | #import "PCCircle.h" 5 | 6 | @interface PCCircleInfoView() 7 | 8 | 9 | @end 10 | 11 | @implementation PCCircleInfoView 12 | 13 | - (instancetype)init 14 | { 15 | if (self = [super init]) { 16 | // 解锁视图 17 | [self lockViewPrepare]; 18 | } 19 | return self; 20 | } 21 | 22 | - (id)initWithCoder:(NSCoder *)aDecoder 23 | { 24 | if (self = [super initWithCoder:aDecoder]) { 25 | // 解锁视图 26 | [self lockViewPrepare]; 27 | } 28 | return self; 29 | } 30 | 31 | /* 32 | * 解锁视图 33 | */ 34 | -(void)lockViewPrepare{ 35 | 36 | self.backgroundColor = CircleBackgroundColor; 37 | 38 | for (NSUInteger i=0; i<9; i++) { 39 | 40 | PCCircle *circle = [[PCCircle alloc] init]; 41 | circle.type = CircleTypeInfo; 42 | [self addSubview:circle]; 43 | } 44 | } 45 | 46 | -(void)layoutSubviews{ 47 | 48 | [super layoutSubviews]; 49 | 50 | CGFloat itemViewWH = CircleInfoRadius * 2; 51 | CGFloat marginValue = (self.frame.size.width - 3 * itemViewWH) / 3.0f; 52 | 53 | [self.subviews enumerateObjectsUsingBlock:^(UIView *subview, NSUInteger idx, BOOL *stop) { 54 | 55 | NSUInteger row = idx % 3; 56 | 57 | NSUInteger col = idx / 3; 58 | 59 | CGFloat x = marginValue * row + row * itemViewWH + marginValue/2; 60 | 61 | CGFloat y = marginValue * col + col * itemViewWH + marginValue/2; 62 | 63 | CGRect frame = CGRectMake(x, y, itemViewWH, itemViewWH); 64 | 65 | // 设置tag -> 密码记录的单元 66 | subview.tag = idx + 1; 67 | 68 | subview.frame = frame; 69 | }]; 70 | } 71 | 72 | @end 73 | 74 | -------------------------------------------------------------------------------- /PCGestureUnlock/View/PCLockLabel.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | @interface PCLockLabel : UILabel 5 | 6 | 7 | 8 | /* 9 | * 普通提示信息 10 | */ 11 | - (void)showNormalMsg:(NSString *)msg; 12 | 13 | 14 | /* 15 | * 警示信息 16 | */ 17 | - (void)showWarnMsg:(NSString *)msg; 18 | 19 | /* 20 | * 警示信息(shake) 21 | */ 22 | - (void)showWarnMsgAndShake:(NSString *)msg; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /PCGestureUnlock/View/PCLockLabel.m: -------------------------------------------------------------------------------- 1 | 2 | #import "PCLockLabel.h" 3 | #import "PCCircleViewConst.h" 4 | #import "CALayer+Anim.h" 5 | 6 | @implementation PCLockLabel 7 | 8 | 9 | - (instancetype)initWithFrame:(CGRect)frame{ 10 | 11 | self = [super initWithFrame:frame]; 12 | 13 | if(self){ 14 | 15 | //视图初始化 16 | [self viewPrepare]; 17 | } 18 | 19 | return self; 20 | } 21 | 22 | 23 | 24 | - (instancetype)initWithCoder:(NSCoder *)aDecoder{ 25 | 26 | self=[super initWithCoder:aDecoder]; 27 | 28 | if(self){ 29 | 30 | //视图初始化 31 | [self viewPrepare]; 32 | } 33 | 34 | return self; 35 | } 36 | 37 | 38 | /* 39 | * 视图初始化 40 | */ 41 | - (void)viewPrepare{ 42 | 43 | [self setFont:[UIFont systemFontOfSize:14.0f]]; 44 | [self setTextAlignment:NSTextAlignmentCenter]; 45 | } 46 | 47 | 48 | /* 49 | * 普通提示信息 50 | */ 51 | - (void)showNormalMsg:(NSString *)msg{ 52 | 53 | [self setText:msg]; 54 | [self setTextColor:textColorNormalState]; 55 | } 56 | 57 | /* 58 | * 警示信息 59 | */ 60 | - (void)showWarnMsg:(NSString *)msg{ 61 | 62 | [self setText:msg]; 63 | [self setTextColor:textColorWarningState]; 64 | } 65 | 66 | /* 67 | * 警示信息(shake) 68 | */ 69 | - (void)showWarnMsgAndShake:(NSString *)msg{ 70 | 71 | [self setText:msg]; 72 | [self setTextColor:textColorWarningState]; 73 | 74 | //添加一个shake动画 75 | [self.layer shake]; 76 | } 77 | 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /PCGestureUnlock/arrowDirctions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iosdeveloperpanc/PCGestureUnlock/666798b8095878b9824ab9351ca62075f1cd86e9/PCGestureUnlock/arrowDirctions.gif -------------------------------------------------------------------------------- /PCGestureUnlock/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PCGestureUnlock 4 | // 5 | // Created by panchao on 15/6/10. 6 | // Copyright (c) 2015年 coderMonkey. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /PCGestureUnlock/settingGesture.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iosdeveloperpanc/PCGestureUnlock/666798b8095878b9824ab9351ca62075f1cd86e9/PCGestureUnlock/settingGesture.gif -------------------------------------------------------------------------------- /PCGestureUnlockTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /PCGestureUnlockTests/PCGestureUnlockTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // PCGestureUnlockTests.m 3 | // PCGestureUnlockTests 4 | // 5 | // Created by panchao on 15/6/10. 6 | // Copyright (c) 2015年 coderMonkey. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface PCGestureUnlockTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation PCGestureUnlockTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PCGestureUnlock 2 | 3 | 目前最全面最高仿支付宝的手势解锁,而且提供方法进行参数修改,能解决项目开发中所有手势解锁的开发 4 | ------------------ 5 | 宣言:不仅仅是支付宝手势解锁,它很好很强大~ 6 | 7 | 框架基础:全面实现支付宝手势解锁,包括各种细节!!!(具体见gif图片) 8 | 9 | 框架目标:打造主流手势解锁终结者,简单易用,高度解耦! 10 | 11 | 框架特点:面向实际项目开发,修改参数(PCCircleViewConst.h文件中)即可实现实际需求 12 | 13 | 设置密码: 14 | 15 | ![ABC](https://github.com/iosdeveloperpanc/PCGestureUnlock/blob/master/PCGestureUnlock/settingGesture.gif) 16 | 17 | 细节处理之全方向箭头 18 | 19 | ![ABC](https://github.com/iosdeveloperpanc/PCGestureUnlock/blob/master/PCGestureUnlock/arrowDirctions.gif) 20 | 21 | 细节处理之错误绘制 22 | 23 | ![ABC](https://github.com/iosdeveloperpanc/PCGestureUnlock/blob/master/PCGestureUnlock/ErrorDisplay.gif) 24 | 25 | 细节处理之跳跃连线 26 | 27 | ![ABC](https://github.com/iosdeveloperpanc/PCGestureUnlock/blob/master/PCGestureUnlock/JumpConnect.gif) 28 | 29 | 框架使用说明: 30 | 使用前说明: 31 | 解锁界面(PCCircleView)可以实例化出特定使用的类型界面,实现以下方法即可 32 | // 初始化方法(设置view的相关类型、参数) 33 | - (instancetype)initWithType:(CircleViewType)type clip:(BOOL)clip arrow:(BOOL)arrow; 34 | clip代表圆内是否剪切 arrow代表是否有三角箭头 35 | 36 | 1.包含框架文件:(FrameWork) 37 | 2.在使用到的控制器中实现以下方法: 38 | - (void)viewDidLoad { 39 | [super viewDidLoad]; 40 | // Do any additional setup after loading the view. 41 | 42 | // 解锁界面 默认clip:YES, arrow:YES 43 | PCCircleView *lockView = [[PCCircleView alloc] init]; 44 | lockView.delegate = self; 45 | self.lockView = lockView; 46 | [self.view addSubview:lockView]; 47 | } 48 | 49 | #pragma - mark - circleView - delegate 50 | #pragma mark - circleView - delegate - setting 51 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type connectCirclesLessThanNeedWithGesture:(NSString *)gesture 52 | { 53 | NSString *gestureOne = [PCCircleViewConst getGestureWithKey:gestureOneSaveKey]; 54 | 55 | // 看是否存在第一个密码 56 | if ([gestureOne length]) { 57 | NSLog(@"提示再次绘制之前绘制的第一个手势密码"); 58 | } else { 59 | NSLog(@"密码长度不合法%@", gesture); 60 | } 61 | } 62 | 63 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteSetFirstGesture:(NSString *)gesture 64 | { 65 | NSLog(@"获得第一个手势密码%@", gesture); 66 | // infoView展示对应选中的圆 67 | } 68 | 69 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteSetSecondGesture:(NSString *)gesture result:(BOOL)equal 70 | { 71 | NSLog(@"获得第二个手势密码%@",gesture); 72 | if (equal) { 73 | NSLog(@"两次手势匹配!可以进行本地化保存了"); 74 | 75 | } else { 76 | NSLog(@"两次手势不匹配!"); 77 | } 78 | } 79 | 80 | #pragma mark - circleView - delegate - login or verify gesture 81 | - (void)circleView:(PCCircleView *)view type:(CircleViewType)type didCompleteLoginGesture:(NSString *)gesture result:(BOOL)equal 82 | { 83 | // 此时的type有两种情况 Login or verify 84 | if (type == CircleViewTypeLogin) { 85 | if (equal) { 86 | NSLog(@"登陆成功!"); 87 | } else { 88 | NSLog(@"密码错误!"); 89 | } 90 | } else if (type == CircleViewTypeVerify) { 91 | 92 | if (equal) { 93 | NSLog(@"验证成功,跳转到设置手势界面"); 94 | 95 | } else { 96 | NSLog(@"原手势密码输入错误!"); 97 | 98 | } 99 | } 100 | } 101 | 102 | 103 | #PCGestureUnlock 手势解锁终结者 104 | ------------ 105 | 106 | --------------------------------------------------------------------------------