├── QRCode.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── QRCode.xccheckout │ └── xcuserdata │ │ ├── CHEN1.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── Mac_Mini.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ ├── CHEN1.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── QRCode.xcscheme │ │ └── xcschememanagement.plist │ └── Mac_Mini.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── QRCode.xcscheme │ └── xcschememanagement.plist ├── QRCode ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── CustomViewController.h ├── CustomViewController.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── QRCodeViewController.h ├── QRCodeViewController.m ├── WebViewController.h ├── WebViewController.m └── main.m ├── QRCodeTests ├── Info.plist └── QRCodeTests.m ├── QRCustom ├── QRItem.h ├── QRItem.m ├── QRMenu.h ├── QRMenu.m ├── QRView.h └── QRView.m ├── README.md ├── Resource ├── MBProgressHUD │ ├── MBProgressHUD+MJ.h │ ├── MBProgressHUD+MJ.m │ ├── MBProgressHUD.bundle │ │ ├── error.png │ │ ├── error@2x.png │ │ ├── success.png │ │ └── success@2x.png │ ├── MBProgressHUD.h │ └── MBProgressHUD.m └── qr_scan_line@2x.png └── SampleImage ├── IMG_0023.PNG └── IMG_0024.PNG /QRCode.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 58A144561BA7D97A0066948D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A144551BA7D97A0066948D /* main.m */; }; 11 | 58A144591BA7D97A0066948D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A144581BA7D97A0066948D /* AppDelegate.m */; }; 12 | 58A1445C1BA7D97A0066948D /* CustomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A1445B1BA7D97A0066948D /* CustomViewController.m */; }; 13 | 58A1445F1BA7D97A0066948D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 58A1445D1BA7D97A0066948D /* Main.storyboard */; }; 14 | 58A144611BA7D97A0066948D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 58A144601BA7D97A0066948D /* Images.xcassets */; }; 15 | 58A144641BA7D97A0066948D /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 58A144621BA7D97A0066948D /* LaunchScreen.xib */; }; 16 | 58A144701BA7D97A0066948D /* QRCodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A1446F1BA7D97A0066948D /* QRCodeTests.m */; }; 17 | 58A144821BA7D9F30066948D /* MBProgressHUD+MJ.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A1447D1BA7D9F30066948D /* MBProgressHUD+MJ.m */; }; 18 | 58A144831BA7D9F30066948D /* MBProgressHUD.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 58A1447E1BA7D9F30066948D /* MBProgressHUD.bundle */; }; 19 | 58A144841BA7D9F30066948D /* MBProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A144801BA7D9F30066948D /* MBProgressHUD.m */; }; 20 | 58A144851BA7D9F30066948D /* qr_scan_line@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 58A144811BA7D9F30066948D /* qr_scan_line@2x.png */; }; 21 | 58A1448E1BA7DA5E0066948D /* QRItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A144891BA7DA5E0066948D /* QRItem.m */; }; 22 | 58A1448F1BA7DA5E0066948D /* QRMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A1448B1BA7DA5E0066948D /* QRMenu.m */; }; 23 | 58A144901BA7DA5E0066948D /* QRView.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A1448D1BA7DA5E0066948D /* QRView.m */; }; 24 | 58A144931BA7DC400066948D /* QRCodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A144921BA7DC400066948D /* QRCodeViewController.m */; }; 25 | 58A144961BA7DCAF0066948D /* WebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58A144951BA7DCAF0066948D /* WebViewController.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 58A1446A1BA7D97A0066948D /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 58A144481BA7D97A0066948D /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 58A1444F1BA7D97A0066948D; 34 | remoteInfo = QRCode; 35 | }; 36 | /* End PBXContainerItemProxy section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 58A144501BA7D97A0066948D /* QRCode.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QRCode.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | 58A144541BA7D97A0066948D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | 58A144551BA7D97A0066948D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | 58A144571BA7D97A0066948D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 43 | 58A144581BA7D97A0066948D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 44 | 58A1445A1BA7D97A0066948D /* CustomViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomViewController.h; sourceTree = ""; }; 45 | 58A1445B1BA7D97A0066948D /* CustomViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CustomViewController.m; sourceTree = ""; }; 46 | 58A1445E1BA7D97A0066948D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 47 | 58A144601BA7D97A0066948D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 48 | 58A144631BA7D97A0066948D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 49 | 58A144691BA7D97A0066948D /* QRCodeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QRCodeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 58A1446E1BA7D97A0066948D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | 58A1446F1BA7D97A0066948D /* QRCodeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QRCodeTests.m; sourceTree = ""; }; 52 | 58A1447C1BA7D9F30066948D /* MBProgressHUD+MJ.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MBProgressHUD+MJ.h"; sourceTree = ""; }; 53 | 58A1447D1BA7D9F30066948D /* MBProgressHUD+MJ.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MBProgressHUD+MJ.m"; sourceTree = ""; }; 54 | 58A1447E1BA7D9F30066948D /* MBProgressHUD.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = MBProgressHUD.bundle; sourceTree = ""; }; 55 | 58A1447F1BA7D9F30066948D /* MBProgressHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBProgressHUD.h; sourceTree = ""; }; 56 | 58A144801BA7D9F30066948D /* MBProgressHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBProgressHUD.m; sourceTree = ""; }; 57 | 58A144811BA7D9F30066948D /* qr_scan_line@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "qr_scan_line@2x.png"; sourceTree = ""; }; 58 | 58A144881BA7DA5E0066948D /* QRItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRItem.h; sourceTree = ""; }; 59 | 58A144891BA7DA5E0066948D /* QRItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRItem.m; sourceTree = ""; }; 60 | 58A1448A1BA7DA5E0066948D /* QRMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRMenu.h; sourceTree = ""; }; 61 | 58A1448B1BA7DA5E0066948D /* QRMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRMenu.m; sourceTree = ""; }; 62 | 58A1448C1BA7DA5E0066948D /* QRView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRView.h; sourceTree = ""; }; 63 | 58A1448D1BA7DA5E0066948D /* QRView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRView.m; sourceTree = ""; }; 64 | 58A144911BA7DC400066948D /* QRCodeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeViewController.h; sourceTree = ""; }; 65 | 58A144921BA7DC400066948D /* QRCodeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeViewController.m; sourceTree = ""; }; 66 | 58A144941BA7DCAF0066948D /* WebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewController.h; sourceTree = ""; }; 67 | 58A144951BA7DCAF0066948D /* WebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewController.m; sourceTree = ""; }; 68 | /* End PBXFileReference section */ 69 | 70 | /* Begin PBXFrameworksBuildPhase section */ 71 | 58A1444D1BA7D97A0066948D /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | 58A144661BA7D97A0066948D /* Frameworks */ = { 79 | isa = PBXFrameworksBuildPhase; 80 | buildActionMask = 2147483647; 81 | files = ( 82 | ); 83 | runOnlyForDeploymentPostprocessing = 0; 84 | }; 85 | /* End PBXFrameworksBuildPhase section */ 86 | 87 | /* Begin PBXGroup section */ 88 | 58A144471BA7D97A0066948D = { 89 | isa = PBXGroup; 90 | children = ( 91 | 58A144871BA7DA510066948D /* QRCustom */, 92 | 58A1447A1BA7D9F30066948D /* Resource */, 93 | 58A144521BA7D97A0066948D /* QRCode */, 94 | 58A1446C1BA7D97A0066948D /* QRCodeTests */, 95 | 58A144511BA7D97A0066948D /* Products */, 96 | ); 97 | sourceTree = ""; 98 | }; 99 | 58A144511BA7D97A0066948D /* Products */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 58A144501BA7D97A0066948D /* QRCode.app */, 103 | 58A144691BA7D97A0066948D /* QRCodeTests.xctest */, 104 | ); 105 | name = Products; 106 | sourceTree = ""; 107 | }; 108 | 58A144521BA7D97A0066948D /* QRCode */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 58A144571BA7D97A0066948D /* AppDelegate.h */, 112 | 58A144581BA7D97A0066948D /* AppDelegate.m */, 113 | 58A1445A1BA7D97A0066948D /* CustomViewController.h */, 114 | 58A1445B1BA7D97A0066948D /* CustomViewController.m */, 115 | 58A144911BA7DC400066948D /* QRCodeViewController.h */, 116 | 58A144921BA7DC400066948D /* QRCodeViewController.m */, 117 | 58A144941BA7DCAF0066948D /* WebViewController.h */, 118 | 58A144951BA7DCAF0066948D /* WebViewController.m */, 119 | 58A1445D1BA7D97A0066948D /* Main.storyboard */, 120 | 58A144601BA7D97A0066948D /* Images.xcassets */, 121 | 58A144621BA7D97A0066948D /* LaunchScreen.xib */, 122 | 58A144531BA7D97A0066948D /* Supporting Files */, 123 | ); 124 | path = QRCode; 125 | sourceTree = ""; 126 | }; 127 | 58A144531BA7D97A0066948D /* Supporting Files */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 58A144541BA7D97A0066948D /* Info.plist */, 131 | 58A144551BA7D97A0066948D /* main.m */, 132 | ); 133 | name = "Supporting Files"; 134 | sourceTree = ""; 135 | }; 136 | 58A1446C1BA7D97A0066948D /* QRCodeTests */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 58A1446F1BA7D97A0066948D /* QRCodeTests.m */, 140 | 58A1446D1BA7D97A0066948D /* Supporting Files */, 141 | ); 142 | path = QRCodeTests; 143 | sourceTree = ""; 144 | }; 145 | 58A1446D1BA7D97A0066948D /* Supporting Files */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 58A1446E1BA7D97A0066948D /* Info.plist */, 149 | ); 150 | name = "Supporting Files"; 151 | sourceTree = ""; 152 | }; 153 | 58A1447A1BA7D9F30066948D /* Resource */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 58A1447B1BA7D9F30066948D /* MBProgressHUD */, 157 | 58A144811BA7D9F30066948D /* qr_scan_line@2x.png */, 158 | ); 159 | path = Resource; 160 | sourceTree = ""; 161 | }; 162 | 58A1447B1BA7D9F30066948D /* MBProgressHUD */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 58A1447C1BA7D9F30066948D /* MBProgressHUD+MJ.h */, 166 | 58A1447D1BA7D9F30066948D /* MBProgressHUD+MJ.m */, 167 | 58A1447E1BA7D9F30066948D /* MBProgressHUD.bundle */, 168 | 58A1447F1BA7D9F30066948D /* MBProgressHUD.h */, 169 | 58A144801BA7D9F30066948D /* MBProgressHUD.m */, 170 | ); 171 | path = MBProgressHUD; 172 | sourceTree = ""; 173 | }; 174 | 58A144871BA7DA510066948D /* QRCustom */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 58A144881BA7DA5E0066948D /* QRItem.h */, 178 | 58A144891BA7DA5E0066948D /* QRItem.m */, 179 | 58A1448A1BA7DA5E0066948D /* QRMenu.h */, 180 | 58A1448B1BA7DA5E0066948D /* QRMenu.m */, 181 | 58A1448C1BA7DA5E0066948D /* QRView.h */, 182 | 58A1448D1BA7DA5E0066948D /* QRView.m */, 183 | ); 184 | path = QRCustom; 185 | sourceTree = ""; 186 | }; 187 | /* End PBXGroup section */ 188 | 189 | /* Begin PBXNativeTarget section */ 190 | 58A1444F1BA7D97A0066948D /* QRCode */ = { 191 | isa = PBXNativeTarget; 192 | buildConfigurationList = 58A144731BA7D97A0066948D /* Build configuration list for PBXNativeTarget "QRCode" */; 193 | buildPhases = ( 194 | 58A1444C1BA7D97A0066948D /* Sources */, 195 | 58A1444D1BA7D97A0066948D /* Frameworks */, 196 | 58A1444E1BA7D97A0066948D /* Resources */, 197 | ); 198 | buildRules = ( 199 | ); 200 | dependencies = ( 201 | ); 202 | name = QRCode; 203 | productName = QRCode; 204 | productReference = 58A144501BA7D97A0066948D /* QRCode.app */; 205 | productType = "com.apple.product-type.application"; 206 | }; 207 | 58A144681BA7D97A0066948D /* QRCodeTests */ = { 208 | isa = PBXNativeTarget; 209 | buildConfigurationList = 58A144761BA7D97A0066948D /* Build configuration list for PBXNativeTarget "QRCodeTests" */; 210 | buildPhases = ( 211 | 58A144651BA7D97A0066948D /* Sources */, 212 | 58A144661BA7D97A0066948D /* Frameworks */, 213 | 58A144671BA7D97A0066948D /* Resources */, 214 | ); 215 | buildRules = ( 216 | ); 217 | dependencies = ( 218 | 58A1446B1BA7D97A0066948D /* PBXTargetDependency */, 219 | ); 220 | name = QRCodeTests; 221 | productName = QRCodeTests; 222 | productReference = 58A144691BA7D97A0066948D /* QRCodeTests.xctest */; 223 | productType = "com.apple.product-type.bundle.unit-test"; 224 | }; 225 | /* End PBXNativeTarget section */ 226 | 227 | /* Begin PBXProject section */ 228 | 58A144481BA7D97A0066948D /* Project object */ = { 229 | isa = PBXProject; 230 | attributes = { 231 | LastUpgradeCheck = 0640; 232 | ORGANIZATIONNAME = 33e9; 233 | TargetAttributes = { 234 | 58A1444F1BA7D97A0066948D = { 235 | CreatedOnToolsVersion = 6.4; 236 | }; 237 | 58A144681BA7D97A0066948D = { 238 | CreatedOnToolsVersion = 6.4; 239 | TestTargetID = 58A1444F1BA7D97A0066948D; 240 | }; 241 | }; 242 | }; 243 | buildConfigurationList = 58A1444B1BA7D97A0066948D /* Build configuration list for PBXProject "QRCode" */; 244 | compatibilityVersion = "Xcode 3.2"; 245 | developmentRegion = English; 246 | hasScannedForEncodings = 0; 247 | knownRegions = ( 248 | en, 249 | Base, 250 | ); 251 | mainGroup = 58A144471BA7D97A0066948D; 252 | productRefGroup = 58A144511BA7D97A0066948D /* Products */; 253 | projectDirPath = ""; 254 | projectRoot = ""; 255 | targets = ( 256 | 58A1444F1BA7D97A0066948D /* QRCode */, 257 | 58A144681BA7D97A0066948D /* QRCodeTests */, 258 | ); 259 | }; 260 | /* End PBXProject section */ 261 | 262 | /* Begin PBXResourcesBuildPhase section */ 263 | 58A1444E1BA7D97A0066948D /* Resources */ = { 264 | isa = PBXResourcesBuildPhase; 265 | buildActionMask = 2147483647; 266 | files = ( 267 | 58A1445F1BA7D97A0066948D /* Main.storyboard in Resources */, 268 | 58A144831BA7D9F30066948D /* MBProgressHUD.bundle in Resources */, 269 | 58A144851BA7D9F30066948D /* qr_scan_line@2x.png in Resources */, 270 | 58A144641BA7D97A0066948D /* LaunchScreen.xib in Resources */, 271 | 58A144611BA7D97A0066948D /* Images.xcassets in Resources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | 58A144671BA7D97A0066948D /* Resources */ = { 276 | isa = PBXResourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | /* End PBXResourcesBuildPhase section */ 283 | 284 | /* Begin PBXSourcesBuildPhase section */ 285 | 58A1444C1BA7D97A0066948D /* Sources */ = { 286 | isa = PBXSourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | 58A144821BA7D9F30066948D /* MBProgressHUD+MJ.m in Sources */, 290 | 58A144961BA7DCAF0066948D /* WebViewController.m in Sources */, 291 | 58A144901BA7DA5E0066948D /* QRView.m in Sources */, 292 | 58A1445C1BA7D97A0066948D /* CustomViewController.m in Sources */, 293 | 58A1448F1BA7DA5E0066948D /* QRMenu.m in Sources */, 294 | 58A144931BA7DC400066948D /* QRCodeViewController.m in Sources */, 295 | 58A144841BA7D9F30066948D /* MBProgressHUD.m in Sources */, 296 | 58A1448E1BA7DA5E0066948D /* QRItem.m in Sources */, 297 | 58A144591BA7D97A0066948D /* AppDelegate.m in Sources */, 298 | 58A144561BA7D97A0066948D /* main.m in Sources */, 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | 58A144651BA7D97A0066948D /* Sources */ = { 303 | isa = PBXSourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | 58A144701BA7D97A0066948D /* QRCodeTests.m in Sources */, 307 | ); 308 | runOnlyForDeploymentPostprocessing = 0; 309 | }; 310 | /* End PBXSourcesBuildPhase section */ 311 | 312 | /* Begin PBXTargetDependency section */ 313 | 58A1446B1BA7D97A0066948D /* PBXTargetDependency */ = { 314 | isa = PBXTargetDependency; 315 | target = 58A1444F1BA7D97A0066948D /* QRCode */; 316 | targetProxy = 58A1446A1BA7D97A0066948D /* PBXContainerItemProxy */; 317 | }; 318 | /* End PBXTargetDependency section */ 319 | 320 | /* Begin PBXVariantGroup section */ 321 | 58A1445D1BA7D97A0066948D /* Main.storyboard */ = { 322 | isa = PBXVariantGroup; 323 | children = ( 324 | 58A1445E1BA7D97A0066948D /* Base */, 325 | ); 326 | name = Main.storyboard; 327 | sourceTree = ""; 328 | }; 329 | 58A144621BA7D97A0066948D /* LaunchScreen.xib */ = { 330 | isa = PBXVariantGroup; 331 | children = ( 332 | 58A144631BA7D97A0066948D /* Base */, 333 | ); 334 | name = LaunchScreen.xib; 335 | sourceTree = ""; 336 | }; 337 | /* End PBXVariantGroup section */ 338 | 339 | /* Begin XCBuildConfiguration section */ 340 | 58A144711BA7D97A0066948D /* Debug */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | ALWAYS_SEARCH_USER_PATHS = NO; 344 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 345 | CLANG_CXX_LIBRARY = "libc++"; 346 | CLANG_ENABLE_MODULES = YES; 347 | CLANG_ENABLE_OBJC_ARC = YES; 348 | CLANG_WARN_BOOL_CONVERSION = YES; 349 | CLANG_WARN_CONSTANT_CONVERSION = YES; 350 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 351 | CLANG_WARN_EMPTY_BODY = YES; 352 | CLANG_WARN_ENUM_CONVERSION = YES; 353 | CLANG_WARN_INT_CONVERSION = YES; 354 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 355 | CLANG_WARN_UNREACHABLE_CODE = YES; 356 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 357 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 358 | COPY_PHASE_STRIP = NO; 359 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 360 | ENABLE_STRICT_OBJC_MSGSEND = YES; 361 | GCC_C_LANGUAGE_STANDARD = gnu99; 362 | GCC_DYNAMIC_NO_PIC = NO; 363 | GCC_NO_COMMON_BLOCKS = YES; 364 | GCC_OPTIMIZATION_LEVEL = 0; 365 | GCC_PREPROCESSOR_DEFINITIONS = ( 366 | "DEBUG=1", 367 | "$(inherited)", 368 | ); 369 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 370 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 371 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 372 | GCC_WARN_UNDECLARED_SELECTOR = YES; 373 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 374 | GCC_WARN_UNUSED_FUNCTION = YES; 375 | GCC_WARN_UNUSED_VARIABLE = YES; 376 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 377 | MTL_ENABLE_DEBUG_INFO = YES; 378 | ONLY_ACTIVE_ARCH = YES; 379 | SDKROOT = iphoneos; 380 | }; 381 | name = Debug; 382 | }; 383 | 58A144721BA7D97A0066948D /* Release */ = { 384 | isa = XCBuildConfiguration; 385 | buildSettings = { 386 | ALWAYS_SEARCH_USER_PATHS = NO; 387 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 388 | CLANG_CXX_LIBRARY = "libc++"; 389 | CLANG_ENABLE_MODULES = YES; 390 | CLANG_ENABLE_OBJC_ARC = YES; 391 | CLANG_WARN_BOOL_CONVERSION = YES; 392 | CLANG_WARN_CONSTANT_CONVERSION = YES; 393 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 394 | CLANG_WARN_EMPTY_BODY = YES; 395 | CLANG_WARN_ENUM_CONVERSION = YES; 396 | CLANG_WARN_INT_CONVERSION = YES; 397 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 398 | CLANG_WARN_UNREACHABLE_CODE = YES; 399 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 400 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 401 | COPY_PHASE_STRIP = NO; 402 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 403 | ENABLE_NS_ASSERTIONS = NO; 404 | ENABLE_STRICT_OBJC_MSGSEND = YES; 405 | GCC_C_LANGUAGE_STANDARD = gnu99; 406 | GCC_NO_COMMON_BLOCKS = YES; 407 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 408 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 409 | GCC_WARN_UNDECLARED_SELECTOR = YES; 410 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 411 | GCC_WARN_UNUSED_FUNCTION = YES; 412 | GCC_WARN_UNUSED_VARIABLE = YES; 413 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 414 | MTL_ENABLE_DEBUG_INFO = NO; 415 | SDKROOT = iphoneos; 416 | VALIDATE_PRODUCT = YES; 417 | }; 418 | name = Release; 419 | }; 420 | 58A144741BA7D97A0066948D /* Debug */ = { 421 | isa = XCBuildConfiguration; 422 | buildSettings = { 423 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 424 | INFOPLIST_FILE = QRCode/Info.plist; 425 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 426 | PRODUCT_NAME = "$(TARGET_NAME)"; 427 | }; 428 | name = Debug; 429 | }; 430 | 58A144751BA7D97A0066948D /* Release */ = { 431 | isa = XCBuildConfiguration; 432 | buildSettings = { 433 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 434 | INFOPLIST_FILE = QRCode/Info.plist; 435 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 436 | PRODUCT_NAME = "$(TARGET_NAME)"; 437 | }; 438 | name = Release; 439 | }; 440 | 58A144771BA7D97A0066948D /* Debug */ = { 441 | isa = XCBuildConfiguration; 442 | buildSettings = { 443 | BUNDLE_LOADER = "$(TEST_HOST)"; 444 | FRAMEWORK_SEARCH_PATHS = ( 445 | "$(SDKROOT)/Developer/Library/Frameworks", 446 | "$(inherited)", 447 | ); 448 | GCC_PREPROCESSOR_DEFINITIONS = ( 449 | "DEBUG=1", 450 | "$(inherited)", 451 | ); 452 | INFOPLIST_FILE = QRCodeTests/Info.plist; 453 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 454 | PRODUCT_NAME = "$(TARGET_NAME)"; 455 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/QRCode.app/QRCode"; 456 | }; 457 | name = Debug; 458 | }; 459 | 58A144781BA7D97A0066948D /* Release */ = { 460 | isa = XCBuildConfiguration; 461 | buildSettings = { 462 | BUNDLE_LOADER = "$(TEST_HOST)"; 463 | FRAMEWORK_SEARCH_PATHS = ( 464 | "$(SDKROOT)/Developer/Library/Frameworks", 465 | "$(inherited)", 466 | ); 467 | INFOPLIST_FILE = QRCodeTests/Info.plist; 468 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 469 | PRODUCT_NAME = "$(TARGET_NAME)"; 470 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/QRCode.app/QRCode"; 471 | }; 472 | name = Release; 473 | }; 474 | /* End XCBuildConfiguration section */ 475 | 476 | /* Begin XCConfigurationList section */ 477 | 58A1444B1BA7D97A0066948D /* Build configuration list for PBXProject "QRCode" */ = { 478 | isa = XCConfigurationList; 479 | buildConfigurations = ( 480 | 58A144711BA7D97A0066948D /* Debug */, 481 | 58A144721BA7D97A0066948D /* Release */, 482 | ); 483 | defaultConfigurationIsVisible = 0; 484 | defaultConfigurationName = Release; 485 | }; 486 | 58A144731BA7D97A0066948D /* Build configuration list for PBXNativeTarget "QRCode" */ = { 487 | isa = XCConfigurationList; 488 | buildConfigurations = ( 489 | 58A144741BA7D97A0066948D /* Debug */, 490 | 58A144751BA7D97A0066948D /* Release */, 491 | ); 492 | defaultConfigurationIsVisible = 0; 493 | }; 494 | 58A144761BA7D97A0066948D /* Build configuration list for PBXNativeTarget "QRCodeTests" */ = { 495 | isa = XCConfigurationList; 496 | buildConfigurations = ( 497 | 58A144771BA7D97A0066948D /* Debug */, 498 | 58A144781BA7D97A0066948D /* Release */, 499 | ); 500 | defaultConfigurationIsVisible = 0; 501 | }; 502 | /* End XCConfigurationList section */ 503 | }; 504 | rootObject = 58A144481BA7D97A0066948D /* Project object */; 505 | } 506 | -------------------------------------------------------------------------------- /QRCode.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /QRCode.xcodeproj/project.xcworkspace/xcshareddata/QRCode.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | EC848D78-E425-4C76-AF76-027732D105B1 9 | IDESourceControlProjectName 10 | QRCode 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | DE1ED0E37A46E3F088B11B1884E1D6D8D6CC78FC 14 | https://github.com/chenxuhunoc/QRCode_CopyQQ.git 15 | 16 | IDESourceControlProjectPath 17 | QRCode.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | DE1ED0E37A46E3F088B11B1884E1D6D8D6CC78FC 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/chenxuhunoc/QRCode_CopyQQ.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | DE1ED0E37A46E3F088B11B1884E1D6D8D6CC78FC 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | DE1ED0E37A46E3F088B11B1884E1D6D8D6CC78FC 36 | IDESourceControlWCCName 37 | QRCode_CopyQQ 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /QRCode.xcodeproj/project.xcworkspace/xcuserdata/CHEN1.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenxuhunoc/QRCode/8f89f110d8ae65c8a52f15c5f82ab356d42940bc/QRCode.xcodeproj/project.xcworkspace/xcuserdata/CHEN1.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /QRCode.xcodeproj/project.xcworkspace/xcuserdata/Mac_Mini.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenxuhunoc/QRCode/8f89f110d8ae65c8a52f15c5f82ab356d42940bc/QRCode.xcodeproj/project.xcworkspace/xcuserdata/Mac_Mini.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /QRCode.xcodeproj/project.xcworkspace/xcuserdata/Mac_Mini.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /QRCode.xcodeproj/xcuserdata/CHEN1.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /QRCode.xcodeproj/xcuserdata/CHEN1.xcuserdatad/xcschemes/QRCode.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 | -------------------------------------------------------------------------------- /QRCode.xcodeproj/xcuserdata/CHEN1.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | QRCode.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 58A1444F1BA7D97A0066948D 16 | 17 | primary 18 | 19 | 20 | 58A144681BA7D97A0066948D 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /QRCode.xcodeproj/xcuserdata/Mac_Mini.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /QRCode.xcodeproj/xcuserdata/Mac_Mini.xcuserdatad/xcschemes/QRCode.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 | -------------------------------------------------------------------------------- /QRCode.xcodeproj/xcuserdata/Mac_Mini.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | QRCode.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 58A1444F1BA7D97A0066948D 16 | 17 | primary 18 | 19 | 20 | 58A144681BA7D97A0066948D 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /QRCode/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. 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 | -------------------------------------------------------------------------------- /QRCode/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. 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 | -------------------------------------------------------------------------------- /QRCode/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 | -------------------------------------------------------------------------------- /QRCode/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /QRCode/CustomViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CustomViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /QRCode/CustomViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import "CustomViewController.h" 10 | #import "QRCodeViewController.h" 11 | @interface CustomViewController () 12 | 13 | @end 14 | 15 | @implementation CustomViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view, typically from a nib. 20 | 21 | UIButton *openQRBtn = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.origin.x + 100, self.view.frame.origin.y + 250, 150, 40)]; 22 | openQRBtn.backgroundColor = [UIColor grayColor]; 23 | [openQRBtn setTitle:@"Open QRCode" forState:UIControlStateNormal]; 24 | [openQRBtn addTarget:self action:@selector(validateCanmere:) forControlEvents:UIControlEventTouchUpInside]; 25 | [self.view addSubview:openQRBtn]; 26 | 27 | } 28 | 29 | -(void)validateCanmere:(UIButton *)validate 30 | { 31 | if ([self validateCamera]) { 32 | 33 | [self showQRViewController]; 34 | 35 | } else { 36 | 37 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"没有摄像头或摄像头不可用" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; 38 | [alertView show]; 39 | } 40 | } 41 | 42 | - (BOOL)validateCamera { 43 | 44 | return [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] && 45 | [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]; 46 | } 47 | 48 | - (void)showQRViewController { 49 | 50 | QRCodeViewController *qrVC = [[QRCodeViewController alloc] init]; 51 | [self.navigationController pushViewController:qrVC animated:YES]; 52 | } 53 | 54 | 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /QRCode/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 | } -------------------------------------------------------------------------------- /QRCode/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | Chenxuhun.$(PRODUCT_NAME:rfc1034identifier) 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 | -------------------------------------------------------------------------------- /QRCode/QRCodeViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomViewController.h 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef void(^QRUrlBlock)(NSString *url); 12 | @interface QRCodeViewController : UIViewController 13 | 14 | @property (nonatomic, copy) QRUrlBlock qrUrlBlock; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /QRCode/QRCodeViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomViewController.m 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import "QRCodeViewController.h" 10 | #import 11 | #import "QRView.h" 12 | #import "WebViewController.h" 13 | @interface QRCodeViewController () 14 | 15 | @property (strong, nonatomic) AVCaptureDevice * device; 16 | @property (strong, nonatomic) AVCaptureDeviceInput * input; 17 | @property (strong, nonatomic) AVCaptureMetadataOutput * output; 18 | @property (strong, nonatomic) AVCaptureSession * session; 19 | @property (strong, nonatomic) AVCaptureVideoPreviewLayer * preview; 20 | 21 | @end 22 | 23 | @implementation QRCodeViewController 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | // Do any additional setup after loading the view. 28 | 29 | self.title = @"扫一扫"; 30 | 31 | _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 32 | 33 | // Input 34 | _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil]; 35 | 36 | // Output 37 | _output = [[AVCaptureMetadataOutput alloc]init]; 38 | [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; 39 | 40 | // Session 41 | _session = [[AVCaptureSession alloc]init]; 42 | [_session setSessionPreset:AVCaptureSessionPresetHigh]; 43 | if ([_session canAddInput:self.input]) 44 | { 45 | [_session addInput:self.input]; 46 | } 47 | 48 | if ([_session canAddOutput:self.output]) 49 | { 50 | [_session addOutput:self.output]; 51 | } 52 | 53 | // 条码类型 AVMetadataObjectTypeQRCode 54 | _output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode]; 55 | 56 | //增加条形码扫描 57 | // _output.metadataObjectTypes = @[AVMetadataObjectTypeEAN13Code, 58 | // AVMetadataObjectTypeEAN8Code, 59 | // AVMetadataObjectTypeCode128Code, 60 | // AVMetadataObjectTypeQRCode]; 61 | 62 | // Preview 63 | _preview =[AVCaptureVideoPreviewLayer layerWithSession:_session]; 64 | _preview.videoGravity =AVLayerVideoGravityResize; 65 | _preview.frame =self.view.layer.bounds; 66 | [self.view.layer insertSublayer:_preview atIndex:0]; 67 | 68 | [_session startRunning]; 69 | 70 | 71 | CGRect screenRect = [UIScreen mainScreen].bounds; 72 | QRView *qrRectView = [[QRView alloc] initWithFrame:screenRect]; 73 | qrRectView.transparentArea = CGSizeMake(200, 200); 74 | qrRectView.backgroundColor = [UIColor clearColor]; 75 | qrRectView.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2); 76 | qrRectView.delegate = self; 77 | [self.view addSubview:qrRectView]; 78 | 79 | UIButton *openBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 80 | openBtn.frame = CGRectMake(260, 0, 50, 50); 81 | [openBtn setTitle:@"开灯" forState:UIControlStateNormal]; 82 | [openBtn addTarget:self action:@selector(openFlashlight:) forControlEvents:UIControlEventTouchUpInside]; 83 | [openBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 84 | 85 | UIBarButtonItem *openItem = [[UIBarButtonItem alloc] initWithCustomView:openBtn]; 86 | 87 | self.navigationItem.rightBarButtonItem = openItem; 88 | 89 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(90, 65, 150, 60)]; 90 | label.textAlignment = NSTextAlignmentCenter; 91 | label.numberOfLines = 2; 92 | label.font = [UIFont systemFontOfSize:18]; 93 | label.text = @"将取景框对准二维码即可自动扫描"; 94 | label.textColor = [UIColor whiteColor]; 95 | [self.view addSubview:label]; 96 | 97 | //修正扫描区域 98 | CGFloat screenHeight = self.view.frame.size.height; 99 | CGFloat screenWidth = self.view.frame.size.width; 100 | CGRect cropRect = CGRectMake((screenWidth - qrRectView.transparentArea.width) / 2, 101 | (screenHeight - qrRectView.transparentArea.height) / 2, 102 | qrRectView.transparentArea.width, 103 | qrRectView.transparentArea.height); 104 | 105 | [_output setRectOfInterest:CGRectMake(cropRect.origin.y / screenHeight, 106 | cropRect.origin.x / screenWidth, 107 | cropRect.size.height / screenHeight, 108 | cropRect.size.width / screenWidth)]; 109 | 110 | 111 | 112 | } 113 | 114 | -(void)openFlashlight:(UIButton *)sender 115 | { 116 | sender.selected = !sender.selected; 117 | Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice"); 118 | if (captureDeviceClass != nil) { 119 | AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 120 | if ([device hasTorch] && [device hasFlash]){ 121 | 122 | [device lockForConfiguration:nil]; 123 | if (sender.selected) { 124 | 125 | [sender setTitle:@"关灯" forState:UIControlStateNormal]; 126 | [device setTorchMode:AVCaptureTorchModeOn]; 127 | [device setFlashMode:AVCaptureFlashModeOn]; 128 | 129 | } else { 130 | 131 | [sender setTitle:@"开灯" forState:UIControlStateNormal]; 132 | [device setTorchMode:AVCaptureTorchModeOff]; 133 | [device setFlashMode:AVCaptureFlashModeOff]; 134 | 135 | } 136 | [device unlockForConfiguration]; 137 | } 138 | } 139 | } 140 | 141 | #pragma mark QRViewDelegate 142 | -(void)scanTypeConfig:(QRItem *)item { 143 | 144 | if (item.type == QRItemTypeQRCode) { 145 | _output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode]; 146 | 147 | } else if (item.type == QRItemTypeOther) { 148 | 149 | _output.metadataObjectTypes = @[AVMetadataObjectTypeEAN13Code, 150 | AVMetadataObjectTypeEAN8Code, 151 | AVMetadataObjectTypeCode128Code, 152 | AVMetadataObjectTypeQRCode]; 153 | } 154 | } 155 | #pragma mark AVCaptureMetadataOutputObjectsDelegate 156 | - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection 157 | { 158 | NSString *stringValue; 159 | if ([metadataObjects count] >0) 160 | { 161 | //停止扫描 162 | [_session stopRunning]; 163 | AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0]; 164 | stringValue = metadataObject.stringValue; 165 | } 166 | 167 | NSLog(@" =============%@",stringValue); 168 | 169 | if (self.qrUrlBlock) { 170 | self.qrUrlBlock(stringValue); 171 | } 172 | 173 | WebViewController *scanVC = [[WebViewController alloc]init]; 174 | scanVC.path = stringValue; 175 | [self.navigationController pushViewController:scanVC animated:YES]; 176 | [_session startRunning]; 177 | } 178 | 179 | @end 180 | -------------------------------------------------------------------------------- /QRCode/WebViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewController.h 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WebViewController : UIViewController 12 | @property (nonatomic ,copy)NSString *path; 13 | @end 14 | -------------------------------------------------------------------------------- /QRCode/WebViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewController.m 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import "WebViewController.h" 10 | #import "MBProgressHUD+MJ.h" 11 | @interface WebViewController () 12 | 13 | @end 14 | 15 | @implementation WebViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | self.title = @"浏览网址"; 21 | 22 | UIWebView *wv = [[UIWebView alloc]initWithFrame:self.view.bounds]; 23 | [self.view addSubview:wv]; 24 | wv.delegate = self; 25 | 26 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.path]]; 27 | NSLog(@"===%@",self.path); 28 | [wv loadRequest:request]; 29 | 30 | } 31 | 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /QRCode/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. 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 | -------------------------------------------------------------------------------- /QRCodeTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | Chenxuhun.$(PRODUCT_NAME:rfc1034identifier) 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 | -------------------------------------------------------------------------------- /QRCodeTests/QRCodeTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // QRCodeTests.m 3 | // QRCodeTests 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | #import 9 | #import 10 | 11 | @interface QRCodeTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation QRCodeTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | XCTAssert(YES, @"Pass"); 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /QRCustom/QRItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // QRItem.h 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | typedef NS_ENUM(NSUInteger, QRItemType) { 13 | QRItemTypeQRCode = 0, 14 | QRItemTypeOther, 15 | }; 16 | 17 | 18 | @interface QRItem : UIButton 19 | 20 | @property (nonatomic, assign) QRItemType type; 21 | 22 | - (instancetype)initWithFrame:(CGRect)frame 23 | titile:(NSString *)titile; 24 | @end 25 | -------------------------------------------------------------------------------- /QRCustom/QRItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // QRItem.m 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import "QRItem.h" 10 | #import 11 | 12 | @implementation QRItem 13 | 14 | /* 15 | // Only override drawRect: if you perform custom drawing. 16 | // An empty implementation adversely affects performance during animation. 17 | - (void)drawRect:(CGRect)rect { 18 | // Drawing code 19 | } 20 | */ 21 | 22 | 23 | - (instancetype)initWithFrame:(CGRect)frame 24 | titile:(NSString *)titile{ 25 | 26 | self = [QRItem buttonWithType:UIButtonTypeSystem]; 27 | if (self) { 28 | 29 | [self setTitle:titile forState:UIControlStateNormal]; 30 | self.frame = frame; 31 | } 32 | return self; 33 | } 34 | @end 35 | -------------------------------------------------------------------------------- /QRCustom/QRMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // QRMenu.h 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QRItem.h" 11 | 12 | typedef void(^QRMenuDidSelectedBlock)(QRItem *item); 13 | 14 | @interface QRMenu : UIView 15 | 16 | @property (nonatomic, copy) QRMenuDidSelectedBlock didSelectedBlock; 17 | 18 | - (instancetype)initWithFrame:(CGRect)frame; 19 | @end 20 | -------------------------------------------------------------------------------- /QRCustom/QRMenu.m: -------------------------------------------------------------------------------- 1 | // 2 | // QRMenu.m 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | #import "QRMenu.h" 9 | 10 | @implementation QRMenu 11 | 12 | /* 13 | // Only override drawRect: if you perform custom drawing. 14 | // An empty implementation adversely affects performance during animation. 15 | - (void)drawRect:(CGRect)rect { 16 | // Drawing code 17 | } 18 | */ 19 | 20 | - (instancetype)initWithFrame:(CGRect)frame { 21 | self = [super initWithFrame:frame]; 22 | if (self) { 23 | 24 | [self setupQRItem]; 25 | 26 | } 27 | 28 | return self; 29 | } 30 | 31 | - (void)setupQRItem { 32 | 33 | QRItem *qrItem = [[QRItem alloc] initWithFrame:(CGRect){ 34 | .origin.x = 0, 35 | .origin.y = 0, 36 | .size.width = self.bounds.size.width / 3, 37 | .size.height = self.bounds.size.height 38 | } titile:@"二维码扫描"]; 39 | qrItem.type = QRItemTypeQRCode; 40 | [self addSubview:qrItem]; 41 | 42 | QRItem *otherItem = [[QRItem alloc] initWithFrame: (CGRect){ 43 | 44 | .origin.x = self.bounds.size.width / 2, 45 | .origin.y = 0, 46 | .size.width = self.bounds.size.width / 2, 47 | .size.height = self.bounds.size.height 48 | } titile:@"条形码扫描"]; 49 | otherItem.type = QRItemTypeOther; 50 | [self addSubview:otherItem]; 51 | 52 | [qrItem addTarget:self action:@selector(qrScan:) forControlEvents:UIControlEventTouchUpInside]; 53 | [otherItem addTarget:self action:@selector(qrScan:) forControlEvents:UIControlEventTouchUpInside]; 54 | } 55 | 56 | 57 | #pragma mark - Action 58 | 59 | - (void)qrScan:(QRItem *)qrItem { 60 | 61 | if (self.didSelectedBlock) { 62 | 63 | self.didSelectedBlock(qrItem); 64 | } 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /QRCustom/QRView.h: -------------------------------------------------------------------------------- 1 | // 2 | // QRView.h 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QRMenu.h" 11 | 12 | @protocol QRViewDelegate 13 | 14 | -(void)scanTypeConfig:(QRItem *)item; 15 | 16 | @end 17 | @interface QRView : UIView 18 | 19 | 20 | @property (nonatomic, weak) id delegate; 21 | /** 22 | * 透明的区域 23 | */ 24 | @property (nonatomic, assign) CGSize transparentArea; 25 | @end 26 | -------------------------------------------------------------------------------- /QRCustom/QRView.m: -------------------------------------------------------------------------------- 1 | // 2 | // QRView.m 3 | // QRCode 4 | // 5 | // Created by Mac_Mini on 15/9/15. 6 | // Copyright (c) 2015年 Chenxuhun. All rights reserved. 7 | // 8 | 9 | #import "QRView.h" 10 | 11 | 12 | static NSTimeInterval kQrLineanimateDuration = 0.02; 13 | 14 | @implementation QRView { 15 | 16 | UIImageView *qrLine; 17 | CGFloat qrLineY; 18 | QRMenu *qrMenu; 19 | } 20 | 21 | - (instancetype)initWithFrame:(CGRect)frame { 22 | 23 | self = [super initWithFrame:frame]; 24 | if (self) { 25 | 26 | } 27 | return self; 28 | } 29 | 30 | 31 | - (void)layoutSubviews { 32 | 33 | [super layoutSubviews]; 34 | if (!qrLine) { 35 | 36 | [self initQRLine]; 37 | 38 | NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:kQrLineanimateDuration target:self selector:@selector(show) userInfo:nil repeats:YES]; 39 | [timer fire]; 40 | } 41 | 42 | if (!qrMenu) { 43 | [self initQrMenu]; 44 | } 45 | } 46 | 47 | - (void)initQRLine { 48 | 49 | 50 | qrLine = [[UIImageView alloc] initWithFrame:CGRectMake(self.bounds.size.width / 2 - self.transparentArea.width / 2, self.bounds.size.height / 2 - self.transparentArea.height / 2, self.transparentArea.width, 2)]; 51 | qrLine.image = [UIImage imageNamed:@"qr_scan_line"]; 52 | qrLine.contentMode = UIViewContentModeScaleAspectFill; 53 | [self addSubview:qrLine]; 54 | qrLineY = qrLine.frame.origin.y; 55 | } 56 | 57 | 58 | //底部TabBarView 59 | - (void)initQrMenu { 60 | 61 | CGFloat height = 80; 62 | CGFloat width = self.bounds.size.width; 63 | qrMenu = [[QRMenu alloc] initWithFrame:CGRectMake(0, self.bounds.size.height - height, width, height)]; 64 | qrMenu.backgroundColor = [UIColor yellowColor]; 65 | [self addSubview:qrMenu]; 66 | 67 | __weak typeof(self)weakSelf = self; 68 | 69 | qrMenu.didSelectedBlock = ^(QRItem *item){ 70 | 71 | NSLog(@"点击的是%lu",(unsigned long)item.type); 72 | 73 | if ([weakSelf.delegate respondsToSelector:@selector(scanTypeConfig:)] ) { 74 | 75 | [weakSelf.delegate scanTypeConfig:item]; 76 | } 77 | }; 78 | } 79 | 80 | - (void)show { 81 | 82 | [UIView animateWithDuration:kQrLineanimateDuration animations:^{ 83 | 84 | CGRect rect = qrLine.frame; 85 | rect.origin.y = qrLineY; 86 | qrLine.frame = rect; 87 | 88 | } completion:^(BOOL finished) { 89 | 90 | CGFloat maxBorder = self.frame.size.height / 2 + self.transparentArea.height / 2 - 4; 91 | if (qrLineY > maxBorder) { 92 | 93 | qrLineY = self.frame.size.height / 2 - self.transparentArea.height /2; 94 | } 95 | qrLineY++; 96 | }]; 97 | } 98 | 99 | - (void)drawRect:(CGRect)rect { 100 | 101 | //整个二维码扫描界面的颜色 102 | CGSize screenSize =[UIScreen mainScreen].bounds.size; 103 | CGRect screenDrawRect =CGRectMake(0, 0, screenSize.width,screenSize.height); 104 | 105 | //中间清空的矩形框 106 | CGRect clearDrawRect = CGRectMake(screenDrawRect.size.width / 2 - self.transparentArea.width / 2, 107 | screenDrawRect.size.height / 2 - self.transparentArea.height / 2, 108 | self.transparentArea.width,self.transparentArea.height); 109 | 110 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 111 | [self addScreenFillRect:ctx rect:screenDrawRect]; 112 | 113 | [self addCenterClearRect:ctx rect:clearDrawRect]; 114 | 115 | [self addWhiteRect:ctx rect:clearDrawRect]; 116 | 117 | [self addCornerLineWithContext:ctx rect:clearDrawRect]; 118 | 119 | 120 | } 121 | 122 | - (void)addScreenFillRect:(CGContextRef)ctx rect:(CGRect)rect { 123 | 124 | CGContextSetRGBFillColor(ctx, 40 / 255.0,40 / 255.0,40 / 255.0,0.5); 125 | CGContextFillRect(ctx, rect); //draw the transparent layer 126 | } 127 | 128 | - (void)addCenterClearRect :(CGContextRef)ctx rect:(CGRect)rect { 129 | 130 | CGContextClearRect(ctx, rect); //clear the center rect of the layer 131 | } 132 | 133 | - (void)addWhiteRect:(CGContextRef)ctx rect:(CGRect)rect { 134 | 135 | CGContextStrokeRect(ctx, rect); 136 | CGContextSetRGBStrokeColor(ctx, 1, 1, 1, 1); 137 | CGContextSetLineWidth(ctx, 0.8); 138 | CGContextAddRect(ctx, rect); 139 | CGContextStrokePath(ctx); 140 | } 141 | 142 | - (void)addCornerLineWithContext:(CGContextRef)ctx rect:(CGRect)rect{ 143 | 144 | //画四个边角 145 | CGContextSetLineWidth(ctx, 5); 146 | CGContextSetRGBStrokeColor(ctx, 83 /255.0, 239/255.0, 111/255.0, 1);//绿色 147 | 148 | //左上角 149 | CGPoint poinsTopLeftA[] = { 150 | CGPointMake(rect.origin.x+0.7, rect.origin.y), 151 | CGPointMake(rect.origin.x+0.7 , rect.origin.y + 15) 152 | }; 153 | 154 | CGPoint poinsTopLeftB[] = {CGPointMake(rect.origin.x, rect.origin.y +0.7),CGPointMake(rect.origin.x + 15, rect.origin.y+0.7)}; 155 | [self addLine:poinsTopLeftA pointB:poinsTopLeftB ctx:ctx]; 156 | 157 | //左下角 158 | CGPoint poinsBottomLeftA[] = {CGPointMake(rect.origin.x+ 0.7, rect.origin.y + rect.size.height - 15),CGPointMake(rect.origin.x +0.7,rect.origin.y + rect.size.height)}; 159 | CGPoint poinsBottomLeftB[] = {CGPointMake(rect.origin.x , rect.origin.y + rect.size.height - 0.7) ,CGPointMake(rect.origin.x+0.7 +15, rect.origin.y + rect.size.height - 0.7)}; 160 | [self addLine:poinsBottomLeftA pointB:poinsBottomLeftB ctx:ctx]; 161 | 162 | //右上角 163 | CGPoint poinsTopRightA[] = {CGPointMake(rect.origin.x+ rect.size.width - 15, rect.origin.y+0.7),CGPointMake(rect.origin.x + rect.size.width,rect.origin.y +0.7 )}; 164 | CGPoint poinsTopRightB[] = {CGPointMake(rect.origin.x+ rect.size.width-0.7, rect.origin.y),CGPointMake(rect.origin.x + rect.size.width-0.7,rect.origin.y + 15 +0.7 )}; 165 | [self addLine:poinsTopRightA pointB:poinsTopRightB ctx:ctx]; 166 | 167 | CGPoint poinsBottomRightA[] = {CGPointMake(rect.origin.x+ rect.size.width -0.7 , rect.origin.y+rect.size.height+ -15),CGPointMake(rect.origin.x-0.7 + rect.size.width,rect.origin.y +rect.size.height )}; 168 | CGPoint poinsBottomRightB[] = {CGPointMake(rect.origin.x+ rect.size.width - 15 , rect.origin.y + rect.size.height-0.7),CGPointMake(rect.origin.x + rect.size.width,rect.origin.y + rect.size.height - 0.7 )}; 169 | [self addLine:poinsBottomRightA pointB:poinsBottomRightB ctx:ctx]; 170 | CGContextStrokePath(ctx); 171 | } 172 | 173 | - (void)addLine:(CGPoint[])pointA pointB:(CGPoint[])pointB ctx:(CGContextRef)ctx { 174 | CGContextAddLines(ctx, pointA, 2); 175 | CGContextAddLines(ctx, pointB, 2); 176 | } 177 | 178 | 179 | @end 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QRCode 2 | 原生IOS二维码扫描,高仿QQ二维码扫描 3 | ![image](https://github.com/chenxuhunoc/QRCode/blob/master/SampleImage/IMG_0023.PNG) 4 | -------------------------------------------------------------------------------- /Resource/MBProgressHUD/MBProgressHUD+MJ.h: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD+MJ.h 3 | // 4 | // Created by mj on 13-4-18. 5 | // Copyright (c) 2013年 itcast. All rights reserved. 6 | // 7 | 8 | #import "MBProgressHUD.h" 9 | 10 | @interface MBProgressHUD (MJ) 11 | + (void)showSuccess:(NSString *)success toView:(UIView *)view; 12 | + (void)showError:(NSString *)error toView:(UIView *)view; 13 | 14 | + (MBProgressHUD *)showMessage:(NSString *)message toView:(UIView *)view; 15 | 16 | 17 | + (void)showSuccess:(NSString *)success; 18 | + (void)showError:(NSString *)error; 19 | 20 | + (MBProgressHUD *)showMessage:(NSString *)message; 21 | 22 | + (void)hideHUDForView:(UIView *)view; 23 | + (void)hideHUD; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Resource/MBProgressHUD/MBProgressHUD+MJ.m: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD+MJ.m 3 | // 4 | // Created by mj on 13-4-18. 5 | // Copyright (c) 2013年 itcast. All rights reserved. 6 | // 7 | 8 | #import "MBProgressHUD+MJ.h" 9 | 10 | @implementation MBProgressHUD (MJ) 11 | #pragma mark 显示信息 12 | + (void)show:(NSString *)text icon:(NSString *)icon view:(UIView *)view 13 | { 14 | if (view == nil) view = [[UIApplication sharedApplication].windows lastObject]; 15 | // 快速显示一个提示信息 16 | MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:view animated:YES]; 17 | hud.labelText = text; 18 | // 设置图片 19 | hud.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"MBProgressHUD.bundle/%@", icon]]]; 20 | // 再设置模式 21 | hud.mode = MBProgressHUDModeCustomView; 22 | 23 | // 隐藏时候从父控件中移除 24 | hud.removeFromSuperViewOnHide = YES; 25 | 26 | // 1秒之后再消失 27 | [hud hide:YES afterDelay:1]; 28 | } 29 | 30 | #pragma mark 显示错误信息 31 | + (void)showError:(NSString *)error toView:(UIView *)view{ 32 | [self show:error icon:@"" view:view]; 33 | } 34 | 35 | + (void)showSuccess:(NSString *)success toView:(UIView *)view 36 | { 37 | [self show:success icon:@"success.png" view:view]; 38 | } 39 | 40 | #pragma mark 显示一些信息 41 | + (MBProgressHUD *)showMessage:(NSString *)message toView:(UIView *)view { 42 | if (view == nil) view = [[UIApplication sharedApplication].windows lastObject]; 43 | // 快速显示一个提示信息 44 | MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:view animated:YES]; 45 | hud.labelText = message; 46 | // 隐藏时候从父控件中移除 47 | hud.removeFromSuperViewOnHide = YES; 48 | // YES代表需要蒙版效果 49 | hud.dimBackground = YES; 50 | return hud; 51 | } 52 | 53 | + (void)showSuccess:(NSString *)success 54 | { 55 | [self showSuccess:success toView:nil]; 56 | } 57 | 58 | + (void)showError:(NSString *)error 59 | { 60 | [self showError:error toView:nil]; 61 | } 62 | 63 | + (MBProgressHUD *)showMessage:(NSString *)message 64 | { 65 | return [self showMessage:message toView:nil]; 66 | } 67 | 68 | + (void)hideHUDForView:(UIView *)view 69 | { 70 | [self hideHUDForView:view animated:YES]; 71 | } 72 | 73 | + (void)hideHUD 74 | { 75 | [self hideHUDForView:nil]; 76 | } 77 | @end 78 | -------------------------------------------------------------------------------- /Resource/MBProgressHUD/MBProgressHUD.bundle/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenxuhunoc/QRCode/8f89f110d8ae65c8a52f15c5f82ab356d42940bc/Resource/MBProgressHUD/MBProgressHUD.bundle/error.png -------------------------------------------------------------------------------- /Resource/MBProgressHUD/MBProgressHUD.bundle/error@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenxuhunoc/QRCode/8f89f110d8ae65c8a52f15c5f82ab356d42940bc/Resource/MBProgressHUD/MBProgressHUD.bundle/error@2x.png -------------------------------------------------------------------------------- /Resource/MBProgressHUD/MBProgressHUD.bundle/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenxuhunoc/QRCode/8f89f110d8ae65c8a52f15c5f82ab356d42940bc/Resource/MBProgressHUD/MBProgressHUD.bundle/success.png -------------------------------------------------------------------------------- /Resource/MBProgressHUD/MBProgressHUD.bundle/success@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenxuhunoc/QRCode/8f89f110d8ae65c8a52f15c5f82ab356d42940bc/Resource/MBProgressHUD/MBProgressHUD.bundle/success@2x.png -------------------------------------------------------------------------------- /Resource/MBProgressHUD/MBProgressHUD.h: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD.h 3 | // Version 0.7 4 | // Created by Matej Bukovinski on 2.4.09. 5 | // 6 | 7 | // This code is distributed under the terms and conditions of the MIT license. 8 | 9 | // Copyright (c) 2013 Matej Bukovinski 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | 29 | #import 30 | #import 31 | #import 32 | 33 | @protocol MBProgressHUDDelegate; 34 | 35 | 36 | typedef enum { 37 | /** Progress is shown using an UIActivityIndicatorView. This is the default. */ 38 | MBProgressHUDModeIndeterminate, 39 | /** Progress is shown using a round, pie-chart like, progress view. */ 40 | MBProgressHUDModeDeterminate, 41 | /** Progress is shown using a horizontal progress bar */ 42 | MBProgressHUDModeDeterminateHorizontalBar, 43 | /** Progress is shown using a ring-shaped progress view. */ 44 | MBProgressHUDModeAnnularDeterminate, 45 | /** Shows a custom view */ 46 | MBProgressHUDModeCustomView, 47 | /** Shows only labels */ 48 | MBProgressHUDModeText 49 | } MBProgressHUDMode; 50 | 51 | typedef enum { 52 | /** Opacity animation */ 53 | MBProgressHUDAnimationFade, 54 | /** Opacity + scale animation */ 55 | MBProgressHUDAnimationZoom, 56 | MBProgressHUDAnimationZoomOut = MBProgressHUDAnimationZoom, 57 | MBProgressHUDAnimationZoomIn 58 | } MBProgressHUDAnimation; 59 | 60 | 61 | #ifndef MB_INSTANCETYPE 62 | #if __has_feature(objc_instancetype) 63 | #define MB_INSTANCETYPE instancetype 64 | #else 65 | #define MB_INSTANCETYPE id 66 | #endif 67 | #endif 68 | 69 | #ifndef MB_STRONG 70 | #if __has_feature(objc_arc) 71 | #define MB_STRONG strong 72 | #else 73 | #define MB_STRONG retain 74 | #endif 75 | #endif 76 | 77 | #ifndef MB_WEAK 78 | #if __has_feature(objc_arc_weak) 79 | #define MB_WEAK weak 80 | #elif __has_feature(objc_arc) 81 | #define MB_WEAK unsafe_unretained 82 | #else 83 | #define MB_WEAK assign 84 | #endif 85 | #endif 86 | 87 | #if NS_BLOCKS_AVAILABLE 88 | typedef void (^MBProgressHUDCompletionBlock)(); 89 | #endif 90 | 91 | 92 | /** 93 | * Displays a simple HUD window containing a progress indicator and two optional labels for short messages. 94 | * 95 | * This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class. 96 | * The MBProgressHUD window spans over the entire space given to it by the initWithFrame constructor and catches all 97 | * user input on this region, thereby preventing the user operations on components below the view. The HUD itself is 98 | * drawn centered as a rounded semi-transparent view which resizes depending on the user specified content. 99 | * 100 | * This view supports four modes of operation: 101 | * - MBProgressHUDModeIndeterminate - shows a UIActivityIndicatorView 102 | * - MBProgressHUDModeDeterminate - shows a custom round progress indicator 103 | * - MBProgressHUDModeAnnularDeterminate - shows a custom annular progress indicator 104 | * - MBProgressHUDModeCustomView - shows an arbitrary, user specified view (@see customView) 105 | * 106 | * All three modes can have optional labels assigned: 107 | * - If the labelText property is set and non-empty then a label containing the provided content is placed below the 108 | * indicator view. 109 | * - If also the detailsLabelText property is set then another label is placed below the first label. 110 | */ 111 | @interface MBProgressHUD : UIView 112 | 113 | /** 114 | * Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:. 115 | * 116 | * @param view The view that the HUD will be added to 117 | * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use 118 | * animations while appearing. 119 | * @return A reference to the created HUD. 120 | * 121 | * @see hideHUDForView:animated: 122 | * @see animationType 123 | */ 124 | + (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated; 125 | 126 | /** 127 | * Finds the top-most HUD subview and hides it. The counterpart to this method is showHUDAddedTo:animated:. 128 | * 129 | * @param view The view that is going to be searched for a HUD subview. 130 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 131 | * animations while disappearing. 132 | * @return YES if a HUD was found and removed, NO otherwise. 133 | * 134 | * @see showHUDAddedTo:animated: 135 | * @see animationType 136 | */ 137 | + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated; 138 | 139 | /** 140 | * Finds all the HUD subviews and hides them. 141 | * 142 | * @param view The view that is going to be searched for HUD subviews. 143 | * @param animated If set to YES the HUDs will disappear using the current animationType. If set to NO the HUDs will not use 144 | * animations while disappearing. 145 | * @return the number of HUDs found and removed. 146 | * 147 | * @see hideHUDForView:animated: 148 | * @see animationType 149 | */ 150 | + (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated; 151 | 152 | /** 153 | * Finds the top-most HUD subview and returns it. 154 | * 155 | * @param view The view that is going to be searched. 156 | * @return A reference to the last HUD subview discovered. 157 | */ 158 | + (MB_INSTANCETYPE)HUDForView:(UIView *)view; 159 | 160 | /** 161 | * Finds all HUD subviews and returns them. 162 | * 163 | * @param view The view that is going to be searched. 164 | * @return All found HUD views (array of MBProgressHUD objects). 165 | */ 166 | + (NSArray *)allHUDsForView:(UIView *)view; 167 | 168 | /** 169 | * A convenience constructor that initializes the HUD with the window's bounds. Calls the designated constructor with 170 | * window.bounds as the parameter. 171 | * 172 | * @param window The window instance that will provide the bounds for the HUD. Should be the same instance as 173 | * the HUD's superview (i.e., the window that the HUD will be added to). 174 | */ 175 | - (id)initWithWindow:(UIWindow *)window; 176 | 177 | /** 178 | * A convenience constructor that initializes the HUD with the view's bounds. Calls the designated constructor with 179 | * view.bounds as the parameter 180 | * 181 | * @param view The view instance that will provide the bounds for the HUD. Should be the same instance as 182 | * the HUD's superview (i.e., the view that the HUD will be added to). 183 | */ 184 | - (id)initWithView:(UIView *)view; 185 | 186 | /** 187 | * Display the HUD. You need to make sure that the main thread completes its run loop soon after this method call so 188 | * the user interface can be updated. Call this method when your task is already set-up to be executed in a new thread 189 | * (e.g., when using something like NSOperation or calling an asynchronous call like NSURLRequest). 190 | * 191 | * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use 192 | * animations while appearing. 193 | * 194 | * @see animationType 195 | */ 196 | - (void)show:(BOOL)animated; 197 | 198 | /** 199 | * Hide the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to 200 | * hide the HUD when your task completes. 201 | * 202 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 203 | * animations while disappearing. 204 | * 205 | * @see animationType 206 | */ 207 | - (void)hide:(BOOL)animated; 208 | 209 | /** 210 | * Hide the HUD after a delay. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to 211 | * hide the HUD when your task completes. 212 | * 213 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 214 | * animations while disappearing. 215 | * @param delay Delay in seconds until the HUD is hidden. 216 | * 217 | * @see animationType 218 | */ 219 | - (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay; 220 | 221 | /** 222 | * Shows the HUD while a background task is executing in a new thread, then hides the HUD. 223 | * 224 | * This method also takes care of autorelease pools so your method does not have to be concerned with setting up a 225 | * pool. 226 | * 227 | * @param method The method to be executed while the HUD is shown. This method will be executed in a new thread. 228 | * @param target The object that the target method belongs to. 229 | * @param object An optional object to be passed to the method. 230 | * @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will not use 231 | * animations while (dis)appearing. 232 | */ 233 | - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated; 234 | 235 | #if NS_BLOCKS_AVAILABLE 236 | 237 | /** 238 | * Shows the HUD while a block is executing on a background queue, then hides the HUD. 239 | * 240 | * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: 241 | */ 242 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block; 243 | 244 | /** 245 | * Shows the HUD while a block is executing on a background queue, then hides the HUD. 246 | * 247 | * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: 248 | */ 249 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(MBProgressHUDCompletionBlock)completion; 250 | 251 | /** 252 | * Shows the HUD while a block is executing on the specified dispatch queue, then hides the HUD. 253 | * 254 | * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: 255 | */ 256 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue; 257 | 258 | /** 259 | * Shows the HUD while a block is executing on the specified dispatch queue, executes completion block on the main queue, and then hides the HUD. 260 | * 261 | * @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will 262 | * not use animations while (dis)appearing. 263 | * @param block The block to be executed while the HUD is shown. 264 | * @param queue The dispatch queue on which the block should be executed. 265 | * @param completion The block to be executed on completion. 266 | * 267 | * @see completionBlock 268 | */ 269 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue 270 | completionBlock:(MBProgressHUDCompletionBlock)completion; 271 | 272 | /** 273 | * A block that gets called after the HUD was completely hidden. 274 | */ 275 | @property (copy) MBProgressHUDCompletionBlock completionBlock; 276 | 277 | #endif 278 | 279 | /** 280 | * MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate. 281 | * 282 | * @see MBProgressHUDMode 283 | */ 284 | @property (assign) MBProgressHUDMode mode; 285 | 286 | /** 287 | * The animation type that should be used when the HUD is shown and hidden. 288 | * 289 | * @see MBProgressHUDAnimation 290 | */ 291 | @property (assign) MBProgressHUDAnimation animationType; 292 | 293 | /** 294 | * The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView. 295 | * For best results use a 37 by 37 pixel view (so the bounds match the built in indicator bounds). 296 | */ 297 | @property (MB_STRONG) UIView *customView; 298 | 299 | /** 300 | * The HUD delegate object. 301 | * 302 | * @see MBProgressHUDDelegate 303 | */ 304 | @property (MB_WEAK) id delegate; 305 | 306 | /** 307 | * An optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit 308 | * the entire text. If the text is too long it will get clipped by displaying "..." at the end. If left unchanged or 309 | * set to @"", then no message is displayed. 310 | */ 311 | @property (copy) NSString *labelText; 312 | 313 | /** 314 | * An optional details message displayed below the labelText message. This message is displayed only if the labelText 315 | * property is also set and is different from an empty string (@""). The details text can span multiple lines. 316 | */ 317 | @property (copy) NSString *detailsLabelText; 318 | 319 | /** 320 | * The opacity of the HUD window. Defaults to 0.8 (80% opacity). 321 | */ 322 | @property (assign) float opacity; 323 | 324 | /** 325 | * The color of the HUD window. Defaults to black. If this property is set, color is set using 326 | * this UIColor and the opacity property is not used. using retain because performing copy on 327 | * UIColor base colors (like [UIColor greenColor]) cause problems with the copyZone. 328 | */ 329 | @property (MB_STRONG) UIColor *color; 330 | 331 | /** 332 | * The x-axis offset of the HUD relative to the centre of the superview. 333 | */ 334 | @property (assign) float xOffset; 335 | 336 | /** 337 | * The y-axis offset of the HUD relative to the centre of the superview. 338 | */ 339 | @property (assign) float yOffset; 340 | 341 | /** 342 | * The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views). 343 | * Defaults to 20.0 344 | */ 345 | @property (assign) float margin; 346 | 347 | /** 348 | * Cover the HUD background view with a radial gradient. 349 | */ 350 | @property (assign) BOOL dimBackground; 351 | 352 | /* 353 | * Grace period is the time (in seconds) that the invoked method may be run without 354 | * showing the HUD. If the task finishes before the grace time runs out, the HUD will 355 | * not be shown at all. 356 | * This may be used to prevent HUD display for very short tasks. 357 | * Defaults to 0 (no grace time). 358 | * Grace time functionality is only supported when the task status is known! 359 | * @see taskInProgress 360 | */ 361 | @property (assign) float graceTime; 362 | 363 | /** 364 | * The minimum time (in seconds) that the HUD is shown. 365 | * This avoids the problem of the HUD being shown and than instantly hidden. 366 | * Defaults to 0 (no minimum show time). 367 | */ 368 | @property (assign) float minShowTime; 369 | 370 | /** 371 | * Indicates that the executed operation is in progress. Needed for correct graceTime operation. 372 | * If you don't set a graceTime (different than 0.0) this does nothing. 373 | * This property is automatically set when using showWhileExecuting:onTarget:withObject:animated:. 374 | * When threading is done outside of the HUD (i.e., when the show: and hide: methods are used directly), 375 | * you need to set this property when your task starts and completes in order to have normal graceTime 376 | * functionality. 377 | */ 378 | @property (assign) BOOL taskInProgress; 379 | 380 | /** 381 | * Removes the HUD from its parent view when hidden. 382 | * Defaults to NO. 383 | */ 384 | @property (assign) BOOL removeFromSuperViewOnHide; 385 | 386 | /** 387 | * Font to be used for the main label. Set this property if the default is not adequate. 388 | */ 389 | @property (MB_STRONG) UIFont* labelFont; 390 | 391 | /** 392 | * Font to be used for the details label. Set this property if the default is not adequate. 393 | */ 394 | @property (MB_STRONG) UIFont* detailsLabelFont; 395 | 396 | /** 397 | * The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0. 398 | */ 399 | @property (assign) float progress; 400 | 401 | /** 402 | * The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size). 403 | */ 404 | @property (assign) CGSize minSize; 405 | 406 | /** 407 | * Force the HUD dimensions to be equal if possible. 408 | */ 409 | @property (assign, getter = isSquare) BOOL square; 410 | 411 | @end 412 | 413 | 414 | @protocol MBProgressHUDDelegate 415 | 416 | @optional 417 | 418 | /** 419 | * Called after the HUD was fully hidden from the screen. 420 | */ 421 | - (void)hudWasHidden:(MBProgressHUD *)hud; 422 | 423 | @end 424 | 425 | 426 | /** 427 | * A progress view for showing definite progress by filling up a circle (pie chart). 428 | */ 429 | @interface MBRoundProgressView : UIView 430 | 431 | /** 432 | * Progress (0.0 to 1.0) 433 | */ 434 | @property (nonatomic, assign) float progress; 435 | 436 | /** 437 | * Indicator progress color. 438 | * Defaults to white [UIColor whiteColor] 439 | */ 440 | @property (nonatomic, MB_STRONG) UIColor *progressTintColor; 441 | 442 | /** 443 | * Indicator background (non-progress) color. 444 | * Defaults to translucent white (alpha 0.1) 445 | */ 446 | @property (nonatomic, MB_STRONG) UIColor *backgroundTintColor; 447 | 448 | /* 449 | * Display mode - NO = round or YES = annular. Defaults to round. 450 | */ 451 | @property (nonatomic, assign, getter = isAnnular) BOOL annular; 452 | 453 | @end 454 | 455 | 456 | /** 457 | * A flat bar progress view. 458 | */ 459 | @interface MBBarProgressView : UIView 460 | 461 | /** 462 | * Progress (0.0 to 1.0) 463 | */ 464 | @property (nonatomic, assign) float progress; 465 | 466 | /** 467 | * Bar border line color. 468 | * Defaults to white [UIColor whiteColor]. 469 | */ 470 | @property (nonatomic, MB_STRONG) UIColor *lineColor; 471 | 472 | /** 473 | * Bar background color. 474 | * Defaults to clear [UIColor clearColor]; 475 | */ 476 | @property (nonatomic, MB_STRONG) UIColor *progressRemainingColor; 477 | 478 | /** 479 | * Bar progress color. 480 | * Defaults to white [UIColor whiteColor]. 481 | */ 482 | @property (nonatomic, MB_STRONG) UIColor *progressColor; 483 | 484 | @end 485 | -------------------------------------------------------------------------------- /Resource/MBProgressHUD/MBProgressHUD.m: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD.m 3 | // Version 0.7 4 | // Created by Matej Bukovinski on 2.4.09. 5 | // 6 | 7 | #import "MBProgressHUD.h" 8 | 9 | 10 | #if __has_feature(objc_arc) 11 | #define MB_AUTORELEASE(exp) exp 12 | #define MB_RELEASE(exp) exp 13 | #define MB_RETAIN(exp) exp 14 | #else 15 | #define MB_AUTORELEASE(exp) [exp autorelease] 16 | #define MB_RELEASE(exp) [exp release] 17 | #define MB_RETAIN(exp) [exp retain] 18 | #endif 19 | 20 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 21 | #define MBLabelAlignmentCenter NSTextAlignmentCenter 22 | #else 23 | #define MBLabelAlignmentCenter UITextAlignmentCenter 24 | #endif 25 | 26 | 27 | static const CGFloat kPadding = 4.f; 28 | static const CGFloat kLabelFontSize = 15.f; 29 | static const CGFloat kDetailsLabelFontSize = 12.f; 30 | 31 | 32 | @interface MBProgressHUD () 33 | 34 | - (void)setupLabels; 35 | - (void)registerForKVO; 36 | - (void)unregisterFromKVO; 37 | - (NSArray *)observableKeypaths; 38 | - (void)registerForNotifications; 39 | - (void)unregisterFromNotifications; 40 | - (void)updateUIForKeypath:(NSString *)keyPath; 41 | - (void)hideUsingAnimation:(BOOL)animated; 42 | - (void)showUsingAnimation:(BOOL)animated; 43 | - (void)done; 44 | - (void)updateIndicators; 45 | - (void)handleGraceTimer:(NSTimer *)theTimer; 46 | - (void)handleMinShowTimer:(NSTimer *)theTimer; 47 | - (void)setTransformForCurrentOrientation:(BOOL)animated; 48 | - (void)cleanUp; 49 | - (void)launchExecution; 50 | - (void)deviceOrientationDidChange:(NSNotification *)notification; 51 | - (void)hideDelayed:(NSNumber *)animated; 52 | 53 | @property (atomic, MB_STRONG) UIView *indicator; 54 | @property (atomic, MB_STRONG) NSTimer *graceTimer; 55 | @property (atomic, MB_STRONG) NSTimer *minShowTimer; 56 | @property (atomic, MB_STRONG) NSDate *showStarted; 57 | @property (atomic, assign) CGSize size; 58 | 59 | @end 60 | 61 | 62 | @implementation MBProgressHUD { 63 | BOOL useAnimation; 64 | SEL methodForExecution; 65 | id targetForExecution; 66 | id objectForExecution; 67 | UILabel *label; 68 | UILabel *detailsLabel; 69 | BOOL isFinished; 70 | CGAffineTransform rotationTransform; 71 | } 72 | 73 | #pragma mark - Properties 74 | 75 | @synthesize animationType; 76 | @synthesize delegate; 77 | @synthesize opacity; 78 | @synthesize color; 79 | @synthesize labelFont; 80 | @synthesize detailsLabelFont; 81 | @synthesize indicator; 82 | @synthesize xOffset; 83 | @synthesize yOffset; 84 | @synthesize minSize; 85 | @synthesize square; 86 | @synthesize margin; 87 | @synthesize dimBackground; 88 | @synthesize graceTime; 89 | @synthesize minShowTime; 90 | @synthesize graceTimer; 91 | @synthesize minShowTimer; 92 | @synthesize taskInProgress; 93 | @synthesize removeFromSuperViewOnHide; 94 | @synthesize customView; 95 | @synthesize showStarted; 96 | @synthesize mode; 97 | @synthesize labelText; 98 | @synthesize detailsLabelText; 99 | @synthesize progress; 100 | @synthesize size; 101 | #if NS_BLOCKS_AVAILABLE 102 | @synthesize completionBlock; 103 | #endif 104 | 105 | #pragma mark - Class methods 106 | 107 | + (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated { 108 | MBProgressHUD *hud = [[self alloc] initWithView:view]; 109 | [view addSubview:hud]; 110 | [hud show:animated]; 111 | return MB_AUTORELEASE(hud); 112 | } 113 | 114 | + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated { 115 | if (view == nil) view = [[UIApplication sharedApplication].windows lastObject]; 116 | MBProgressHUD *hud = [self HUDForView:view]; 117 | if (hud != nil) { 118 | hud.removeFromSuperViewOnHide = YES; 119 | [hud hide:animated]; 120 | return YES; 121 | } 122 | return NO; 123 | } 124 | 125 | + (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated { 126 | if (view == nil) view = [[UIApplication sharedApplication].windows lastObject]; 127 | NSArray *huds = [MBProgressHUD allHUDsForView:view]; 128 | for (MBProgressHUD *hud in huds) { 129 | hud.removeFromSuperViewOnHide = YES; 130 | [hud hide:animated]; 131 | } 132 | return [huds count]; 133 | } 134 | 135 | + (MB_INSTANCETYPE)HUDForView:(UIView *)view { 136 | NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator]; 137 | for (UIView *subview in subviewsEnum) { 138 | if ([subview isKindOfClass:self]) { 139 | return (MBProgressHUD *)subview; 140 | } 141 | } 142 | return nil; 143 | } 144 | 145 | + (NSArray *)allHUDsForView:(UIView *)view { 146 | NSMutableArray *huds = [NSMutableArray array]; 147 | NSArray *subviews = view.subviews; 148 | for (UIView *aView in subviews) { 149 | if ([aView isKindOfClass:self]) { 150 | [huds addObject:aView]; 151 | } 152 | } 153 | return [NSArray arrayWithArray:huds]; 154 | } 155 | 156 | #pragma mark - Lifecycle 157 | 158 | - (id)initWithFrame:(CGRect)frame { 159 | self = [super initWithFrame:frame]; 160 | if (self) { 161 | // Set default values for properties 162 | self.animationType = MBProgressHUDAnimationFade; 163 | self.mode = MBProgressHUDModeIndeterminate; 164 | self.labelText = nil; 165 | self.detailsLabelText = nil; 166 | self.opacity = 0.7f; 167 | self.color = nil; 168 | self.labelFont = [UIFont boldSystemFontOfSize:kLabelFontSize]; 169 | self.detailsLabelFont = [UIFont boldSystemFontOfSize:kDetailsLabelFontSize]; 170 | self.xOffset = 0.0f; 171 | self.yOffset = 0.0f; 172 | self.dimBackground = NO; 173 | self.margin = 20.0f; 174 | self.graceTime = 0.0f; 175 | self.minShowTime = 0.0f; 176 | self.removeFromSuperViewOnHide = NO; 177 | self.minSize = CGSizeZero; 178 | self.square = NO; 179 | self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin 180 | | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; 181 | 182 | // Transparent background 183 | self.opaque = NO; 184 | self.backgroundColor = [UIColor clearColor]; 185 | // Make it invisible for now 186 | self.alpha = 0.0f; 187 | 188 | taskInProgress = NO; 189 | rotationTransform = CGAffineTransformIdentity; 190 | 191 | [self setupLabels]; 192 | [self updateIndicators]; 193 | [self registerForKVO]; 194 | [self registerForNotifications]; 195 | } 196 | return self; 197 | } 198 | 199 | - (id)initWithView:(UIView *)view { 200 | NSAssert(view, @"View must not be nil."); 201 | return [self initWithFrame:view.bounds]; 202 | } 203 | 204 | - (id)initWithWindow:(UIWindow *)window { 205 | return [self initWithView:window]; 206 | } 207 | 208 | - (void)dealloc { 209 | [self unregisterFromNotifications]; 210 | [self unregisterFromKVO]; 211 | #if !__has_feature(objc_arc) 212 | [color release]; 213 | [indicator release]; 214 | [label release]; 215 | [detailsLabel release]; 216 | [labelText release]; 217 | [detailsLabelText release]; 218 | [graceTimer release]; 219 | [minShowTimer release]; 220 | [showStarted release]; 221 | [customView release]; 222 | #if NS_BLOCKS_AVAILABLE 223 | [completionBlock release]; 224 | #endif 225 | [super dealloc]; 226 | #endif 227 | } 228 | 229 | #pragma mark - Show & hide 230 | 231 | - (void)show:(BOOL)animated { 232 | useAnimation = animated; 233 | // If the grace time is set postpone the HUD display 234 | if (self.graceTime > 0.0) { 235 | self.graceTimer = [NSTimer scheduledTimerWithTimeInterval:self.graceTime target:self 236 | selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO]; 237 | } 238 | // ... otherwise show the HUD imediately 239 | else { 240 | [self setNeedsDisplay]; 241 | [self showUsingAnimation:useAnimation]; 242 | } 243 | } 244 | 245 | - (void)hide:(BOOL)animated { 246 | useAnimation = animated; 247 | // If the minShow time is set, calculate how long the hud was shown, 248 | // and pospone the hiding operation if necessary 249 | if (self.minShowTime > 0.0 && showStarted) { 250 | NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:showStarted]; 251 | if (interv < self.minShowTime) { 252 | self.minShowTimer = [NSTimer scheduledTimerWithTimeInterval:(self.minShowTime - interv) target:self 253 | selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO]; 254 | return; 255 | } 256 | } 257 | // ... otherwise hide the HUD immediately 258 | [self hideUsingAnimation:useAnimation]; 259 | } 260 | 261 | - (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay { 262 | [self performSelector:@selector(hideDelayed:) withObject:[NSNumber numberWithBool:animated] afterDelay:delay]; 263 | } 264 | 265 | - (void)hideDelayed:(NSNumber *)animated { 266 | [self hide:[animated boolValue]]; 267 | } 268 | 269 | #pragma mark - Timer callbacks 270 | 271 | - (void)handleGraceTimer:(NSTimer *)theTimer { 272 | // Show the HUD only if the task is still running 273 | if (taskInProgress) { 274 | [self setNeedsDisplay]; 275 | [self showUsingAnimation:useAnimation]; 276 | } 277 | } 278 | 279 | - (void)handleMinShowTimer:(NSTimer *)theTimer { 280 | [self hideUsingAnimation:useAnimation]; 281 | } 282 | 283 | #pragma mark - View Hierrarchy 284 | 285 | - (void)didMoveToSuperview { 286 | // We need to take care of rotation ourselfs if we're adding the HUD to a window 287 | if ([self.superview isKindOfClass:[UIWindow class]]) { 288 | [self setTransformForCurrentOrientation:NO]; 289 | } 290 | } 291 | 292 | #pragma mark - Internal show & hide operations 293 | 294 | - (void)showUsingAnimation:(BOOL)animated { 295 | if (animated && animationType == MBProgressHUDAnimationZoomIn) { 296 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f)); 297 | } else if (animated && animationType == MBProgressHUDAnimationZoomOut) { 298 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f)); 299 | } 300 | self.showStarted = [NSDate date]; 301 | // Fade in 302 | if (animated) { 303 | [UIView beginAnimations:nil context:NULL]; 304 | [UIView setAnimationDuration:0.30]; 305 | self.alpha = 1.0f; 306 | if (animationType == MBProgressHUDAnimationZoomIn || animationType == MBProgressHUDAnimationZoomOut) { 307 | self.transform = rotationTransform; 308 | } 309 | [UIView commitAnimations]; 310 | } 311 | else { 312 | self.alpha = 1.0f; 313 | } 314 | } 315 | 316 | - (void)hideUsingAnimation:(BOOL)animated { 317 | // Fade out 318 | if (animated && showStarted) { 319 | [UIView beginAnimations:nil context:NULL]; 320 | [UIView setAnimationDuration:0.30]; 321 | [UIView setAnimationDelegate:self]; 322 | [UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)]; 323 | // 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden 324 | // in the done method 325 | if (animationType == MBProgressHUDAnimationZoomIn) { 326 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f)); 327 | } else if (animationType == MBProgressHUDAnimationZoomOut) { 328 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f)); 329 | } 330 | 331 | self.alpha = 0.02f; 332 | [UIView commitAnimations]; 333 | } 334 | else { 335 | self.alpha = 0.0f; 336 | [self done]; 337 | } 338 | self.showStarted = nil; 339 | } 340 | 341 | - (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context { 342 | [self done]; 343 | } 344 | 345 | - (void)done { 346 | isFinished = YES; 347 | self.alpha = 0.0f; 348 | if ([delegate respondsToSelector:@selector(hudWasHidden:)]) { 349 | [delegate performSelector:@selector(hudWasHidden:) withObject:self]; 350 | } 351 | #if NS_BLOCKS_AVAILABLE 352 | if (self.completionBlock) { 353 | self.completionBlock(); 354 | self.completionBlock = NULL; 355 | } 356 | #endif 357 | if (removeFromSuperViewOnHide) { 358 | [self removeFromSuperview]; 359 | } 360 | } 361 | 362 | #pragma mark - Threading 363 | 364 | - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated { 365 | methodForExecution = method; 366 | targetForExecution = MB_RETAIN(target); 367 | objectForExecution = MB_RETAIN(object); 368 | // Launch execution in new thread 369 | self.taskInProgress = YES; 370 | [NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil]; 371 | // Show HUD view 372 | [self show:animated]; 373 | } 374 | 375 | #if NS_BLOCKS_AVAILABLE 376 | 377 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block { 378 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 379 | [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL]; 380 | } 381 | 382 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(void (^)())completion { 383 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 384 | [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:completion]; 385 | } 386 | 387 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue { 388 | [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL]; 389 | } 390 | 391 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue 392 | completionBlock:(MBProgressHUDCompletionBlock)completion { 393 | self.taskInProgress = YES; 394 | self.completionBlock = completion; 395 | dispatch_async(queue, ^(void) { 396 | block(); 397 | dispatch_async(dispatch_get_main_queue(), ^(void) { 398 | [self cleanUp]; 399 | }); 400 | }); 401 | [self show:animated]; 402 | } 403 | 404 | #endif 405 | 406 | - (void)launchExecution { 407 | @autoreleasepool { 408 | #pragma clang diagnostic push 409 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 410 | // Start executing the requested task 411 | [targetForExecution performSelector:methodForExecution withObject:objectForExecution]; 412 | #pragma clang diagnostic pop 413 | // Task completed, update view in main thread (note: view operations should 414 | // be done only in the main thread) 415 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO]; 416 | } 417 | } 418 | 419 | - (void)cleanUp { 420 | taskInProgress = NO; 421 | self.indicator = nil; 422 | #if !__has_feature(objc_arc) 423 | [targetForExecution release]; 424 | [objectForExecution release]; 425 | #else 426 | targetForExecution = nil; 427 | objectForExecution = nil; 428 | #endif 429 | [self hide:useAnimation]; 430 | } 431 | 432 | #pragma mark - UI 433 | 434 | - (void)setupLabels { 435 | label = [[UILabel alloc] initWithFrame:self.bounds]; 436 | label.adjustsFontSizeToFitWidth = NO; 437 | label.textAlignment = MBLabelAlignmentCenter; 438 | label.opaque = NO; 439 | label.backgroundColor = [UIColor clearColor]; 440 | label.textColor = [UIColor whiteColor]; 441 | label.font = self.labelFont; 442 | label.text = self.labelText; 443 | [self addSubview:label]; 444 | 445 | detailsLabel = [[UILabel alloc] initWithFrame:self.bounds]; 446 | detailsLabel.font = self.detailsLabelFont; 447 | detailsLabel.adjustsFontSizeToFitWidth = NO; 448 | detailsLabel.textAlignment = MBLabelAlignmentCenter; 449 | detailsLabel.opaque = NO; 450 | detailsLabel.backgroundColor = [UIColor clearColor]; 451 | detailsLabel.textColor = [UIColor whiteColor]; 452 | detailsLabel.numberOfLines = 0; 453 | detailsLabel.font = self.detailsLabelFont; 454 | detailsLabel.text = self.detailsLabelText; 455 | [self addSubview:detailsLabel]; 456 | } 457 | 458 | - (void)updateIndicators { 459 | 460 | BOOL isActivityIndicator = [indicator isKindOfClass:[UIActivityIndicatorView class]]; 461 | BOOL isRoundIndicator = [indicator isKindOfClass:[MBRoundProgressView class]]; 462 | 463 | if (mode == MBProgressHUDModeIndeterminate && !isActivityIndicator) { 464 | // Update to indeterminate indicator 465 | [indicator removeFromSuperview]; 466 | self.indicator = MB_AUTORELEASE([[UIActivityIndicatorView alloc] 467 | initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]); 468 | [(UIActivityIndicatorView *)indicator startAnimating]; 469 | [self addSubview:indicator]; 470 | } 471 | else if (mode == MBProgressHUDModeDeterminateHorizontalBar) { 472 | // Update to bar determinate indicator 473 | [indicator removeFromSuperview]; 474 | self.indicator = MB_AUTORELEASE([[MBBarProgressView alloc] init]); 475 | [self addSubview:indicator]; 476 | } 477 | else if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) { 478 | if (!isRoundIndicator) { 479 | // Update to determinante indicator 480 | [indicator removeFromSuperview]; 481 | self.indicator = MB_AUTORELEASE([[MBRoundProgressView alloc] init]); 482 | [self addSubview:indicator]; 483 | } 484 | if (mode == MBProgressHUDModeAnnularDeterminate) { 485 | [(MBRoundProgressView *)indicator setAnnular:YES]; 486 | } 487 | } 488 | else if (mode == MBProgressHUDModeCustomView && customView != indicator) { 489 | // Update custom view indicator 490 | [indicator removeFromSuperview]; 491 | self.indicator = customView; 492 | [self addSubview:indicator]; 493 | } else if (mode == MBProgressHUDModeText) { 494 | [indicator removeFromSuperview]; 495 | self.indicator = nil; 496 | } 497 | } 498 | 499 | #pragma mark - Layout 500 | 501 | - (void)layoutSubviews { 502 | 503 | // Entirely cover the parent view 504 | UIView *parent = self.superview; 505 | if (parent) { 506 | self.frame = parent.bounds; 507 | } 508 | CGRect bounds = self.bounds; 509 | 510 | // Determine the total widt and height needed 511 | CGFloat maxWidth = bounds.size.width - 4 * margin; 512 | CGSize totalSize = CGSizeZero; 513 | 514 | CGRect indicatorF = indicator.bounds; 515 | indicatorF.size.width = MIN(indicatorF.size.width, maxWidth); 516 | totalSize.width = MAX(totalSize.width, indicatorF.size.width); 517 | totalSize.height += indicatorF.size.height; 518 | 519 | CGSize labelSize = [label.text sizeWithFont:label.font]; 520 | labelSize.width = MIN(labelSize.width, maxWidth); 521 | totalSize.width = MAX(totalSize.width, labelSize.width); 522 | totalSize.height += labelSize.height; 523 | if (labelSize.height > 0.f && indicatorF.size.height > 0.f) { 524 | totalSize.height += kPadding; 525 | } 526 | 527 | CGFloat remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 * margin; 528 | CGSize maxSize = CGSizeMake(maxWidth, remainingHeight); 529 | CGSize detailsLabelSize = [detailsLabel.text sizeWithFont:detailsLabel.font 530 | constrainedToSize:maxSize lineBreakMode:detailsLabel.lineBreakMode]; 531 | totalSize.width = MAX(totalSize.width, detailsLabelSize.width); 532 | totalSize.height += detailsLabelSize.height; 533 | if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) { 534 | totalSize.height += kPadding; 535 | } 536 | 537 | totalSize.width += 2 * margin; 538 | totalSize.height += 2 * margin; 539 | 540 | // Position elements 541 | CGFloat yPos = roundf(((bounds.size.height - totalSize.height) / 2)) + margin + yOffset; 542 | CGFloat xPos = xOffset; 543 | indicatorF.origin.y = yPos; 544 | indicatorF.origin.x = roundf((bounds.size.width - indicatorF.size.width) / 2) + xPos; 545 | indicator.frame = indicatorF; 546 | yPos += indicatorF.size.height; 547 | 548 | if (labelSize.height > 0.f && indicatorF.size.height > 0.f) { 549 | yPos += kPadding; 550 | } 551 | CGRect labelF; 552 | labelF.origin.y = yPos; 553 | labelF.origin.x = roundf((bounds.size.width - labelSize.width) / 2) + xPos; 554 | labelF.size = labelSize; 555 | label.frame = labelF; 556 | yPos += labelF.size.height; 557 | 558 | if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) { 559 | yPos += kPadding; 560 | } 561 | CGRect detailsLabelF; 562 | detailsLabelF.origin.y = yPos; 563 | detailsLabelF.origin.x = roundf((bounds.size.width - detailsLabelSize.width) / 2) + xPos; 564 | detailsLabelF.size = detailsLabelSize; 565 | detailsLabel.frame = detailsLabelF; 566 | 567 | // Enforce minsize and quare rules 568 | if (square) { 569 | CGFloat max = MAX(totalSize.width, totalSize.height); 570 | if (max <= bounds.size.width - 2 * margin) { 571 | totalSize.width = max; 572 | } 573 | if (max <= bounds.size.height - 2 * margin) { 574 | totalSize.height = max; 575 | } 576 | } 577 | if (totalSize.width < minSize.width) { 578 | totalSize.width = minSize.width; 579 | } 580 | if (totalSize.height < minSize.height) { 581 | totalSize.height = minSize.height; 582 | } 583 | 584 | self.size = totalSize; 585 | } 586 | 587 | #pragma mark BG Drawing 588 | 589 | - (void)drawRect:(CGRect)rect { 590 | 591 | CGContextRef context = UIGraphicsGetCurrentContext(); 592 | UIGraphicsPushContext(context); 593 | 594 | if (self.dimBackground) { 595 | //Gradient colours 596 | size_t gradLocationsNum = 2; 597 | CGFloat gradLocations[2] = {0.0f, 1.0f}; 598 | CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f}; 599 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 600 | CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum); 601 | CGColorSpaceRelease(colorSpace); 602 | //Gradient center 603 | CGPoint gradCenter= CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); 604 | //Gradient radius 605 | float gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ; 606 | //Gradient draw 607 | CGContextDrawRadialGradient (context, gradient, gradCenter, 608 | 0, gradCenter, gradRadius, 609 | kCGGradientDrawsAfterEndLocation); 610 | CGGradientRelease(gradient); 611 | } 612 | 613 | // Set background rect color 614 | if (self.color) { 615 | CGContextSetFillColorWithColor(context, self.color.CGColor); 616 | } else { 617 | CGContextSetGrayFillColor(context, 0.0f, self.opacity); 618 | } 619 | 620 | 621 | // Center HUD 622 | CGRect allRect = self.bounds; 623 | // Draw rounded HUD backgroud rect 624 | CGRect boxRect = CGRectMake(roundf((allRect.size.width - size.width) / 2) + self.xOffset, 625 | roundf((allRect.size.height - size.height) / 2) + self.yOffset, size.width, size.height); 626 | float radius = 10.0f; 627 | CGContextBeginPath(context); 628 | CGContextMoveToPoint(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect)); 629 | CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMinY(boxRect) + radius, radius, 3 * (float)M_PI / 2, 0, 0); 630 | CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMaxY(boxRect) - radius, radius, 0, (float)M_PI / 2, 0); 631 | CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMaxY(boxRect) - radius, radius, (float)M_PI / 2, (float)M_PI, 0); 632 | CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect) + radius, radius, (float)M_PI, 3 * (float)M_PI / 2, 0); 633 | CGContextClosePath(context); 634 | CGContextFillPath(context); 635 | 636 | UIGraphicsPopContext(); 637 | } 638 | 639 | #pragma mark - KVO 640 | 641 | - (void)registerForKVO { 642 | for (NSString *keyPath in [self observableKeypaths]) { 643 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 644 | } 645 | } 646 | 647 | - (void)unregisterFromKVO { 648 | for (NSString *keyPath in [self observableKeypaths]) { 649 | [self removeObserver:self forKeyPath:keyPath]; 650 | } 651 | } 652 | 653 | - (NSArray *)observableKeypaths { 654 | return [NSArray arrayWithObjects:@"mode", @"customView", @"labelText", @"labelFont", 655 | @"detailsLabelText", @"detailsLabelFont", @"progress", nil]; 656 | } 657 | 658 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 659 | if (![NSThread isMainThread]) { 660 | [self performSelectorOnMainThread:@selector(updateUIForKeypath:) withObject:keyPath waitUntilDone:NO]; 661 | } else { 662 | [self updateUIForKeypath:keyPath]; 663 | } 664 | } 665 | 666 | - (void)updateUIForKeypath:(NSString *)keyPath { 667 | if ([keyPath isEqualToString:@"mode"] || [keyPath isEqualToString:@"customView"]) { 668 | [self updateIndicators]; 669 | } else if ([keyPath isEqualToString:@"labelText"]) { 670 | label.text = self.labelText; 671 | } else if ([keyPath isEqualToString:@"labelFont"]) { 672 | label.font = self.labelFont; 673 | } else if ([keyPath isEqualToString:@"detailsLabelText"]) { 674 | detailsLabel.text = self.detailsLabelText; 675 | } else if ([keyPath isEqualToString:@"detailsLabelFont"]) { 676 | detailsLabel.font = self.detailsLabelFont; 677 | } else if ([keyPath isEqualToString:@"progress"]) { 678 | if ([indicator respondsToSelector:@selector(setProgress:)]) { 679 | [(id)indicator setProgress:progress]; 680 | } 681 | return; 682 | } 683 | [self setNeedsLayout]; 684 | [self setNeedsDisplay]; 685 | } 686 | 687 | #pragma mark - Notifications 688 | 689 | - (void)registerForNotifications { 690 | NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 691 | [nc addObserver:self selector:@selector(deviceOrientationDidChange:) 692 | name:UIDeviceOrientationDidChangeNotification object:nil]; 693 | } 694 | 695 | - (void)unregisterFromNotifications { 696 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 697 | } 698 | 699 | - (void)deviceOrientationDidChange:(NSNotification *)notification { 700 | UIView *superview = self.superview; 701 | if (!superview) { 702 | return; 703 | } else if ([superview isKindOfClass:[UIWindow class]]) { 704 | [self setTransformForCurrentOrientation:YES]; 705 | } else { 706 | self.bounds = self.superview.bounds; 707 | [self setNeedsDisplay]; 708 | } 709 | } 710 | 711 | - (void)setTransformForCurrentOrientation:(BOOL)animated { 712 | // Stay in sync with the superview 713 | if (self.superview) { 714 | self.bounds = self.superview.bounds; 715 | [self setNeedsDisplay]; 716 | } 717 | 718 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 719 | CGFloat radians = 0; 720 | if (UIInterfaceOrientationIsLandscape(orientation)) { 721 | if (orientation == UIInterfaceOrientationLandscapeLeft) { radians = -(CGFloat)M_PI_2; } 722 | else { radians = (CGFloat)M_PI_2; } 723 | // Window coordinates differ! 724 | self.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.width); 725 | } else { 726 | if (orientation == UIInterfaceOrientationPortraitUpsideDown) { radians = (CGFloat)M_PI; } 727 | else { radians = 0; } 728 | } 729 | rotationTransform = CGAffineTransformMakeRotation(radians); 730 | 731 | if (animated) { 732 | [UIView beginAnimations:nil context:nil]; 733 | } 734 | [self setTransform:rotationTransform]; 735 | if (animated) { 736 | [UIView commitAnimations]; 737 | } 738 | } 739 | 740 | @end 741 | 742 | 743 | @implementation MBRoundProgressView 744 | 745 | #pragma mark - Lifecycle 746 | 747 | - (id)init { 748 | return [self initWithFrame:CGRectMake(0.f, 0.f, 37.f, 37.f)]; 749 | } 750 | 751 | - (id)initWithFrame:(CGRect)frame { 752 | self = [super initWithFrame:frame]; 753 | if (self) { 754 | self.backgroundColor = [UIColor clearColor]; 755 | self.opaque = NO; 756 | _progress = 0.f; 757 | _annular = NO; 758 | _progressTintColor = [[UIColor alloc] initWithWhite:1.f alpha:1.f]; 759 | _backgroundTintColor = [[UIColor alloc] initWithWhite:1.f alpha:.1f]; 760 | [self registerForKVO]; 761 | } 762 | return self; 763 | } 764 | 765 | - (void)dealloc { 766 | [self unregisterFromKVO]; 767 | #if !__has_feature(objc_arc) 768 | [_progressTintColor release]; 769 | [_backgroundTintColor release]; 770 | [super dealloc]; 771 | #endif 772 | } 773 | 774 | #pragma mark - Drawing 775 | 776 | - (void)drawRect:(CGRect)rect { 777 | 778 | CGRect allRect = self.bounds; 779 | CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f); 780 | CGContextRef context = UIGraphicsGetCurrentContext(); 781 | 782 | if (_annular) { 783 | // Draw background 784 | CGFloat lineWidth = 5.f; 785 | UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath]; 786 | processBackgroundPath.lineWidth = lineWidth; 787 | processBackgroundPath.lineCapStyle = kCGLineCapRound; 788 | CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); 789 | CGFloat radius = (self.bounds.size.width - lineWidth)/2; 790 | CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees 791 | CGFloat endAngle = (2 * (float)M_PI) + startAngle; 792 | [processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; 793 | [_backgroundTintColor set]; 794 | [processBackgroundPath stroke]; 795 | // Draw progress 796 | UIBezierPath *processPath = [UIBezierPath bezierPath]; 797 | processPath.lineCapStyle = kCGLineCapRound; 798 | processPath.lineWidth = lineWidth; 799 | endAngle = (self.progress * 2 * (float)M_PI) + startAngle; 800 | [processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; 801 | [_progressTintColor set]; 802 | [processPath stroke]; 803 | } else { 804 | // Draw background 805 | [_progressTintColor setStroke]; 806 | [_backgroundTintColor setFill]; 807 | CGContextSetLineWidth(context, 2.0f); 808 | CGContextFillEllipseInRect(context, circleRect); 809 | CGContextStrokeEllipseInRect(context, circleRect); 810 | // Draw progress 811 | CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2); 812 | CGFloat radius = (allRect.size.width - 4) / 2; 813 | CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees 814 | CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle; 815 | CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // white 816 | CGContextMoveToPoint(context, center.x, center.y); 817 | CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0); 818 | CGContextClosePath(context); 819 | CGContextFillPath(context); 820 | } 821 | } 822 | 823 | #pragma mark - KVO 824 | 825 | - (void)registerForKVO { 826 | for (NSString *keyPath in [self observableKeypaths]) { 827 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 828 | } 829 | } 830 | 831 | - (void)unregisterFromKVO { 832 | for (NSString *keyPath in [self observableKeypaths]) { 833 | [self removeObserver:self forKeyPath:keyPath]; 834 | } 835 | } 836 | 837 | - (NSArray *)observableKeypaths { 838 | return [NSArray arrayWithObjects:@"progressTintColor", @"backgroundTintColor", @"progress", @"annular", nil]; 839 | } 840 | 841 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 842 | [self setNeedsDisplay]; 843 | } 844 | 845 | @end 846 | 847 | 848 | @implementation MBBarProgressView 849 | 850 | #pragma mark - Lifecycle 851 | 852 | - (id)init { 853 | return [self initWithFrame:CGRectMake(.0f, .0f, 120.0f, 20.0f)]; 854 | } 855 | 856 | - (id)initWithFrame:(CGRect)frame { 857 | self = [super initWithFrame:frame]; 858 | if (self) { 859 | _progress = 0.f; 860 | _lineColor = [UIColor whiteColor]; 861 | _progressColor = [UIColor whiteColor]; 862 | _progressRemainingColor = [UIColor clearColor]; 863 | self.backgroundColor = [UIColor clearColor]; 864 | self.opaque = NO; 865 | [self registerForKVO]; 866 | } 867 | return self; 868 | } 869 | 870 | - (void)dealloc { 871 | [self unregisterFromKVO]; 872 | #if !__has_feature(objc_arc) 873 | [_lineColor release]; 874 | [_progressColor release]; 875 | [_progressRemainingColor release]; 876 | [super dealloc]; 877 | #endif 878 | } 879 | 880 | #pragma mark - Drawing 881 | 882 | - (void)drawRect:(CGRect)rect { 883 | CGContextRef context = UIGraphicsGetCurrentContext(); 884 | 885 | // setup properties 886 | CGContextSetLineWidth(context, 2); 887 | CGContextSetStrokeColorWithColor(context,[_lineColor CGColor]); 888 | CGContextSetFillColorWithColor(context, [_progressRemainingColor CGColor]); 889 | 890 | // draw line border 891 | float radius = (rect.size.height / 2) - 2; 892 | CGContextMoveToPoint(context, 2, rect.size.height/2); 893 | CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius); 894 | CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2); 895 | CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius); 896 | CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius); 897 | CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2); 898 | CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius); 899 | CGContextFillPath(context); 900 | 901 | // draw progress background 902 | CGContextMoveToPoint(context, 2, rect.size.height/2); 903 | CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius); 904 | CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2); 905 | CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius); 906 | CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius); 907 | CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2); 908 | CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius); 909 | CGContextStrokePath(context); 910 | 911 | // setup to draw progress color 912 | CGContextSetFillColorWithColor(context, [_progressColor CGColor]); 913 | radius = radius - 2; 914 | float amount = self.progress * rect.size.width; 915 | 916 | // if progress is in the middle area 917 | if (amount >= radius + 4 && amount <= (rect.size.width - radius - 4)) { 918 | // top 919 | CGContextMoveToPoint(context, 4, rect.size.height/2); 920 | CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); 921 | CGContextAddLineToPoint(context, amount, 4); 922 | CGContextAddLineToPoint(context, amount, radius + 4); 923 | 924 | // bottom 925 | CGContextMoveToPoint(context, 4, rect.size.height/2); 926 | CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); 927 | CGContextAddLineToPoint(context, amount, rect.size.height - 4); 928 | CGContextAddLineToPoint(context, amount, radius + 4); 929 | 930 | CGContextFillPath(context); 931 | } 932 | 933 | // progress is in the right arc 934 | else if (amount > radius + 4) { 935 | float x = amount - (rect.size.width - radius - 4); 936 | 937 | // top 938 | CGContextMoveToPoint(context, 4, rect.size.height/2); 939 | CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); 940 | CGContextAddLineToPoint(context, rect.size.width - radius - 4, 4); 941 | float angle = -acos(x/radius); 942 | if (isnan(angle)) angle = 0; 943 | CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, M_PI, angle, 0); 944 | CGContextAddLineToPoint(context, amount, rect.size.height/2); 945 | 946 | // bottom 947 | CGContextMoveToPoint(context, 4, rect.size.height/2); 948 | CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); 949 | CGContextAddLineToPoint(context, rect.size.width - radius - 4, rect.size.height - 4); 950 | angle = acos(x/radius); 951 | if (isnan(angle)) angle = 0; 952 | CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, -M_PI, angle, 1); 953 | CGContextAddLineToPoint(context, amount, rect.size.height/2); 954 | 955 | CGContextFillPath(context); 956 | } 957 | 958 | // progress is in the left arc 959 | else if (amount < radius + 4 && amount > 0) { 960 | // top 961 | CGContextMoveToPoint(context, 4, rect.size.height/2); 962 | CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); 963 | CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); 964 | 965 | // bottom 966 | CGContextMoveToPoint(context, 4, rect.size.height/2); 967 | CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); 968 | CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); 969 | 970 | CGContextFillPath(context); 971 | } 972 | } 973 | 974 | #pragma mark - KVO 975 | 976 | - (void)registerForKVO { 977 | for (NSString *keyPath in [self observableKeypaths]) { 978 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 979 | } 980 | } 981 | 982 | - (void)unregisterFromKVO { 983 | for (NSString *keyPath in [self observableKeypaths]) { 984 | [self removeObserver:self forKeyPath:keyPath]; 985 | } 986 | } 987 | 988 | - (NSArray *)observableKeypaths { 989 | return [NSArray arrayWithObjects:@"lineColor", @"progressRemainingColor", @"progressColor", @"progress", nil]; 990 | } 991 | 992 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 993 | [self setNeedsDisplay]; 994 | } 995 | 996 | @end 997 | -------------------------------------------------------------------------------- /Resource/qr_scan_line@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenxuhunoc/QRCode/8f89f110d8ae65c8a52f15c5f82ab356d42940bc/Resource/qr_scan_line@2x.png -------------------------------------------------------------------------------- /SampleImage/IMG_0023.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenxuhunoc/QRCode/8f89f110d8ae65c8a52f15c5f82ab356d42940bc/SampleImage/IMG_0023.PNG -------------------------------------------------------------------------------- /SampleImage/IMG_0024.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenxuhunoc/QRCode/8f89f110d8ae65c8a52f15c5f82ab356d42940bc/SampleImage/IMG_0024.PNG --------------------------------------------------------------------------------