├── README.md ├── ZWMGuideViewDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── lingcheng.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── lingcheng.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── ZWMGuideViewDemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── arrow.imageset │ │ ├── Contents.json │ │ └── 添加题目引导箭头.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── SecondViewController.h ├── SecondViewController.m ├── ViewController.h ├── ViewController.m ├── ZWMGuideView │ ├── ZWMGuideView.h │ └── ZWMGuideView.m ├── guide.gif └── main.m └── ZWMGuideViewDemoUITests ├── Info.plist └── ZWMGuideViewDemoUITests.m /README.md: -------------------------------------------------------------------------------- 1 | # ZWMGuideView 2 | 3 | 新手引导页   4 | 5 | 适用于所有App的新手指引,使用简单,动画顺畅!     6 | 7 | 如果你觉得还不错,希望赏个star,谢谢了!  8 | 9 | 10 | ![img](https://github.com/weiming4219/ZWMGuideView/blob/master/ZWMGuideViewDemo/guide.gif) 11 | 12 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7CBE1DD01FCD4AD700AC4899 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CBE1DCF1FCD4AD700AC4899 /* AppDelegate.m */; }; 11 | 7CBE1DD31FCD4AD700AC4899 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CBE1DD21FCD4AD700AC4899 /* ViewController.m */; }; 12 | 7CBE1DD61FCD4AD700AC4899 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7CBE1DD41FCD4AD700AC4899 /* Main.storyboard */; }; 13 | 7CBE1DD81FCD4AD700AC4899 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7CBE1DD71FCD4AD700AC4899 /* Assets.xcassets */; }; 14 | 7CBE1DDB1FCD4AD700AC4899 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7CBE1DD91FCD4AD700AC4899 /* LaunchScreen.storyboard */; }; 15 | 7CBE1DDE1FCD4AD700AC4899 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CBE1DDD1FCD4AD700AC4899 /* main.m */; }; 16 | 7CBE1DE81FCD4AD700AC4899 /* ZWMGuideViewDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CBE1DE71FCD4AD700AC4899 /* ZWMGuideViewDemoUITests.m */; }; 17 | 7CBE1DF51FCD4D0000AC4899 /* ZWMGuideView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CBE1DF41FCD4D0000AC4899 /* ZWMGuideView.m */; }; 18 | 7CBE1DF81FCD583100AC4899 /* SecondViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CBE1DF71FCD583100AC4899 /* SecondViewController.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 7CBE1DE41FCD4AD700AC4899 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 7CBE1DC31FCD4AD600AC4899 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 7CBE1DCA1FCD4AD600AC4899; 27 | remoteInfo = ZWMGuideViewDemo; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 7CBE1DCB1FCD4AD600AC4899 /* ZWMGuideViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZWMGuideViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 7CBE1DCE1FCD4AD600AC4899 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 34 | 7CBE1DCF1FCD4AD700AC4899 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 35 | 7CBE1DD11FCD4AD700AC4899 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 36 | 7CBE1DD21FCD4AD700AC4899 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 37 | 7CBE1DD51FCD4AD700AC4899 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 38 | 7CBE1DD71FCD4AD700AC4899 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 39 | 7CBE1DDA1FCD4AD700AC4899 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 40 | 7CBE1DDC1FCD4AD700AC4899 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | 7CBE1DDD1FCD4AD700AC4899 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | 7CBE1DE31FCD4AD700AC4899 /* ZWMGuideViewDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZWMGuideViewDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 7CBE1DE71FCD4AD700AC4899 /* ZWMGuideViewDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZWMGuideViewDemoUITests.m; sourceTree = ""; }; 44 | 7CBE1DE91FCD4AD700AC4899 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | 7CBE1DF31FCD4D0000AC4899 /* ZWMGuideView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZWMGuideView.h; sourceTree = ""; }; 46 | 7CBE1DF41FCD4D0000AC4899 /* ZWMGuideView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZWMGuideView.m; sourceTree = ""; }; 47 | 7CBE1DF61FCD583100AC4899 /* SecondViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecondViewController.h; sourceTree = ""; }; 48 | 7CBE1DF71FCD583100AC4899 /* SecondViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecondViewController.m; sourceTree = ""; }; 49 | 7CCA90F81FCE91D20073A814 /* guide.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = guide.gif; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 7CBE1DC81FCD4AD600AC4899 /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | 7CBE1DE01FCD4AD700AC4899 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | 7CBE1DC21FCD4AD600AC4899 = { 71 | isa = PBXGroup; 72 | children = ( 73 | 7CBE1DCD1FCD4AD600AC4899 /* ZWMGuideViewDemo */, 74 | 7CBE1DE61FCD4AD700AC4899 /* ZWMGuideViewDemoUITests */, 75 | 7CBE1DCC1FCD4AD600AC4899 /* Products */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | 7CBE1DCC1FCD4AD600AC4899 /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 7CBE1DCB1FCD4AD600AC4899 /* ZWMGuideViewDemo.app */, 83 | 7CBE1DE31FCD4AD700AC4899 /* ZWMGuideViewDemoUITests.xctest */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | 7CBE1DCD1FCD4AD600AC4899 /* ZWMGuideViewDemo */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 7CBE1DF21FCD4AE000AC4899 /* ZWMGuideView */, 92 | 7CBE1DCE1FCD4AD600AC4899 /* AppDelegate.h */, 93 | 7CBE1DCF1FCD4AD700AC4899 /* AppDelegate.m */, 94 | 7CBE1DD11FCD4AD700AC4899 /* ViewController.h */, 95 | 7CBE1DD21FCD4AD700AC4899 /* ViewController.m */, 96 | 7CBE1DF61FCD583100AC4899 /* SecondViewController.h */, 97 | 7CBE1DF71FCD583100AC4899 /* SecondViewController.m */, 98 | 7CBE1DD41FCD4AD700AC4899 /* Main.storyboard */, 99 | 7CBE1DD71FCD4AD700AC4899 /* Assets.xcassets */, 100 | 7CCA90F81FCE91D20073A814 /* guide.gif */, 101 | 7CBE1DD91FCD4AD700AC4899 /* LaunchScreen.storyboard */, 102 | 7CBE1DDC1FCD4AD700AC4899 /* Info.plist */, 103 | 7CBE1DDD1FCD4AD700AC4899 /* main.m */, 104 | ); 105 | path = ZWMGuideViewDemo; 106 | sourceTree = ""; 107 | }; 108 | 7CBE1DE61FCD4AD700AC4899 /* ZWMGuideViewDemoUITests */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 7CBE1DE71FCD4AD700AC4899 /* ZWMGuideViewDemoUITests.m */, 112 | 7CBE1DE91FCD4AD700AC4899 /* Info.plist */, 113 | ); 114 | path = ZWMGuideViewDemoUITests; 115 | sourceTree = ""; 116 | }; 117 | 7CBE1DF21FCD4AE000AC4899 /* ZWMGuideView */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 7CBE1DF31FCD4D0000AC4899 /* ZWMGuideView.h */, 121 | 7CBE1DF41FCD4D0000AC4899 /* ZWMGuideView.m */, 122 | ); 123 | path = ZWMGuideView; 124 | sourceTree = ""; 125 | }; 126 | /* End PBXGroup section */ 127 | 128 | /* Begin PBXNativeTarget section */ 129 | 7CBE1DCA1FCD4AD600AC4899 /* ZWMGuideViewDemo */ = { 130 | isa = PBXNativeTarget; 131 | buildConfigurationList = 7CBE1DEC1FCD4AD700AC4899 /* Build configuration list for PBXNativeTarget "ZWMGuideViewDemo" */; 132 | buildPhases = ( 133 | 7CBE1DC71FCD4AD600AC4899 /* Sources */, 134 | 7CBE1DC81FCD4AD600AC4899 /* Frameworks */, 135 | 7CBE1DC91FCD4AD600AC4899 /* Resources */, 136 | ); 137 | buildRules = ( 138 | ); 139 | dependencies = ( 140 | ); 141 | name = ZWMGuideViewDemo; 142 | productName = ZWMGuideViewDemo; 143 | productReference = 7CBE1DCB1FCD4AD600AC4899 /* ZWMGuideViewDemo.app */; 144 | productType = "com.apple.product-type.application"; 145 | }; 146 | 7CBE1DE21FCD4AD700AC4899 /* ZWMGuideViewDemoUITests */ = { 147 | isa = PBXNativeTarget; 148 | buildConfigurationList = 7CBE1DEF1FCD4AD700AC4899 /* Build configuration list for PBXNativeTarget "ZWMGuideViewDemoUITests" */; 149 | buildPhases = ( 150 | 7CBE1DDF1FCD4AD700AC4899 /* Sources */, 151 | 7CBE1DE01FCD4AD700AC4899 /* Frameworks */, 152 | 7CBE1DE11FCD4AD700AC4899 /* Resources */, 153 | ); 154 | buildRules = ( 155 | ); 156 | dependencies = ( 157 | 7CBE1DE51FCD4AD700AC4899 /* PBXTargetDependency */, 158 | ); 159 | name = ZWMGuideViewDemoUITests; 160 | productName = ZWMGuideViewDemoUITests; 161 | productReference = 7CBE1DE31FCD4AD700AC4899 /* ZWMGuideViewDemoUITests.xctest */; 162 | productType = "com.apple.product-type.bundle.ui-testing"; 163 | }; 164 | /* End PBXNativeTarget section */ 165 | 166 | /* Begin PBXProject section */ 167 | 7CBE1DC31FCD4AD600AC4899 /* Project object */ = { 168 | isa = PBXProject; 169 | attributes = { 170 | LastUpgradeCheck = 0900; 171 | ORGANIZATIONNAME = com.zhongzhou; 172 | TargetAttributes = { 173 | 7CBE1DCA1FCD4AD600AC4899 = { 174 | CreatedOnToolsVersion = 9.0; 175 | ProvisioningStyle = Automatic; 176 | }; 177 | 7CBE1DE21FCD4AD700AC4899 = { 178 | CreatedOnToolsVersion = 9.0; 179 | ProvisioningStyle = Automatic; 180 | TestTargetID = 7CBE1DCA1FCD4AD600AC4899; 181 | }; 182 | }; 183 | }; 184 | buildConfigurationList = 7CBE1DC61FCD4AD600AC4899 /* Build configuration list for PBXProject "ZWMGuideViewDemo" */; 185 | compatibilityVersion = "Xcode 8.0"; 186 | developmentRegion = en; 187 | hasScannedForEncodings = 0; 188 | knownRegions = ( 189 | en, 190 | Base, 191 | ); 192 | mainGroup = 7CBE1DC21FCD4AD600AC4899; 193 | productRefGroup = 7CBE1DCC1FCD4AD600AC4899 /* Products */; 194 | projectDirPath = ""; 195 | projectRoot = ""; 196 | targets = ( 197 | 7CBE1DCA1FCD4AD600AC4899 /* ZWMGuideViewDemo */, 198 | 7CBE1DE21FCD4AD700AC4899 /* ZWMGuideViewDemoUITests */, 199 | ); 200 | }; 201 | /* End PBXProject section */ 202 | 203 | /* Begin PBXResourcesBuildPhase section */ 204 | 7CBE1DC91FCD4AD600AC4899 /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | 7CBE1DDB1FCD4AD700AC4899 /* LaunchScreen.storyboard in Resources */, 209 | 7CBE1DD81FCD4AD700AC4899 /* Assets.xcassets in Resources */, 210 | 7CBE1DD61FCD4AD700AC4899 /* Main.storyboard in Resources */, 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | }; 214 | 7CBE1DE11FCD4AD700AC4899 /* Resources */ = { 215 | isa = PBXResourcesBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | }; 221 | /* End PBXResourcesBuildPhase section */ 222 | 223 | /* Begin PBXSourcesBuildPhase section */ 224 | 7CBE1DC71FCD4AD600AC4899 /* Sources */ = { 225 | isa = PBXSourcesBuildPhase; 226 | buildActionMask = 2147483647; 227 | files = ( 228 | 7CBE1DF81FCD583100AC4899 /* SecondViewController.m in Sources */, 229 | 7CBE1DF51FCD4D0000AC4899 /* ZWMGuideView.m in Sources */, 230 | 7CBE1DD31FCD4AD700AC4899 /* ViewController.m in Sources */, 231 | 7CBE1DDE1FCD4AD700AC4899 /* main.m in Sources */, 232 | 7CBE1DD01FCD4AD700AC4899 /* AppDelegate.m in Sources */, 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | 7CBE1DDF1FCD4AD700AC4899 /* Sources */ = { 237 | isa = PBXSourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | 7CBE1DE81FCD4AD700AC4899 /* ZWMGuideViewDemoUITests.m in Sources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXSourcesBuildPhase section */ 245 | 246 | /* Begin PBXTargetDependency section */ 247 | 7CBE1DE51FCD4AD700AC4899 /* PBXTargetDependency */ = { 248 | isa = PBXTargetDependency; 249 | target = 7CBE1DCA1FCD4AD600AC4899 /* ZWMGuideViewDemo */; 250 | targetProxy = 7CBE1DE41FCD4AD700AC4899 /* PBXContainerItemProxy */; 251 | }; 252 | /* End PBXTargetDependency section */ 253 | 254 | /* Begin PBXVariantGroup section */ 255 | 7CBE1DD41FCD4AD700AC4899 /* Main.storyboard */ = { 256 | isa = PBXVariantGroup; 257 | children = ( 258 | 7CBE1DD51FCD4AD700AC4899 /* Base */, 259 | ); 260 | name = Main.storyboard; 261 | sourceTree = ""; 262 | }; 263 | 7CBE1DD91FCD4AD700AC4899 /* LaunchScreen.storyboard */ = { 264 | isa = PBXVariantGroup; 265 | children = ( 266 | 7CBE1DDA1FCD4AD700AC4899 /* Base */, 267 | ); 268 | name = LaunchScreen.storyboard; 269 | sourceTree = ""; 270 | }; 271 | /* End PBXVariantGroup section */ 272 | 273 | /* Begin XCBuildConfiguration section */ 274 | 7CBE1DEA1FCD4AD700AC4899 /* Debug */ = { 275 | isa = XCBuildConfiguration; 276 | buildSettings = { 277 | ALWAYS_SEARCH_USER_PATHS = NO; 278 | CLANG_ANALYZER_NONNULL = YES; 279 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 280 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 281 | CLANG_CXX_LIBRARY = "libc++"; 282 | CLANG_ENABLE_MODULES = YES; 283 | CLANG_ENABLE_OBJC_ARC = YES; 284 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 285 | CLANG_WARN_BOOL_CONVERSION = YES; 286 | CLANG_WARN_COMMA = YES; 287 | CLANG_WARN_CONSTANT_CONVERSION = YES; 288 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 289 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 290 | CLANG_WARN_EMPTY_BODY = YES; 291 | CLANG_WARN_ENUM_CONVERSION = YES; 292 | CLANG_WARN_INFINITE_RECURSION = YES; 293 | CLANG_WARN_INT_CONVERSION = YES; 294 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 295 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 296 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 297 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 298 | CLANG_WARN_STRICT_PROTOTYPES = YES; 299 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 300 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 301 | CLANG_WARN_UNREACHABLE_CODE = YES; 302 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 303 | CODE_SIGN_IDENTITY = "iPhone Developer"; 304 | COPY_PHASE_STRIP = NO; 305 | DEBUG_INFORMATION_FORMAT = dwarf; 306 | ENABLE_STRICT_OBJC_MSGSEND = YES; 307 | ENABLE_TESTABILITY = YES; 308 | GCC_C_LANGUAGE_STANDARD = gnu11; 309 | GCC_DYNAMIC_NO_PIC = NO; 310 | GCC_NO_COMMON_BLOCKS = YES; 311 | GCC_OPTIMIZATION_LEVEL = 0; 312 | GCC_PREPROCESSOR_DEFINITIONS = ( 313 | "DEBUG=1", 314 | "$(inherited)", 315 | ); 316 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 317 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 318 | GCC_WARN_UNDECLARED_SELECTOR = YES; 319 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 320 | GCC_WARN_UNUSED_FUNCTION = YES; 321 | GCC_WARN_UNUSED_VARIABLE = YES; 322 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 323 | MTL_ENABLE_DEBUG_INFO = YES; 324 | ONLY_ACTIVE_ARCH = YES; 325 | SDKROOT = iphoneos; 326 | }; 327 | name = Debug; 328 | }; 329 | 7CBE1DEB1FCD4AD700AC4899 /* Release */ = { 330 | isa = XCBuildConfiguration; 331 | buildSettings = { 332 | ALWAYS_SEARCH_USER_PATHS = NO; 333 | CLANG_ANALYZER_NONNULL = YES; 334 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 335 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 336 | CLANG_CXX_LIBRARY = "libc++"; 337 | CLANG_ENABLE_MODULES = YES; 338 | CLANG_ENABLE_OBJC_ARC = YES; 339 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 340 | CLANG_WARN_BOOL_CONVERSION = YES; 341 | CLANG_WARN_COMMA = YES; 342 | CLANG_WARN_CONSTANT_CONVERSION = YES; 343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 344 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 345 | CLANG_WARN_EMPTY_BODY = YES; 346 | CLANG_WARN_ENUM_CONVERSION = YES; 347 | CLANG_WARN_INFINITE_RECURSION = YES; 348 | CLANG_WARN_INT_CONVERSION = YES; 349 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 350 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 351 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 352 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 353 | CLANG_WARN_STRICT_PROTOTYPES = YES; 354 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 355 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 356 | CLANG_WARN_UNREACHABLE_CODE = YES; 357 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 358 | CODE_SIGN_IDENTITY = "iPhone Developer"; 359 | COPY_PHASE_STRIP = NO; 360 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 361 | ENABLE_NS_ASSERTIONS = NO; 362 | ENABLE_STRICT_OBJC_MSGSEND = YES; 363 | GCC_C_LANGUAGE_STANDARD = gnu11; 364 | GCC_NO_COMMON_BLOCKS = YES; 365 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 366 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 367 | GCC_WARN_UNDECLARED_SELECTOR = YES; 368 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 369 | GCC_WARN_UNUSED_FUNCTION = YES; 370 | GCC_WARN_UNUSED_VARIABLE = YES; 371 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 372 | MTL_ENABLE_DEBUG_INFO = NO; 373 | SDKROOT = iphoneos; 374 | VALIDATE_PRODUCT = YES; 375 | }; 376 | name = Release; 377 | }; 378 | 7CBE1DED1FCD4AD700AC4899 /* Debug */ = { 379 | isa = XCBuildConfiguration; 380 | buildSettings = { 381 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 382 | CODE_SIGN_STYLE = Automatic; 383 | DEVELOPMENT_TEAM = 345KV6SH8T; 384 | INFOPLIST_FILE = ZWMGuideViewDemo/Info.plist; 385 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 386 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 387 | PRODUCT_BUNDLE_IDENTIFIER = com.zingrow.ZWMGuideViewDemo; 388 | PRODUCT_NAME = "$(TARGET_NAME)"; 389 | TARGETED_DEVICE_FAMILY = "1,2"; 390 | }; 391 | name = Debug; 392 | }; 393 | 7CBE1DEE1FCD4AD700AC4899 /* Release */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 397 | CODE_SIGN_STYLE = Automatic; 398 | DEVELOPMENT_TEAM = 345KV6SH8T; 399 | INFOPLIST_FILE = ZWMGuideViewDemo/Info.plist; 400 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 401 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 402 | PRODUCT_BUNDLE_IDENTIFIER = com.zingrow.ZWMGuideViewDemo; 403 | PRODUCT_NAME = "$(TARGET_NAME)"; 404 | TARGETED_DEVICE_FAMILY = "1,2"; 405 | }; 406 | name = Release; 407 | }; 408 | 7CBE1DF01FCD4AD700AC4899 /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | buildSettings = { 411 | CODE_SIGN_STYLE = Automatic; 412 | DEVELOPMENT_TEAM = 345KV6SH8T; 413 | INFOPLIST_FILE = ZWMGuideViewDemoUITests/Info.plist; 414 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 415 | PRODUCT_BUNDLE_IDENTIFIER = com.zingrow.ZWMGuideViewDemoUITests; 416 | PRODUCT_NAME = "$(TARGET_NAME)"; 417 | TARGETED_DEVICE_FAMILY = "1,2"; 418 | TEST_TARGET_NAME = ZWMGuideViewDemo; 419 | }; 420 | name = Debug; 421 | }; 422 | 7CBE1DF11FCD4AD700AC4899 /* Release */ = { 423 | isa = XCBuildConfiguration; 424 | buildSettings = { 425 | CODE_SIGN_STYLE = Automatic; 426 | DEVELOPMENT_TEAM = 345KV6SH8T; 427 | INFOPLIST_FILE = ZWMGuideViewDemoUITests/Info.plist; 428 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 429 | PRODUCT_BUNDLE_IDENTIFIER = com.zingrow.ZWMGuideViewDemoUITests; 430 | PRODUCT_NAME = "$(TARGET_NAME)"; 431 | TARGETED_DEVICE_FAMILY = "1,2"; 432 | TEST_TARGET_NAME = ZWMGuideViewDemo; 433 | }; 434 | name = Release; 435 | }; 436 | /* End XCBuildConfiguration section */ 437 | 438 | /* Begin XCConfigurationList section */ 439 | 7CBE1DC61FCD4AD600AC4899 /* Build configuration list for PBXProject "ZWMGuideViewDemo" */ = { 440 | isa = XCConfigurationList; 441 | buildConfigurations = ( 442 | 7CBE1DEA1FCD4AD700AC4899 /* Debug */, 443 | 7CBE1DEB1FCD4AD700AC4899 /* Release */, 444 | ); 445 | defaultConfigurationIsVisible = 0; 446 | defaultConfigurationName = Release; 447 | }; 448 | 7CBE1DEC1FCD4AD700AC4899 /* Build configuration list for PBXNativeTarget "ZWMGuideViewDemo" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 7CBE1DED1FCD4AD700AC4899 /* Debug */, 452 | 7CBE1DEE1FCD4AD700AC4899 /* Release */, 453 | ); 454 | defaultConfigurationIsVisible = 0; 455 | defaultConfigurationName = Release; 456 | }; 457 | 7CBE1DEF1FCD4AD700AC4899 /* Build configuration list for PBXNativeTarget "ZWMGuideViewDemoUITests" */ = { 458 | isa = XCConfigurationList; 459 | buildConfigurations = ( 460 | 7CBE1DF01FCD4AD700AC4899 /* Debug */, 461 | 7CBE1DF11FCD4AD700AC4899 /* Release */, 462 | ); 463 | defaultConfigurationIsVisible = 0; 464 | defaultConfigurationName = Release; 465 | }; 466 | /* End XCConfigurationList section */ 467 | }; 468 | rootObject = 7CBE1DC31FCD4AD600AC4899 /* Project object */; 469 | } 470 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo.xcodeproj/project.xcworkspace/xcuserdata/lingcheng.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiming4219/ZWMGuideView/35e9e71848d97ecee04832229a91356607d3a8cd/ZWMGuideViewDemo.xcodeproj/project.xcworkspace/xcuserdata/lingcheng.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ZWMGuideViewDemo.xcodeproj/xcuserdata/lingcheng.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo.xcodeproj/xcuserdata/lingcheng.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ZWMGuideViewDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ZWMGuideViewDemo 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. 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 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ZWMGuideViewDemo 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. 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 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /ZWMGuideViewDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ZWMGuideViewDemo/Assets.xcassets/arrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "添加题目引导箭头.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /ZWMGuideViewDemo/Assets.xcassets/arrow.imageset/添加题目引导箭头.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiming4219/ZWMGuideView/35e9e71848d97ecee04832229a91356607d3a8cd/ZWMGuideViewDemo/Assets.xcassets/arrow.imageset/添加题目引导箭头.png -------------------------------------------------------------------------------- /ZWMGuideViewDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/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 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 97 | 110 | 111 | 112 | 113 | 114 | 115 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // ZWMGuideViewDemo 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SecondViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // ZWMGuideViewDemo 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. All rights reserved. 7 | // 8 | 9 | #import "SecondViewController.h" 10 | #import "ZWMGuideView.h" 11 | 12 | @interface SecondViewController () 13 | @property (strong, nonatomic) IBOutletCollection(UIView) NSArray *viewsArray; 14 | @property (strong, nonatomic) ZWMGuideView *guideView; 15 | @property (strong, nonatomic) NSArray *descriptionArrar; 16 | @end 17 | 18 | @implementation SecondViewController 19 | - (ZWMGuideView *)guideView 20 | { 21 | if (_guideView == nil) { 22 | _guideView = [[ZWMGuideView alloc] initWithFrame:self.view.bounds]; 23 | _guideView.dataSource = self; 24 | _guideView.delegate = self; 25 | } 26 | return _guideView; 27 | } 28 | 29 | - (void)viewDidLoad { 30 | [super viewDidLoad]; 31 | self.title=@"新手引导页"; 32 | self.descriptionArrar = @[@"^^提莫队长正在送命^^!", 33 | @"^^我的大屌早已饥渴难耐了^^!", 34 | @"^^人人都会打飞机^^!", 35 | @"^^我好想射点儿什么^^!", 36 | @"^^你的剑就是我的剑^^!", 37 | @"^^见识下真正的坑货吧^^!", 38 | @"欢迎来到小学生联盟! 小学生还有30秒到达战场!碾碎他们!全军出鸡!"]; 39 | [self.guideView show]; 40 | } 41 | 42 | - (IBAction)again:(id)sender { 43 | [self.guideView show]; 44 | } 45 | 46 | #pragma mark -- ZWMGuideViewDataSource(必须实现的数据源方法) 47 | - (NSInteger)numberOfItemsInGuideMaskView:(ZWMGuideView *)guideMaskView{ 48 | return self.viewsArray.count; 49 | 50 | } 51 | - (UIView *)guideMaskView:(ZWMGuideView *)guideMaskView viewForItemAtIndex:(NSInteger)index{ 52 | return self.viewsArray[index]; 53 | 54 | } 55 | - (NSString *)guideMaskView:(ZWMGuideView *)guideMaskView descriptionLabelForItemAtIndex:(NSInteger)index{ 56 | return self.descriptionArrar[index]; 57 | } 58 | 59 | #pragma mark -- ZWMGuideViewLayoutDelegate 60 | - (CGFloat)guideMaskView:(ZWMGuideView *)guideMaskView cornerRadiusForItemAtIndex:(NSInteger)index 61 | { 62 | if (index == self.viewsArray.count-1) 63 | { 64 | return 30; 65 | } 66 | 67 | return 5; 68 | } 69 | - (UIEdgeInsets)guideMaskView:(ZWMGuideView *)guideMaskView insetsForItemAtIndex:(NSInteger)index{ 70 | return UIEdgeInsetsMake(-10, -10, -10, -10); 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ZWMGuideViewDemo 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ZWMGuideViewDemo 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (IBAction)clickButton:(id)sender { 18 | NSLog(@"去查看引导页"); 19 | } 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | self.title=@"Demo"; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/ZWMGuideView/ZWMGuideView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZWMGuideView.h 3 | // ZWMGuideViewDemo 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ZWMGuideView; 12 | 13 | @protocol ZWMGuideViewDataSource 14 | @required 15 | /** 16 | Item的个数 17 | */ 18 | - (NSInteger)numberOfItemsInGuideMaskView:(ZWMGuideView *)guideMaskView; 19 | 20 | /** 21 | 每个Item对应的的view 22 | */ 23 | - (UIView *)guideMaskView:(ZWMGuideView *)guideMaskView viewForItemAtIndex:(NSInteger)index; 24 | 25 | /** 26 | 每个Item对应的的描述 27 | */ 28 | - (NSString *)guideMaskView:(ZWMGuideView *)guideMaskView descriptionLabelForItemAtIndex:(NSInteger)index; 29 | 30 | @optional 31 | /** 32 | 描述文字的颜色:默认白色 33 | */ 34 | - (UIColor *)guideMaskView:(ZWMGuideView *)guideMaskView colorForDescriptionLabelAtIndex:(NSInteger)index; 35 | 36 | /** 37 | 描述文字的大小:默认15 38 | */ 39 | - (UIFont *)guideMaskView:(ZWMGuideView *)guideMaskView fontForDescriptionLabelAtIndex:(NSInteger)index; 40 | 41 | @end 42 | 43 | 44 | @protocol ZWMGuideViewLayoutDelegate 45 | @optional 46 | 47 | /** 48 | 每个Item的蒙版的圆角:默认为5 49 | */ 50 | - (CGFloat)guideMaskView:(ZWMGuideView *)guideMaskView cornerRadiusForItemAtIndex:(NSInteger)index; 51 | 52 | /** 53 | 每个Item与蒙版的边距:默认为(-8, -8, -8, -8) 54 | */ 55 | - (UIEdgeInsets)guideMaskView:(ZWMGuideView *)guideMaskView insetsForItemAtIndex:(NSInteger)index; 56 | 57 | /** 58 | 每个Item的子视图的间距:默认为 10(子视图包括当前的view、arrowImage、textLabel) 59 | */ 60 | - (CGFloat)guideMaskView:(ZWMGuideView *)guideMaskView spaceForSubviewsAtIndex:(NSInteger)index; 61 | 62 | /** 63 | 每个Item的文字与左右边框的间距:默认为 50 64 | */ 65 | - (CGFloat)guideMaskView:(ZWMGuideView *)guideMaskView horizontalSpaceForDescriptionLabelAtIndex:(NSInteger)index; 66 | @end 67 | 68 | @interface ZWMGuideView : UIView 69 | @property (strong, nonatomic) UIImage *arrowImage; 70 | @property (strong, nonatomic) UIColor *maskBackgroundColor; 71 | @property (assign, nonatomic) CGFloat maskAlpha; 72 | @property (weak, nonatomic) id dataSource; 73 | @property (weak, nonatomic) id delegate; 74 | 75 | - (void)show; 76 | @end 77 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/ZWMGuideView/ZWMGuideView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZWMGuideView.m 3 | // ZWMGuideViewDemo 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. All rights reserved. 7 | // 8 | 9 | #import "ZWMGuideView.h" 10 | 11 | typedef NS_ENUM(NSInteger, ZWMGuideMaskItemRegion) 12 | { 13 | ZWMGuideMaskItemRegionLeftTop = 0, 14 | ZWMGuideMaskItemRegionLeftBottom, 15 | ZWMGuideMaskItemRegionRightTop, 16 | ZWMGuideMaskItemRegionRightBottom 17 | }; 18 | 19 | @interface ZWMGuideView() 20 | @property (strong, nonatomic) UIImageView *arrowImgView; 21 | @property (strong, nonatomic) UILabel *textLabel; 22 | @property (strong, nonatomic) UIView *maskView; 23 | @property (strong, nonatomic) CAShapeLayer *maskLayer; 24 | @property (assign, nonatomic) NSInteger currentIndex; 25 | @end 26 | 27 | @implementation ZWMGuideView 28 | { 29 | NSInteger _count; //记录items总数 30 | } 31 | #pragma mark - 懒加载 32 | - (CAShapeLayer *)maskLayer 33 | { 34 | if (!_maskLayer) 35 | { 36 | _maskLayer = [CAShapeLayer layer]; 37 | } 38 | return _maskLayer; 39 | } 40 | 41 | - (UIView *)maskView 42 | { 43 | if (!_maskView) 44 | { 45 | _maskView = [[UIView alloc] initWithFrame:self.bounds]; 46 | } 47 | return _maskView; 48 | } 49 | 50 | - (UILabel *)textLabel 51 | { 52 | if (!_textLabel) 53 | { 54 | _textLabel = [UILabel new]; 55 | _textLabel.numberOfLines = 0; 56 | } 57 | return _textLabel; 58 | } 59 | 60 | - (UIImageView *)arrowImgView 61 | { 62 | if (!_arrowImgView) 63 | { 64 | _arrowImgView = [UIImageView new]; 65 | } 66 | return _arrowImgView; 67 | } 68 | 69 | #pragma mark - Init Method 70 | - (instancetype)initWithFrame:(CGRect)frame 71 | { 72 | if (self = [super initWithFrame:frame]) 73 | { 74 | [self setupUI]; 75 | } 76 | return self; 77 | } 78 | 79 | - (void)setupUI 80 | { 81 | /// 添加子视图 82 | [self addSubview:self.maskView]; 83 | [self addSubview:self.arrowImgView]; 84 | [self addSubview:self.textLabel]; 85 | 86 | /// 设置默认数据 87 | self.backgroundColor = [UIColor clearColor]; 88 | self.maskBackgroundColor = [UIColor blackColor]; 89 | self.maskAlpha = .7f; 90 | self.arrowImage = [UIImage imageNamed:@"arrow"]; 91 | 92 | self.textLabel.textColor = [UIColor whiteColor]; 93 | self.textLabel.font = [UIFont systemFontOfSize:15]; 94 | } 95 | 96 | 97 | #pragma mark - Setter Method 98 | - (void)setArrowImage:(UIImage *)arrowImage 99 | { 100 | _arrowImage = arrowImage; 101 | self.arrowImgView.image = arrowImage; 102 | } 103 | 104 | - (void)setMaskBackgroundColor:(UIColor *)maskBackgroundColor 105 | { 106 | _maskBackgroundColor = maskBackgroundColor; 107 | self.maskView.backgroundColor = maskBackgroundColor; 108 | } 109 | 110 | - (void)setMaskAlpha:(CGFloat)maskAlpha 111 | { 112 | _maskAlpha = maskAlpha; 113 | self.maskView.alpha = maskAlpha; 114 | } 115 | 116 | - (void)setCurrentIndex:(NSInteger)currentIndex 117 | { 118 | _currentIndex = currentIndex; 119 | [self showMask]; 120 | [self configureItemsFrame]; 121 | } 122 | 123 | #pragma mark - Privite Method 124 | 125 | /** 126 | * 显示蒙板 127 | */ 128 | - (void)showMask 129 | { 130 | CGPathRef fromPath = self.maskLayer.path; 131 | 132 | /// 更新 maskLayer 的 尺寸 133 | self.maskLayer.frame = self.bounds; 134 | self.maskLayer.fillColor = [UIColor blackColor].CGColor; 135 | 136 | CGFloat maskCornerRadius = 5; 137 | 138 | if (self.delegate && [self.delegate respondsToSelector:@selector(guideMaskView:cornerRadiusForItemAtIndex:)]) 139 | { 140 | maskCornerRadius = [self.delegate guideMaskView:self cornerRadiusForItemAtIndex:self.currentIndex]; 141 | } 142 | 143 | /// 获取可见区域的路径(开始路径) 144 | UIBezierPath *visualPath = [UIBezierPath bezierPathWithRoundedRect:[self obtainVisualFrame] cornerRadius:maskCornerRadius]; 145 | 146 | /// 获取终点路径 147 | UIBezierPath *toPath = [UIBezierPath bezierPathWithRect:self.bounds]; 148 | 149 | [toPath appendPath:visualPath]; 150 | 151 | /// 遮罩的路径 152 | self.maskLayer.path = toPath.CGPath; 153 | self.maskLayer.fillRule = kCAFillRuleEvenOdd; 154 | self.layer.mask = self.maskLayer; 155 | 156 | /// 开始移动动画 157 | CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"path"]; 158 | anim.duration = 0.3; 159 | anim.fromValue = (__bridge id _Nullable)(fromPath); 160 | anim.toValue = (__bridge id _Nullable)(toPath.CGPath); 161 | [self.maskLayer addAnimation:anim forKey:NULL]; 162 | } 163 | 164 | /** 165 | * 设置 items 的 frame 166 | */ 167 | - (void)configureItemsFrame 168 | { 169 | // 文字颜色 170 | if (self.dataSource && [self.dataSource respondsToSelector:@selector(guideMaskView:colorForDescriptionLabelAtIndex:)]) 171 | { 172 | self.textLabel.textColor = [self.dataSource guideMaskView:self colorForDescriptionLabelAtIndex:self.currentIndex]; 173 | } 174 | // 文字字体 175 | if (self.dataSource && [self.dataSource respondsToSelector:@selector(guideMaskView:fontForDescriptionLabelAtIndex:)]) 176 | { 177 | self.textLabel.font = [self.dataSource guideMaskView:self fontForDescriptionLabelAtIndex:self.currentIndex]; 178 | } 179 | 180 | // 描述文字 181 | NSString *desc = [self.dataSource guideMaskView:self descriptionLabelForItemAtIndex:self.currentIndex]; 182 | self.textLabel.text = desc; 183 | 184 | /// 每个 item 的文字与左右边框间的距离 185 | CGFloat descInsetsX = 50; 186 | 187 | if (self.delegate && [self.delegate respondsToSelector:@selector(guideMaskView:horizontalSpaceForDescriptionLabelAtIndex:)]) 188 | { 189 | descInsetsX = [self.delegate guideMaskView:self horizontalSpaceForDescriptionLabelAtIndex:self.currentIndex]; 190 | } 191 | 192 | /// 每个 item 的子视图(当前介绍的子视图、箭头、描述文字)之间的间距 193 | CGFloat space = 10; 194 | 195 | if (self.delegate && [self.delegate respondsToSelector:@selector(guideMaskView:spaceForSubviewsAtIndex:)]) 196 | { 197 | space = [self.delegate guideMaskView:self spaceForSubviewsAtIndex:self.currentIndex]; 198 | } 199 | 200 | /// 设置 文字 与 箭头的位置 201 | CGRect textRect, arrowRect; 202 | CGSize imgSize = self.arrowImgView.image.size; 203 | CGFloat maxWidth = self.bounds.size.width - descInsetsX * 2; 204 | CGSize textSize = [desc boundingRectWithSize:CGSizeMake(maxWidth, CGFLOAT_MAX) 205 | options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading 206 | attributes:@{NSFontAttributeName : self.textLabel.font} 207 | context:NULL].size; 208 | CGAffineTransform transform = CGAffineTransformIdentity; 209 | 210 | /// 获取 item 的 方位 211 | ZWMGuideMaskItemRegion itemRegion = [self obtainVisualRegion]; 212 | 213 | switch (itemRegion) 214 | { 215 | case ZWMGuideMaskItemRegionLeftTop: 216 | { 217 | /// 左上 218 | transform = CGAffineTransformMakeScale(-1, 1); 219 | arrowRect = CGRectMake(CGRectGetMidX([self obtainVisualFrame]) - imgSize.width * 0.5, 220 | CGRectGetMaxY([self obtainVisualFrame]) + space, 221 | imgSize.width, 222 | imgSize.height); 223 | CGFloat x = 0; 224 | 225 | if (textSize.width < CGRectGetWidth([self obtainVisualFrame])) 226 | { 227 | x = CGRectGetMaxX(arrowRect) - textSize.width * 0.5; 228 | } 229 | else 230 | { 231 | x = descInsetsX; 232 | } 233 | 234 | textRect = CGRectMake(x, CGRectGetMaxY(arrowRect) + space, textSize.width, textSize.height); 235 | break; 236 | } 237 | case ZWMGuideMaskItemRegionRightTop: 238 | { 239 | /// 右上 240 | arrowRect = CGRectMake(CGRectGetMidX([self obtainVisualFrame]) - imgSize.width * 0.5, 241 | CGRectGetMaxY([self obtainVisualFrame]) + space, 242 | imgSize.width, 243 | imgSize.height); 244 | 245 | CGFloat x = 0; 246 | 247 | if (textSize.width < CGRectGetWidth([self obtainVisualFrame])) 248 | { 249 | x = CGRectGetMinX(arrowRect) - textSize.width * 0.5; 250 | } 251 | else 252 | { 253 | x = descInsetsX + maxWidth - textSize.width; 254 | } 255 | 256 | textRect = CGRectMake(x, CGRectGetMaxY(arrowRect) + space, textSize.width, textSize.height); 257 | break; 258 | } 259 | case ZWMGuideMaskItemRegionLeftBottom: 260 | { 261 | /// 左下 262 | transform = CGAffineTransformMakeScale(-1, -1); 263 | arrowRect = CGRectMake(CGRectGetMidX([self obtainVisualFrame]) - imgSize.width * 0.5, 264 | CGRectGetMinY([self obtainVisualFrame]) - space - imgSize.height, 265 | imgSize.width, 266 | imgSize.height); 267 | 268 | CGFloat x = 0; 269 | 270 | if (textSize.width < CGRectGetWidth([self obtainVisualFrame])) 271 | { 272 | x = CGRectGetMaxX(arrowRect) - textSize.width * 0.5; 273 | } 274 | else 275 | { 276 | x = descInsetsX; 277 | } 278 | 279 | textRect = CGRectMake(x, CGRectGetMinY(arrowRect) - space - textSize.height, textSize.width, textSize.height); 280 | break; 281 | } 282 | case ZWMGuideMaskItemRegionRightBottom: 283 | { 284 | /// 右下 285 | transform = CGAffineTransformMakeScale(1, -1); 286 | arrowRect = CGRectMake(CGRectGetMidX([self obtainVisualFrame]) - imgSize.width * 0.5, 287 | CGRectGetMinY([self obtainVisualFrame]) - space - imgSize.height, 288 | imgSize.width, 289 | imgSize.height); 290 | 291 | CGFloat x = 0; 292 | 293 | if (textSize.width < CGRectGetWidth([self obtainVisualFrame])) 294 | { 295 | x = CGRectGetMinX(arrowRect) - textSize.width * 0.5; 296 | } 297 | else 298 | { 299 | x = descInsetsX + maxWidth - textSize.width; 300 | } 301 | 302 | textRect = CGRectMake(x, CGRectGetMinY(arrowRect) - space - textSize.height, textSize.width, textSize.height); 303 | break; 304 | } 305 | } 306 | 307 | /// 图片 和 文字的动画 308 | [UIView animateWithDuration:0.3 animations:^{ 309 | self.arrowImgView.transform = transform; 310 | self.arrowImgView.frame = arrowRect; 311 | self.textLabel.frame = textRect; 312 | }]; 313 | } 314 | 315 | /** 316 | * 获取可见的视图的frame 317 | */ 318 | - (CGRect)obtainVisualFrame 319 | { 320 | if (self.currentIndex >= _count) 321 | { 322 | return CGRectZero; 323 | } 324 | 325 | UIView *view = [self.dataSource guideMaskView:self viewForItemAtIndex:self.currentIndex]; 326 | 327 | CGRect visualRect = [self convertRect:view.frame fromView:view.superview]; 328 | 329 | /// 每个 item 的 view 与蒙板的边距 330 | UIEdgeInsets maskInsets = UIEdgeInsetsMake(-8, -8, -8, -8); 331 | 332 | if (self.delegate && [self.delegate respondsToSelector:@selector(guideMaskView:insetsForItemAtIndex:)]) 333 | { 334 | maskInsets = [self.delegate guideMaskView:self insetsForItemAtIndex:self.currentIndex]; 335 | } 336 | 337 | visualRect.origin.x += maskInsets.left; 338 | visualRect.origin.y += maskInsets.top; 339 | visualRect.size.width -= (maskInsets.left + maskInsets.right); 340 | visualRect.size.height -= (maskInsets.top + maskInsets.bottom); 341 | 342 | return visualRect; 343 | } 344 | 345 | /** 346 | * 获取可见区域的方位 347 | */ 348 | - (ZWMGuideMaskItemRegion)obtainVisualRegion 349 | { 350 | /// 可见区域的中心坐标 351 | CGPoint visualCenter = CGPointMake(CGRectGetMidX([self obtainVisualFrame]), 352 | CGRectGetMidY([self obtainVisualFrame])); 353 | /// self.view 的中心坐标 354 | CGPoint viewCenter = CGPointMake(CGRectGetMidX(self.bounds), 355 | CGRectGetMidY(self.bounds)); 356 | 357 | if ((visualCenter.x <= viewCenter.x) && 358 | (visualCenter.y <= viewCenter.y)) 359 | { 360 | /// 当前显示的视图在左上角 361 | return ZWMGuideMaskItemRegionLeftTop; 362 | } 363 | 364 | if ((visualCenter.x > viewCenter.x) && 365 | (visualCenter.y <= viewCenter.y)) 366 | { 367 | /// 当前显示的视图在右上角 368 | return ZWMGuideMaskItemRegionRightTop; 369 | } 370 | 371 | if ((visualCenter.x <= viewCenter.x) && 372 | (visualCenter.y > viewCenter.y)) 373 | { 374 | /// 当前显示的视图在左下角 375 | return ZWMGuideMaskItemRegionLeftBottom; 376 | } 377 | 378 | /// 当前显示的视图在右下角 379 | return ZWMGuideMaskItemRegionRightBottom; 380 | } 381 | 382 | 383 | #pragma mark - Public Method 384 | 385 | /** 386 | * 显示 387 | */ 388 | - (void)show 389 | { 390 | if (self.dataSource) 391 | { 392 | _count = [self.dataSource numberOfItemsInGuideMaskView:self]; 393 | } 394 | 395 | /// 如果当前没有可以显示的 item 的数量 396 | if (_count < 1) return; 397 | 398 | [[UIApplication sharedApplication].keyWindow addSubview:self]; 399 | 400 | self.alpha = 0; 401 | 402 | [UIView animateWithDuration:.3f animations:^{ 403 | 404 | self.alpha = 1; 405 | }]; 406 | 407 | /// 从 0 开始进行显示 408 | self.currentIndex = 0; 409 | } 410 | 411 | #pragma mark - Action Method 412 | 413 | /** 414 | * 隐藏 415 | */ 416 | - (void)hide 417 | { 418 | [UIView animateWithDuration:.3f animations:^{ 419 | 420 | self.alpha = 0; 421 | 422 | } completion:^(BOOL finished) { 423 | 424 | [self removeFromSuperview]; 425 | }]; 426 | } 427 | 428 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 429 | { 430 | /** 431 | * 如果当前下标不是最后一个,则移到下一个介绍的视图 432 | * 如果当前下标是最后一个,则直接返回 433 | */ 434 | if (self.currentIndex < _count-1) 435 | { 436 | self.currentIndex ++; 437 | } 438 | else 439 | { 440 | [self hide]; 441 | } 442 | } 443 | 444 | @end 445 | -------------------------------------------------------------------------------- /ZWMGuideViewDemo/guide.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiming4219/ZWMGuideView/35e9e71848d97ecee04832229a91356607d3a8cd/ZWMGuideViewDemo/guide.gif -------------------------------------------------------------------------------- /ZWMGuideViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ZWMGuideViewDemo 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. 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 | -------------------------------------------------------------------------------- /ZWMGuideViewDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ZWMGuideViewDemoUITests/ZWMGuideViewDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZWMGuideViewDemoUITests.m 3 | // ZWMGuideViewDemoUITests 4 | // 5 | // Created by 伟明 on 2017/11/28. 6 | // Copyright © 2017年 com.zhongzhou. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ZWMGuideViewDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation ZWMGuideViewDemoUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | --------------------------------------------------------------------------------