├── README.md ├── TagGroupDemo ├── TagGroupDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ ├── chanli.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ │ └── zmw.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ ├── chanli.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ ├── TagGroupDemo.xcscheme │ │ │ └── xcschememanagement.plist │ │ └── zmw.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── TagGroupDemo.xcscheme │ │ └── xcschememanagement.plist ├── TagGroupDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── camera_color_other.imageset │ │ │ ├── Contents.json │ │ │ ├── camera_color_other.png │ │ │ ├── camera_color_other@2x.png │ │ │ └── camera_color_other@3x.png │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── MaxLightingView.h │ ├── MaxLightingView.m │ ├── MaxShapeView.h │ ├── MaxShapeView.m │ ├── NSString+SizeWithFont.h │ ├── NSString+SizeWithFont.m │ ├── NSTimer │ │ ├── NSTimer+Addition.h │ │ └── NSTimer+Addition.m │ ├── ViewController.h │ ├── ViewController.m │ ├── main.m │ └── meinv.jpg ├── TagGroupDemoTests │ ├── Info.plist │ └── TagGroupDemoTests.m └── TagGroupDemoUITests │ ├── Info.plist │ └── TagGroupDemoUITests.m └── gif └── Untitled.gif /README.md: -------------------------------------------------------------------------------- 1 | # ShapeView 2 | 模仿小红书的标签选择 3 | 支持一个、两个、三个的标签 4 | ![](https://github.com/zmw123/ShapeView/raw/master/gif/Untitled.gif) 5 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C40C70EE1CD839760099AF6A /* NSTimer+Addition.m in Sources */ = {isa = PBXBuildFile; fileRef = C40C70ED1CD839760099AF6A /* NSTimer+Addition.m */; }; 11 | C40C70F11CD83A500099AF6A /* MaxLightingView.m in Sources */ = {isa = PBXBuildFile; fileRef = C40C70F01CD83A500099AF6A /* MaxLightingView.m */; }; 12 | C4B124D61CD36AE1009B302A /* meinv.jpg in Resources */ = {isa = PBXBuildFile; fileRef = C4B124D51CD36AE1009B302A /* meinv.jpg */; }; 13 | C4F4EAA81C88335400494A7E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C4F4EAA71C88335400494A7E /* main.m */; }; 14 | C4F4EAAB1C88335400494A7E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C4F4EAAA1C88335400494A7E /* AppDelegate.m */; }; 15 | C4F4EAAE1C88335400494A7E /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C4F4EAAD1C88335400494A7E /* ViewController.m */; }; 16 | C4F4EAB11C88335400494A7E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C4F4EAAF1C88335400494A7E /* Main.storyboard */; }; 17 | C4F4EAB31C88335400494A7E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4F4EAB21C88335400494A7E /* Assets.xcassets */; }; 18 | C4F4EAB61C88335400494A7E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C4F4EAB41C88335400494A7E /* LaunchScreen.storyboard */; }; 19 | C4F4EAC11C88335400494A7E /* TagGroupDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C4F4EAC01C88335400494A7E /* TagGroupDemoTests.m */; }; 20 | C4F4EACC1C88335400494A7E /* TagGroupDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = C4F4EACB1C88335400494A7E /* TagGroupDemoUITests.m */; }; 21 | C4F4EADB1C8833B000494A7E /* MaxShapeView.m in Sources */ = {isa = PBXBuildFile; fileRef = C4F4EADA1C8833B000494A7E /* MaxShapeView.m */; }; 22 | C4F4EADE1C88450600494A7E /* NSString+SizeWithFont.m in Sources */ = {isa = PBXBuildFile; fileRef = C4F4EADD1C88450600494A7E /* NSString+SizeWithFont.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | C4F4EABD1C88335400494A7E /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = C4F4EA9B1C88335400494A7E /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = C4F4EAA21C88335400494A7E; 31 | remoteInfo = TagGroupDemo; 32 | }; 33 | C4F4EAC81C88335400494A7E /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = C4F4EA9B1C88335400494A7E /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = C4F4EAA21C88335400494A7E; 38 | remoteInfo = TagGroupDemo; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | C40C70EC1CD839760099AF6A /* NSTimer+Addition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+Addition.h"; sourceTree = ""; }; 44 | C40C70ED1CD839760099AF6A /* NSTimer+Addition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+Addition.m"; sourceTree = ""; }; 45 | C40C70EF1CD83A500099AF6A /* MaxLightingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MaxLightingView.h; sourceTree = ""; }; 46 | C40C70F01CD83A500099AF6A /* MaxLightingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MaxLightingView.m; sourceTree = ""; }; 47 | C4B124D51CD36AE1009B302A /* meinv.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = meinv.jpg; sourceTree = ""; }; 48 | C4F4EAA31C88335400494A7E /* TagGroupDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TagGroupDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | C4F4EAA71C88335400494A7E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 50 | C4F4EAA91C88335400494A7E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 51 | C4F4EAAA1C88335400494A7E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 52 | C4F4EAAC1C88335400494A7E /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 53 | C4F4EAAD1C88335400494A7E /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 54 | C4F4EAB01C88335400494A7E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | C4F4EAB21C88335400494A7E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56 | C4F4EAB51C88335400494A7E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 57 | C4F4EAB71C88335400494A7E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | C4F4EABC1C88335400494A7E /* TagGroupDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TagGroupDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | C4F4EAC01C88335400494A7E /* TagGroupDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TagGroupDemoTests.m; sourceTree = ""; }; 60 | C4F4EAC21C88335400494A7E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | C4F4EAC71C88335400494A7E /* TagGroupDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TagGroupDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | C4F4EACB1C88335400494A7E /* TagGroupDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TagGroupDemoUITests.m; sourceTree = ""; }; 63 | C4F4EACD1C88335400494A7E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 64 | C4F4EAD91C8833B000494A7E /* MaxShapeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MaxShapeView.h; sourceTree = ""; }; 65 | C4F4EADA1C8833B000494A7E /* MaxShapeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MaxShapeView.m; sourceTree = ""; }; 66 | C4F4EADC1C88450600494A7E /* NSString+SizeWithFont.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SizeWithFont.h"; sourceTree = ""; }; 67 | C4F4EADD1C88450600494A7E /* NSString+SizeWithFont.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SizeWithFont.m"; sourceTree = ""; }; 68 | /* End PBXFileReference section */ 69 | 70 | /* Begin PBXFrameworksBuildPhase section */ 71 | C4F4EAA01C88335400494A7E /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | C4F4EAB91C88335400494A7E /* Frameworks */ = { 79 | isa = PBXFrameworksBuildPhase; 80 | buildActionMask = 2147483647; 81 | files = ( 82 | ); 83 | runOnlyForDeploymentPostprocessing = 0; 84 | }; 85 | C4F4EAC41C88335400494A7E /* Frameworks */ = { 86 | isa = PBXFrameworksBuildPhase; 87 | buildActionMask = 2147483647; 88 | files = ( 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | /* End PBXFrameworksBuildPhase section */ 93 | 94 | /* Begin PBXGroup section */ 95 | C40C70EB1CD839760099AF6A /* NSTimer */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | C40C70EC1CD839760099AF6A /* NSTimer+Addition.h */, 99 | C40C70ED1CD839760099AF6A /* NSTimer+Addition.m */, 100 | ); 101 | path = NSTimer; 102 | sourceTree = ""; 103 | }; 104 | C4F4EA9A1C88335400494A7E = { 105 | isa = PBXGroup; 106 | children = ( 107 | C4F4EAA51C88335400494A7E /* TagGroupDemo */, 108 | C4F4EABF1C88335400494A7E /* TagGroupDemoTests */, 109 | C4F4EACA1C88335400494A7E /* TagGroupDemoUITests */, 110 | C4F4EAA41C88335400494A7E /* Products */, 111 | ); 112 | sourceTree = ""; 113 | }; 114 | C4F4EAA41C88335400494A7E /* Products */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | C4F4EAA31C88335400494A7E /* TagGroupDemo.app */, 118 | C4F4EABC1C88335400494A7E /* TagGroupDemoTests.xctest */, 119 | C4F4EAC71C88335400494A7E /* TagGroupDemoUITests.xctest */, 120 | ); 121 | name = Products; 122 | sourceTree = ""; 123 | }; 124 | C4F4EAA51C88335400494A7E /* TagGroupDemo */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | C40C70EB1CD839760099AF6A /* NSTimer */, 128 | C4B124D51CD36AE1009B302A /* meinv.jpg */, 129 | C4F4EAA91C88335400494A7E /* AppDelegate.h */, 130 | C4F4EAAA1C88335400494A7E /* AppDelegate.m */, 131 | C4F4EAAC1C88335400494A7E /* ViewController.h */, 132 | C4F4EAAD1C88335400494A7E /* ViewController.m */, 133 | C4F4EAAF1C88335400494A7E /* Main.storyboard */, 134 | C4F4EAB21C88335400494A7E /* Assets.xcassets */, 135 | C4F4EAB41C88335400494A7E /* LaunchScreen.storyboard */, 136 | C4F4EAB71C88335400494A7E /* Info.plist */, 137 | C4F4EAA61C88335400494A7E /* Supporting Files */, 138 | C4F4EAD91C8833B000494A7E /* MaxShapeView.h */, 139 | C4F4EADA1C8833B000494A7E /* MaxShapeView.m */, 140 | C40C70EF1CD83A500099AF6A /* MaxLightingView.h */, 141 | C40C70F01CD83A500099AF6A /* MaxLightingView.m */, 142 | C4F4EADC1C88450600494A7E /* NSString+SizeWithFont.h */, 143 | C4F4EADD1C88450600494A7E /* NSString+SizeWithFont.m */, 144 | ); 145 | path = TagGroupDemo; 146 | sourceTree = ""; 147 | }; 148 | C4F4EAA61C88335400494A7E /* Supporting Files */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | C4F4EAA71C88335400494A7E /* main.m */, 152 | ); 153 | name = "Supporting Files"; 154 | sourceTree = ""; 155 | }; 156 | C4F4EABF1C88335400494A7E /* TagGroupDemoTests */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | C4F4EAC01C88335400494A7E /* TagGroupDemoTests.m */, 160 | C4F4EAC21C88335400494A7E /* Info.plist */, 161 | ); 162 | path = TagGroupDemoTests; 163 | sourceTree = ""; 164 | }; 165 | C4F4EACA1C88335400494A7E /* TagGroupDemoUITests */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | C4F4EACB1C88335400494A7E /* TagGroupDemoUITests.m */, 169 | C4F4EACD1C88335400494A7E /* Info.plist */, 170 | ); 171 | path = TagGroupDemoUITests; 172 | sourceTree = ""; 173 | }; 174 | /* End PBXGroup section */ 175 | 176 | /* Begin PBXNativeTarget section */ 177 | C4F4EAA21C88335400494A7E /* TagGroupDemo */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = C4F4EAD01C88335400494A7E /* Build configuration list for PBXNativeTarget "TagGroupDemo" */; 180 | buildPhases = ( 181 | C4F4EA9F1C88335400494A7E /* Sources */, 182 | C4F4EAA01C88335400494A7E /* Frameworks */, 183 | C4F4EAA11C88335400494A7E /* Resources */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | ); 189 | name = TagGroupDemo; 190 | productName = TagGroupDemo; 191 | productReference = C4F4EAA31C88335400494A7E /* TagGroupDemo.app */; 192 | productType = "com.apple.product-type.application"; 193 | }; 194 | C4F4EABB1C88335400494A7E /* TagGroupDemoTests */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = C4F4EAD31C88335400494A7E /* Build configuration list for PBXNativeTarget "TagGroupDemoTests" */; 197 | buildPhases = ( 198 | C4F4EAB81C88335400494A7E /* Sources */, 199 | C4F4EAB91C88335400494A7E /* Frameworks */, 200 | C4F4EABA1C88335400494A7E /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | C4F4EABE1C88335400494A7E /* PBXTargetDependency */, 206 | ); 207 | name = TagGroupDemoTests; 208 | productName = TagGroupDemoTests; 209 | productReference = C4F4EABC1C88335400494A7E /* TagGroupDemoTests.xctest */; 210 | productType = "com.apple.product-type.bundle.unit-test"; 211 | }; 212 | C4F4EAC61C88335400494A7E /* TagGroupDemoUITests */ = { 213 | isa = PBXNativeTarget; 214 | buildConfigurationList = C4F4EAD61C88335400494A7E /* Build configuration list for PBXNativeTarget "TagGroupDemoUITests" */; 215 | buildPhases = ( 216 | C4F4EAC31C88335400494A7E /* Sources */, 217 | C4F4EAC41C88335400494A7E /* Frameworks */, 218 | C4F4EAC51C88335400494A7E /* Resources */, 219 | ); 220 | buildRules = ( 221 | ); 222 | dependencies = ( 223 | C4F4EAC91C88335400494A7E /* PBXTargetDependency */, 224 | ); 225 | name = TagGroupDemoUITests; 226 | productName = TagGroupDemoUITests; 227 | productReference = C4F4EAC71C88335400494A7E /* TagGroupDemoUITests.xctest */; 228 | productType = "com.apple.product-type.bundle.ui-testing"; 229 | }; 230 | /* End PBXNativeTarget section */ 231 | 232 | /* Begin PBXProject section */ 233 | C4F4EA9B1C88335400494A7E /* Project object */ = { 234 | isa = PBXProject; 235 | attributes = { 236 | LastUpgradeCheck = 0720; 237 | ORGANIZATIONNAME = "Beijing ChunFengShiLi Technology Co., Ltd."; 238 | TargetAttributes = { 239 | C4F4EAA21C88335400494A7E = { 240 | CreatedOnToolsVersion = 7.2.1; 241 | }; 242 | C4F4EABB1C88335400494A7E = { 243 | CreatedOnToolsVersion = 7.2.1; 244 | TestTargetID = C4F4EAA21C88335400494A7E; 245 | }; 246 | C4F4EAC61C88335400494A7E = { 247 | CreatedOnToolsVersion = 7.2.1; 248 | TestTargetID = C4F4EAA21C88335400494A7E; 249 | }; 250 | }; 251 | }; 252 | buildConfigurationList = C4F4EA9E1C88335400494A7E /* Build configuration list for PBXProject "TagGroupDemo" */; 253 | compatibilityVersion = "Xcode 3.2"; 254 | developmentRegion = English; 255 | hasScannedForEncodings = 0; 256 | knownRegions = ( 257 | en, 258 | Base, 259 | ); 260 | mainGroup = C4F4EA9A1C88335400494A7E; 261 | productRefGroup = C4F4EAA41C88335400494A7E /* Products */; 262 | projectDirPath = ""; 263 | projectRoot = ""; 264 | targets = ( 265 | C4F4EAA21C88335400494A7E /* TagGroupDemo */, 266 | C4F4EABB1C88335400494A7E /* TagGroupDemoTests */, 267 | C4F4EAC61C88335400494A7E /* TagGroupDemoUITests */, 268 | ); 269 | }; 270 | /* End PBXProject section */ 271 | 272 | /* Begin PBXResourcesBuildPhase section */ 273 | C4F4EAA11C88335400494A7E /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | C4F4EAB61C88335400494A7E /* LaunchScreen.storyboard in Resources */, 278 | C4F4EAB31C88335400494A7E /* Assets.xcassets in Resources */, 279 | C4B124D61CD36AE1009B302A /* meinv.jpg in Resources */, 280 | C4F4EAB11C88335400494A7E /* Main.storyboard in Resources */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | C4F4EABA1C88335400494A7E /* Resources */ = { 285 | isa = PBXResourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | }; 291 | C4F4EAC51C88335400494A7E /* Resources */ = { 292 | isa = PBXResourcesBuildPhase; 293 | buildActionMask = 2147483647; 294 | files = ( 295 | ); 296 | runOnlyForDeploymentPostprocessing = 0; 297 | }; 298 | /* End PBXResourcesBuildPhase section */ 299 | 300 | /* Begin PBXSourcesBuildPhase section */ 301 | C4F4EA9F1C88335400494A7E /* Sources */ = { 302 | isa = PBXSourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | C40C70F11CD83A500099AF6A /* MaxLightingView.m in Sources */, 306 | C4F4EAAE1C88335400494A7E /* ViewController.m in Sources */, 307 | C4F4EAAB1C88335400494A7E /* AppDelegate.m in Sources */, 308 | C4F4EADE1C88450600494A7E /* NSString+SizeWithFont.m in Sources */, 309 | C4F4EAA81C88335400494A7E /* main.m in Sources */, 310 | C4F4EADB1C8833B000494A7E /* MaxShapeView.m in Sources */, 311 | C40C70EE1CD839760099AF6A /* NSTimer+Addition.m in Sources */, 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | }; 315 | C4F4EAB81C88335400494A7E /* Sources */ = { 316 | isa = PBXSourcesBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | C4F4EAC11C88335400494A7E /* TagGroupDemoTests.m in Sources */, 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | C4F4EAC31C88335400494A7E /* Sources */ = { 324 | isa = PBXSourcesBuildPhase; 325 | buildActionMask = 2147483647; 326 | files = ( 327 | C4F4EACC1C88335400494A7E /* TagGroupDemoUITests.m in Sources */, 328 | ); 329 | runOnlyForDeploymentPostprocessing = 0; 330 | }; 331 | /* End PBXSourcesBuildPhase section */ 332 | 333 | /* Begin PBXTargetDependency section */ 334 | C4F4EABE1C88335400494A7E /* PBXTargetDependency */ = { 335 | isa = PBXTargetDependency; 336 | target = C4F4EAA21C88335400494A7E /* TagGroupDemo */; 337 | targetProxy = C4F4EABD1C88335400494A7E /* PBXContainerItemProxy */; 338 | }; 339 | C4F4EAC91C88335400494A7E /* PBXTargetDependency */ = { 340 | isa = PBXTargetDependency; 341 | target = C4F4EAA21C88335400494A7E /* TagGroupDemo */; 342 | targetProxy = C4F4EAC81C88335400494A7E /* PBXContainerItemProxy */; 343 | }; 344 | /* End PBXTargetDependency section */ 345 | 346 | /* Begin PBXVariantGroup section */ 347 | C4F4EAAF1C88335400494A7E /* Main.storyboard */ = { 348 | isa = PBXVariantGroup; 349 | children = ( 350 | C4F4EAB01C88335400494A7E /* Base */, 351 | ); 352 | name = Main.storyboard; 353 | sourceTree = ""; 354 | }; 355 | C4F4EAB41C88335400494A7E /* LaunchScreen.storyboard */ = { 356 | isa = PBXVariantGroup; 357 | children = ( 358 | C4F4EAB51C88335400494A7E /* Base */, 359 | ); 360 | name = LaunchScreen.storyboard; 361 | sourceTree = ""; 362 | }; 363 | /* End PBXVariantGroup section */ 364 | 365 | /* Begin XCBuildConfiguration section */ 366 | C4F4EACE1C88335400494A7E /* Debug */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | ALWAYS_SEARCH_USER_PATHS = NO; 370 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 371 | CLANG_CXX_LIBRARY = "libc++"; 372 | CLANG_ENABLE_MODULES = YES; 373 | CLANG_ENABLE_OBJC_ARC = YES; 374 | CLANG_WARN_BOOL_CONVERSION = YES; 375 | CLANG_WARN_CONSTANT_CONVERSION = YES; 376 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 377 | CLANG_WARN_EMPTY_BODY = YES; 378 | CLANG_WARN_ENUM_CONVERSION = YES; 379 | CLANG_WARN_INT_CONVERSION = YES; 380 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 381 | CLANG_WARN_UNREACHABLE_CODE = YES; 382 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 383 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 384 | COPY_PHASE_STRIP = NO; 385 | DEBUG_INFORMATION_FORMAT = dwarf; 386 | ENABLE_STRICT_OBJC_MSGSEND = YES; 387 | ENABLE_TESTABILITY = YES; 388 | GCC_C_LANGUAGE_STANDARD = gnu99; 389 | GCC_DYNAMIC_NO_PIC = NO; 390 | GCC_NO_COMMON_BLOCKS = YES; 391 | GCC_OPTIMIZATION_LEVEL = 0; 392 | GCC_PREPROCESSOR_DEFINITIONS = ( 393 | "DEBUG=1", 394 | "$(inherited)", 395 | ); 396 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 397 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 398 | GCC_WARN_UNDECLARED_SELECTOR = YES; 399 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 400 | GCC_WARN_UNUSED_FUNCTION = YES; 401 | GCC_WARN_UNUSED_VARIABLE = YES; 402 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 403 | MTL_ENABLE_DEBUG_INFO = YES; 404 | ONLY_ACTIVE_ARCH = YES; 405 | SDKROOT = iphoneos; 406 | }; 407 | name = Debug; 408 | }; 409 | C4F4EACF1C88335400494A7E /* Release */ = { 410 | isa = XCBuildConfiguration; 411 | buildSettings = { 412 | ALWAYS_SEARCH_USER_PATHS = NO; 413 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 414 | CLANG_CXX_LIBRARY = "libc++"; 415 | CLANG_ENABLE_MODULES = YES; 416 | CLANG_ENABLE_OBJC_ARC = YES; 417 | CLANG_WARN_BOOL_CONVERSION = YES; 418 | CLANG_WARN_CONSTANT_CONVERSION = YES; 419 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 420 | CLANG_WARN_EMPTY_BODY = YES; 421 | CLANG_WARN_ENUM_CONVERSION = YES; 422 | CLANG_WARN_INT_CONVERSION = YES; 423 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 424 | CLANG_WARN_UNREACHABLE_CODE = YES; 425 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 427 | COPY_PHASE_STRIP = NO; 428 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 429 | ENABLE_NS_ASSERTIONS = NO; 430 | ENABLE_STRICT_OBJC_MSGSEND = YES; 431 | GCC_C_LANGUAGE_STANDARD = gnu99; 432 | GCC_NO_COMMON_BLOCKS = YES; 433 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 434 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 435 | GCC_WARN_UNDECLARED_SELECTOR = YES; 436 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 437 | GCC_WARN_UNUSED_FUNCTION = YES; 438 | GCC_WARN_UNUSED_VARIABLE = YES; 439 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 440 | MTL_ENABLE_DEBUG_INFO = NO; 441 | SDKROOT = iphoneos; 442 | VALIDATE_PRODUCT = YES; 443 | }; 444 | name = Release; 445 | }; 446 | C4F4EAD11C88335400494A7E /* Debug */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 450 | INFOPLIST_FILE = TagGroupDemo/Info.plist; 451 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 453 | PRODUCT_BUNDLE_IDENTIFIER = com.aotumanlady..TagGroupDemo; 454 | PRODUCT_NAME = "$(TARGET_NAME)"; 455 | }; 456 | name = Debug; 457 | }; 458 | C4F4EAD21C88335400494A7E /* Release */ = { 459 | isa = XCBuildConfiguration; 460 | buildSettings = { 461 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 462 | INFOPLIST_FILE = TagGroupDemo/Info.plist; 463 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 464 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 465 | PRODUCT_BUNDLE_IDENTIFIER = com.aotumanlady..TagGroupDemo; 466 | PRODUCT_NAME = "$(TARGET_NAME)"; 467 | }; 468 | name = Release; 469 | }; 470 | C4F4EAD41C88335400494A7E /* Debug */ = { 471 | isa = XCBuildConfiguration; 472 | buildSettings = { 473 | BUNDLE_LOADER = "$(TEST_HOST)"; 474 | INFOPLIST_FILE = TagGroupDemoTests/Info.plist; 475 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 476 | PRODUCT_BUNDLE_IDENTIFIER = com.aotumanlady..TagGroupDemoTests; 477 | PRODUCT_NAME = "$(TARGET_NAME)"; 478 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TagGroupDemo.app/TagGroupDemo"; 479 | }; 480 | name = Debug; 481 | }; 482 | C4F4EAD51C88335400494A7E /* Release */ = { 483 | isa = XCBuildConfiguration; 484 | buildSettings = { 485 | BUNDLE_LOADER = "$(TEST_HOST)"; 486 | INFOPLIST_FILE = TagGroupDemoTests/Info.plist; 487 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 488 | PRODUCT_BUNDLE_IDENTIFIER = com.aotumanlady..TagGroupDemoTests; 489 | PRODUCT_NAME = "$(TARGET_NAME)"; 490 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TagGroupDemo.app/TagGroupDemo"; 491 | }; 492 | name = Release; 493 | }; 494 | C4F4EAD71C88335400494A7E /* Debug */ = { 495 | isa = XCBuildConfiguration; 496 | buildSettings = { 497 | INFOPLIST_FILE = TagGroupDemoUITests/Info.plist; 498 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 499 | PRODUCT_BUNDLE_IDENTIFIER = com.aotumanlady..TagGroupDemoUITests; 500 | PRODUCT_NAME = "$(TARGET_NAME)"; 501 | TEST_TARGET_NAME = TagGroupDemo; 502 | USES_XCTRUNNER = YES; 503 | }; 504 | name = Debug; 505 | }; 506 | C4F4EAD81C88335400494A7E /* Release */ = { 507 | isa = XCBuildConfiguration; 508 | buildSettings = { 509 | INFOPLIST_FILE = TagGroupDemoUITests/Info.plist; 510 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 511 | PRODUCT_BUNDLE_IDENTIFIER = com.aotumanlady..TagGroupDemoUITests; 512 | PRODUCT_NAME = "$(TARGET_NAME)"; 513 | TEST_TARGET_NAME = TagGroupDemo; 514 | USES_XCTRUNNER = YES; 515 | }; 516 | name = Release; 517 | }; 518 | /* End XCBuildConfiguration section */ 519 | 520 | /* Begin XCConfigurationList section */ 521 | C4F4EA9E1C88335400494A7E /* Build configuration list for PBXProject "TagGroupDemo" */ = { 522 | isa = XCConfigurationList; 523 | buildConfigurations = ( 524 | C4F4EACE1C88335400494A7E /* Debug */, 525 | C4F4EACF1C88335400494A7E /* Release */, 526 | ); 527 | defaultConfigurationIsVisible = 0; 528 | defaultConfigurationName = Release; 529 | }; 530 | C4F4EAD01C88335400494A7E /* Build configuration list for PBXNativeTarget "TagGroupDemo" */ = { 531 | isa = XCConfigurationList; 532 | buildConfigurations = ( 533 | C4F4EAD11C88335400494A7E /* Debug */, 534 | C4F4EAD21C88335400494A7E /* Release */, 535 | ); 536 | defaultConfigurationIsVisible = 0; 537 | defaultConfigurationName = Release; 538 | }; 539 | C4F4EAD31C88335400494A7E /* Build configuration list for PBXNativeTarget "TagGroupDemoTests" */ = { 540 | isa = XCConfigurationList; 541 | buildConfigurations = ( 542 | C4F4EAD41C88335400494A7E /* Debug */, 543 | C4F4EAD51C88335400494A7E /* Release */, 544 | ); 545 | defaultConfigurationIsVisible = 0; 546 | defaultConfigurationName = Release; 547 | }; 548 | C4F4EAD61C88335400494A7E /* Build configuration list for PBXNativeTarget "TagGroupDemoUITests" */ = { 549 | isa = XCConfigurationList; 550 | buildConfigurations = ( 551 | C4F4EAD71C88335400494A7E /* Debug */, 552 | C4F4EAD81C88335400494A7E /* Release */, 553 | ); 554 | defaultConfigurationIsVisible = 0; 555 | defaultConfigurationName = Release; 556 | }; 557 | /* End XCConfigurationList section */ 558 | }; 559 | rootObject = C4F4EA9B1C88335400494A7E /* Project object */; 560 | } 561 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/project.xcworkspace/xcuserdata/chanli.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmw123/ShapeView/b9128210270bba5d50aece18a8efe6014cfa0861/TagGroupDemo/TagGroupDemo.xcodeproj/project.xcworkspace/xcuserdata/chanli.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/project.xcworkspace/xcuserdata/zmw.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmw123/ShapeView/b9128210270bba5d50aece18a8efe6014cfa0861/TagGroupDemo/TagGroupDemo.xcodeproj/project.xcworkspace/xcuserdata/zmw.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/xcuserdata/chanli.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 18 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/xcuserdata/chanli.xcuserdatad/xcschemes/TagGroupDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/xcuserdata/chanli.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TagGroupDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C4F4EAA21C88335400494A7E 16 | 17 | primary 18 | 19 | 20 | C4F4EABB1C88335400494A7E 21 | 22 | primary 23 | 24 | 25 | C4F4EAC61C88335400494A7E 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/xcuserdata/zmw.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/xcuserdata/zmw.xcuserdatad/xcschemes/TagGroupDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo.xcodeproj/xcuserdata/zmw.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TagGroupDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C4F4EAA21C88335400494A7E 16 | 17 | primary 18 | 19 | 20 | C4F4EABB1C88335400494A7E 21 | 22 | primary 23 | 24 | 25 | C4F4EAC61C88335400494A7E 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TagGroupDemo 4 | // 5 | // Created by chanli on 16/3/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. 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 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TagGroupDemo 4 | // 5 | // Created by chanli on 16/3/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. 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 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/Assets.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 | } -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/Assets.xcassets/camera_color_other.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "camera_color_other.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "camera_color_other@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "camera_color_other@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/Assets.xcassets/camera_color_other.imageset/camera_color_other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmw123/ShapeView/b9128210270bba5d50aece18a8efe6014cfa0861/TagGroupDemo/TagGroupDemo/Assets.xcassets/camera_color_other.imageset/camera_color_other.png -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/Assets.xcassets/camera_color_other.imageset/camera_color_other@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmw123/ShapeView/b9128210270bba5d50aece18a8efe6014cfa0861/TagGroupDemo/TagGroupDemo/Assets.xcassets/camera_color_other.imageset/camera_color_other@2x.png -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/Assets.xcassets/camera_color_other.imageset/camera_color_other@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmw123/ShapeView/b9128210270bba5d50aece18a8efe6014cfa0861/TagGroupDemo/TagGroupDemo/Assets.xcassets/camera_color_other.imageset/camera_color_other@3x.png -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/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 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/MaxLightingView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MaxLightingView.h 3 | // TagGroupDemo 4 | // 5 | // Created by chanli on 16/5/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights 7 | // reserved. 8 | // 9 | 10 | #import 11 | 12 | @interface MaxLightingView : UIView 13 | 14 | /** 15 | * 初始化 闪烁 16 | * 17 | * @param frame frame 18 | * @param times 闪烁次数 1 一直闪烁,0,闪烁一次 19 | * 20 | * @return MaxLightingView 21 | */ 22 | - (id)initWithFrame:(CGRect)frame animationRepeats:(BOOL)repeats; 23 | 24 | @property(assign, nonatomic) CGPoint centerPoint; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/MaxLightingView.m: -------------------------------------------------------------------------------- 1 | // 2 | // MaxLightingView.m 3 | // TagGroupDemo 4 | // 5 | // Created by chanli on 16/5/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights 7 | // reserved. 8 | // 9 | 10 | #import "MaxLightingView.h" 11 | #import "NSTimer+Addition.h" 12 | 13 | #define kWidthCircle 8 14 | 15 | #define kTransformScle 2 16 | 17 | #define UIColorRGBA(r, g, b, a) \ 18 | [UIColor colorWithRed:(r) / 255.0 \ 19 | green:(g) / 255.0 \ 20 | blue:(b) / 255.0 \ 21 | alpha:(a)] 22 | 23 | @interface MaxLightingView () { 24 | NSTimer *timerAnimation; 25 | UIView *viewSpread; 26 | UIView *viewTapDot; 27 | UIImageView *viewTapDotImageView; 28 | } 29 | 30 | @end 31 | 32 | @implementation MaxLightingView 33 | 34 | - (id)initWithFrame:(CGRect)frame animationRepeats:(BOOL)repeats { 35 | 36 | if (self = [super initWithFrame:frame]) { 37 | 38 | timerAnimation = [NSTimer 39 | scheduledTimerWithTimeInterval:3 40 | target:self 41 | selector:@selector(animationTimerDidFired) 42 | userInfo:nil 43 | repeats:repeats]; 44 | 45 | [self setup]; 46 | } 47 | 48 | return self; 49 | } 50 | 51 | 52 | - (void)setCenterPoint:(CGPoint)centerPoint { 53 | 54 | _centerPoint = centerPoint; 55 | [self setFrame:CGRectMake(centerPoint.x - kWidthCircle / 2, 56 | centerPoint.y - kWidthCircle / 2, kWidthCircle, 57 | kWidthCircle)]; 58 | 59 | [self setup]; 60 | 61 | } 62 | 63 | - (void)setup { 64 | 65 | viewSpread = [self getViewSpread]; 66 | viewSpread.layer.cornerRadius = viewSpread.frame.size.width / 2; 67 | viewSpread.layer.masksToBounds = YES; 68 | [self addSubview:viewSpread]; 69 | viewTapDotImageView = [self getViewTapDotImageView]; 70 | [self addSubview:viewTapDotImageView]; 71 | viewSpread.center = viewTapDotImageView.center; 72 | [timerAnimation resumeTimer]; 73 | } 74 | 75 | #pragma - mark init 76 | 77 | - (UIView *)getViewSpread { 78 | UIView *view = [[UIView alloc] 79 | initWithFrame:CGRectMake(0, 0, kWidthCircle / 3, kWidthCircle / 3)]; 80 | view.backgroundColor = UIColorRGBA(255, 255, 255, 1); 81 | view.userInteractionEnabled = NO; 82 | view.center = self.center; 83 | return view; 84 | } 85 | 86 | - (UIView *)getViewTapDot { 87 | UIView *view = [UIView new]; 88 | view.backgroundColor = UIColorRGBA(255, 255, 255, 1); //主题颜色; 89 | view.userInteractionEnabled = NO; 90 | view.center = self.center; 91 | return view; 92 | } 93 | 94 | - (UIImageView *)getViewTapDotImageView { 95 | UIImageView *getViewTapDotImageView = [[UIImageView alloc] 96 | initWithFrame:CGRectMake(0, 0, kWidthCircle, kWidthCircle)]; 97 | // getViewTapDotImageView.center = self.center; 98 | 99 | getViewTapDotImageView.contentMode = UIViewContentModeScaleAspectFit; 100 | getViewTapDotImageView.image = [UIImage imageNamed:@"camera_color_other"]; 101 | getViewTapDotImageView.userInteractionEnabled = NO; 102 | return getViewTapDotImageView; 103 | } 104 | #pragma - mark 监听 105 | /** 106 | * 播放动画 107 | */ 108 | - (void)animationTimerDidFired { 109 | [UIView animateWithDuration:1 110 | animations:^{ 111 | viewTapDot.transform = CGAffineTransformMakeScale(1.3 * kTransformScle, 112 | 1.3 * kTransformScle); 113 | } 114 | completion:^(BOOL finished) { 115 | [UIView animateWithDuration:1 116 | animations:^{ 117 | viewTapDot.transform = CGAffineTransformIdentity; 118 | } 119 | completion:^(BOOL finished) { 120 | viewSpread.alpha = 1; 121 | [UIView animateWithDuration:1 122 | animations:^{ 123 | viewSpread.alpha = 0; 124 | viewSpread.transform = CGAffineTransformMakeScale( 125 | kWidthCircle / 2 * kTransformScle, 126 | kWidthCircle / 2 * kTransformScle); 127 | } 128 | completion:^(BOOL finished) { 129 | viewSpread.transform = CGAffineTransformIdentity; 130 | }]; 131 | }]; 132 | 133 | }]; 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/MaxShapeView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ShapeView.h 3 | // TagGroupDemo 4 | // 5 | // Created by zmw on 16/5/4. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | /** 11 | 12 | * * * * * 13 | --------------- width 50 14 | 15 | 16 | * * * * Hello 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * * * * string 25 | --------------- height 100 width 40 26 | 27 | * * * * Hello 28 | * 29 | * 30 | * 31 | * * * Hello 32 | * 33 | * 34 | * 35 | * * * * Hello 36 | --------------- height 120 width 40 midWidth 30 37 | kMaxTagGroupTypeRight 38 | 39 | 40 | 41 | * 42 | * 43 | * 44 | * 45 | * * * Hello 46 | --------------- brokenLine 50 width 30 47 | 48 | * * * Hello 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * * * Hello 57 | --------------- brokenLine 50 width 30 58 | 59 | * * * Hello 60 | * 61 | * 62 | * 63 | * * * * * * * Hello 64 | * 65 | * 66 | * 67 | * * * Hello 68 | --------------- brokenLine 50 width 30 midWidth 70 69 | kMaxTagGroupTypeBrokenRight 70 | 71 | 72 | 73 | Hello * * * * * 74 | --------------- width 50 75 | 76 | Hello * * * * 77 | * 78 | * 79 | * 80 | * 81 | * 82 | * 83 | * 84 | Hello * * * * 85 | --------------- height 120 width 40 86 | 87 | Hello * * * * 88 | * 89 | * 90 | * 91 | Hello * * * 92 | * 93 | * 94 | * 95 | Hello * * * * 96 | --------------- height 120 width 40 midWidth 30 97 | kMaxTagGroupTypeLeft 98 | 99 | 100 | 101 | 102 | * 103 | * 104 | * 105 | * 106 | Hello * * * 107 | --------------- brokenLine 50 width 30 108 | 109 | * * * Hello 110 | * 111 | * 112 | * 113 | * 114 | * 115 | * 116 | * 117 | * * * Hello 118 | --------------- brokenLine 50 width 30 119 | 120 | * * * Hello 121 | * 122 | * 123 | * 124 | * * * * * * * Hello 125 | * 126 | * 127 | * 128 | * * * Hello 129 | --------------- brokenLine 50 width 30 midWidth 70 130 | 131 | kMaxTagGroupTypeBrokenLeft 132 | 133 | ************ 134 | * 135 | * 136 | * 137 | * * 138 | * * 139 | **** *********** 140 | kMaxTagGroupTypeLeftBottom 141 | 142 | 143 | ********* 144 | * 145 | * 146 | * 147 | * * 148 | * * 149 | ********** ********* 150 | kMaxTagGroupTypeRightBottom, 151 | */ 152 | 153 | typedef enum : NSUInteger { 154 | kMaxTagGroupTypeDefault = 0, 155 | 156 | kMaxTagGroupOneTagTypeRight = 10, 157 | kMaxTagGroupOneTagTypeLeft, 158 | kMaxTagGroupOneTagTypeRightBottom, 159 | kMaxTagGroupOneTagTypeLeftBottom, 160 | 161 | kMaxTagGroupTwoTagTypeBrokenRight = 20, 162 | kMaxTagGroupTypeBrokenBrokenLeft, 163 | kMaxTagGroupTwoTagTypeRight, 164 | kMaxTagGroupTwoTagTypeLeft, 165 | 166 | kMaxTagGroupThreeTagTypeLeftBottom = 30, 167 | kMaxTagGroupThreeTagTypeLeftTop, 168 | kMaxTagGroupThreeTagTypeRightTop, 169 | kMaxTagGroupThreeTagTypeRightBottom, 170 | kMaxTagGroupThreeTagTypeBrokenRight, 171 | kMaxTagGroupThreeTagTypeBrokenLeft, 172 | kMaxTagGroupThreeTagTypeRight, 173 | kMaxTagGroupThreeTagTypeLeft, 174 | } kMaxTagGroupType; 175 | 176 | @interface MaxShapeView : UIView 177 | 178 | @property(nonatomic, readonly) CAShapeLayer *shapeLayer; 179 | 180 | @property(nonatomic, assign) BOOL reverse; 181 | @property(nonatomic, assign) kMaxTagGroupType type; 182 | @property(assign, nonatomic) CGPoint point; //中心点 183 | @property(strong, nonatomic) NSArray *tagGroup; //标签数组 184 | @property(strong, nonatomic) NSArray *oneTagGroup; //多的一侧的标签 185 | @property(strong, nonatomic) NSArray *twoTagGroup; //少的一侧的标签 186 | 187 | @property(strong, nonatomic) NSMutableArray *tagPointsArry; //点数组 188 | 189 | @property(strong, nonatomic) NSMutableArray *animationGroup; //动画数组 190 | 191 | @property(nonatomic, copy) void (^longPressBlock)(MaxShapeView *tagView); 192 | @property(nonatomic, copy) void (^tapBlock)(MaxShapeView *tagView, UILabel *tapLabel); 193 | @property(nonatomic, copy) void (^doubleTapBlock)(MaxShapeView *tagView); 194 | @property(nonatomic, copy) void (^dragDoneBlock)(MaxShapeView *tagView); 195 | @property(nonatomic, copy) void (^dragCancelBlock)(MaxShapeView *tagView); 196 | 197 | - (id)initWithFrame:(CGRect)frame 198 | point:(CGPoint)point 199 | tagGroup:(NSArray *)tagGroup 200 | tagType:(kMaxTagGroupType)type 201 | superFrame:(CGRect)superFrame; 202 | 203 | - (void)drawLine; 204 | 205 | @end 206 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/MaxShapeView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ShapeView.m 3 | // TagGroupDemo 4 | // 5 | // Created by zmw on 16/5/4. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights reserved. 7 | // 8 | 9 | #import "MaxLightingView.h" 10 | #import "MaxShapeView.h" 11 | #import "NSString+SizeWithFont.h" 12 | // 13 | #define kHeight50DPDistance 25 14 | #define kHegiht60DPDistance 30 15 | 16 | #define kSlash30DPLineWidth 15 17 | #define kSlash40DPLineWidth 20 18 | #define kSlash50DPLineWidth 25 19 | #define kSlash70DPLineWidth 35 20 | 21 | #define kLabelHeight 25 22 | #define kTheLeftIndex 1 23 | #define kLineValue 1 24 | 25 | #define kWithePointWidth 6 26 | 27 | #define kBaseTag 2000 28 | 29 | #define ktagColor [UIColor whiteColor] 30 | 31 | @interface MaxShapeView () { 32 | UILongPressGestureRecognizer *_longPressGestureRecognizer; 33 | UITapGestureRecognizer *_tapGestureRecognizer; 34 | UITapGestureRecognizer *_label0TapGestureRecognizer; 35 | UITapGestureRecognizer *_label1TapGestureRecognizer; 36 | UITapGestureRecognizer *_label2TapGestureRecognizer; 37 | BOOL _isDragging; 38 | 39 | CAShapeLayer *_lineLayer0; 40 | CAShapeLayer *_linePoint0; 41 | CAShapeLayer *_lineLayer1; 42 | CAShapeLayer *_linePoint1; 43 | CAShapeLayer *_lineLayer2; 44 | CAShapeLayer *_linePoint2; 45 | 46 | UILabel *_lineLabel0; 47 | UILabel *_lineLabel1; 48 | UILabel *_lineLabel2; 49 | 50 | CGRect _superFrame; 51 | } 52 | 53 | @property(strong, nonatomic) MaxLightingView *lightingView; 54 | @property(assign, nonatomic) CGPoint beginpoint; 55 | 56 | @end 57 | 58 | @implementation MaxShapeView 59 | 60 | + (Class)layerClass { 61 | return [CAShapeLayer class]; 62 | } 63 | 64 | - (CAShapeLayer *)shapeLayer { 65 | return (CAShapeLayer *)self.layer; 66 | } 67 | 68 | - (MaxLightingView *)lightingView { 69 | 70 | if (!_lightingView) 71 | { 72 | _lightingView = 73 | [[MaxLightingView alloc] initWithFrame:CGRectZero animationRepeats:YES]; 74 | 75 | [self addSubview:_lightingView]; 76 | } 77 | return _lightingView; 78 | } 79 | 80 | - (id)initWithFrame:(CGRect)frame 81 | point:(CGPoint)point 82 | tagGroup:(NSArray *)tagGroup 83 | tagType:(kMaxTagGroupType)type 84 | superFrame:(CGRect)superFrame { 85 | if (self = [super initWithFrame:frame]) { 86 | _superFrame = superFrame; 87 | self.type = type; 88 | 89 | if (type == kMaxTagGroupTypeDefault) { 90 | 91 | if (tagGroup.count == 1) { 92 | self.type = kMaxTagGroupOneTagTypeRight; 93 | } else if (tagGroup.count == 2) { 94 | self.type = kMaxTagGroupTwoTagTypeBrokenRight; 95 | } else if (tagGroup.count == 3) { 96 | self.type = kMaxTagGroupThreeTagTypeLeftBottom; 97 | } 98 | } 99 | 100 | self.opaque = NO; 101 | self.translatesAutoresizingMaskIntoConstraints = NO; 102 | self.reverse = NO; 103 | self.point = point; 104 | self.tagGroup = tagGroup; 105 | self.tagPointsArry = [NSMutableArray arrayWithCapacity:self.tagGroup.count]; 106 | self.animationGroup = 107 | [NSMutableArray arrayWithCapacity:self.tagGroup.count]; 108 | 109 | _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] init]; 110 | [_longPressGestureRecognizer addTarget:self 111 | action:@selector(gestureRecognizerHandle:)]; 112 | [_longPressGestureRecognizer setAllowableMovement:0]; 113 | [self addGestureRecognizer:_longPressGestureRecognizer]; 114 | 115 | _tapGestureRecognizer = [[UITapGestureRecognizer alloc] init]; 116 | [_tapGestureRecognizer addTarget:self 117 | action:@selector(gestureRecognizerHandle:)]; 118 | [self addGestureRecognizer:_tapGestureRecognizer]; 119 | 120 | [self drawLine]; 121 | } 122 | 123 | return self; 124 | } 125 | 126 | - (void)drawLine { 127 | if (self.tagGroup.count == 1) { 128 | [self drawLineOne]; 129 | } else if (self.tagGroup.count == 2) { 130 | [self drawLineTwo]; 131 | } else { 132 | [self drawLineThree]; 133 | } 134 | } 135 | 136 | - (void)drawLineOne { 137 | 138 | CGPoint point = CGPointMake(0, kLabelHeight / 2); 139 | //添加 文字显示 140 | CGFloat lineWidth = [NSString widthWithAttributes:nil text:self.tagGroup[0]]; 141 | NSMutableDictionary *tagPointsArry = 142 | [NSMutableDictionary dictionaryWithCapacity:self.tagGroup.count]; 143 | 144 | if (self.type == kMaxTagGroupOneTagTypeRight) { 145 | 146 | point = CGPointMake(0, kLabelHeight / 2); 147 | 148 | self.frame = CGRectMake(self.point.x, self.point.y, 149 | lineWidth + kSlash50DPLineWidth, kLabelHeight); 150 | 151 | NSMutableArray *lineBranch = [NSMutableArray 152 | arrayWithObjects:[NSValue valueWithCGPoint:point], 153 | [NSValue 154 | valueWithCGPoint:CGPointMake( 155 | point.x + kSlash50DPLineWidth, 156 | point.y)], 157 | nil]; 158 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 159 | } else if (self.type == kMaxTagGroupOneTagTypeLeft) { 160 | 161 | point = CGPointMake(lineWidth + kSlash50DPLineWidth, kLabelHeight / 2); 162 | 163 | self.frame = CGRectMake(self.point.x - lineWidth, self.point.y, 164 | lineWidth + kSlash50DPLineWidth, kLabelHeight); 165 | NSMutableArray *lineBranch = [NSMutableArray 166 | arrayWithObjects:[NSValue valueWithCGPoint:point], 167 | [NSValue 168 | valueWithCGPoint:CGPointMake( 169 | point.x - kSlash50DPLineWidth, 170 | point.y)], 171 | nil]; 172 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 173 | } else if (self.type == kMaxTagGroupOneTagTypeLeftBottom) { 174 | self.frame = CGRectMake( 175 | self.point.x - (kSlash50DPLineWidth + lineWidth + kSlash30DPLineWidth), 176 | self.point.y, lineWidth + kSlash50DPLineWidth + kSlash30DPLineWidth, 177 | kHeight50DPDistance + kLabelHeight / 2); 178 | 179 | point = CGPointMake(CGRectGetWidth(self.frame), 0); 180 | 181 | NSMutableArray *lineBranch = [NSMutableArray 182 | arrayWithObjects:[NSValue valueWithCGPoint:point], 183 | [NSValue 184 | valueWithCGPoint:CGPointMake( 185 | point.x - kSlash50DPLineWidth, 186 | point.y + 187 | kHeight50DPDistance)], 188 | [NSValue 189 | valueWithCGPoint:CGPointMake( 190 | point.x - 191 | kSlash50DPLineWidth - 192 | kSlash30DPLineWidth, 193 | point.y + 194 | kHeight50DPDistance)], 195 | nil]; 196 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 197 | } else if (self.type == kMaxTagGroupOneTagTypeRightBottom) { 198 | self.frame = 199 | CGRectMake(self.point.x, self.point.y, 200 | lineWidth + kSlash50DPLineWidth + kSlash30DPLineWidth, 201 | kHeight50DPDistance + kLabelHeight / 2); 202 | point = CGPointMake(0, 0); 203 | NSMutableArray *lineBranch = [NSMutableArray 204 | arrayWithObjects:[NSValue valueWithCGPoint:point], 205 | [NSValue 206 | valueWithCGPoint:CGPointMake( 207 | point.x + kSlash50DPLineWidth, 208 | point.y + 209 | kHeight50DPDistance)], 210 | [NSValue 211 | valueWithCGPoint:CGPointMake( 212 | point.x + 213 | kSlash50DPLineWidth + 214 | kSlash30DPLineWidth, 215 | point.y + 216 | kHeight50DPDistance)], 217 | nil]; 218 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 219 | } 220 | 221 | self.lightingView.frame = CGRectMake(0, 0, 30.f, 30.f); 222 | self.lightingView.centerPoint = point; 223 | 224 | if (self.frame.origin.x < 0) { 225 | self.frame = CGRectMake(0, self.frame.origin.y, self.frame.size.width, 226 | self.frame.size.height); 227 | } 228 | 229 | if (self.frame.origin.y < 0) { 230 | self.frame = CGRectMake(self.frame.origin.x, 0, self.frame.size.width, 231 | self.frame.size.height); 232 | } 233 | if (CGRectGetMaxX(self.frame) > _superFrame.size.width) { 234 | self.frame = CGRectMake(_superFrame.size.width - self.frame.size.width, 235 | self.frame.origin.y, self.frame.size.width, 236 | self.frame.size.height); 237 | } 238 | 239 | if (CGRectGetMaxY(self.frame) > _superFrame.size.height) { 240 | self.frame = CGRectMake(self.frame.origin.x, 241 | _superFrame.size.height - self.frame.size.height, 242 | self.frame.size.width, self.frame.size.height); 243 | } 244 | 245 | [tagPointsArry enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, 246 | NSArray *_Nonnull points, 247 | BOOL *_Nonnull stop) { 248 | 249 | NSInteger idx = [key integerValue]; 250 | CGPoint lastPoint = [[points lastObject] CGPointValue]; 251 | 252 | CAShapeLayer *lineLayer = nil; 253 | CAShapeLayer *linePoint = nil; 254 | UILabel *textlabel = nil; 255 | 256 | if (!_lineLayer0) { 257 | _lineLabel0 = [[UILabel alloc] init]; 258 | _lineLayer0 = [CAShapeLayer layer]; 259 | [self.layer addSublayer:_lineLayer0]; 260 | [self addSubview:_lineLabel0]; 261 | 262 | _label0TapGestureRecognizer = [[UITapGestureRecognizer alloc] init]; 263 | [_label0TapGestureRecognizer addTarget:self 264 | action:@selector(gestureRecognizerHandle:)]; 265 | _lineLabel0.userInteractionEnabled = YES; 266 | [_lineLabel0 addGestureRecognizer:_label0TapGestureRecognizer]; 267 | _linePoint0 = [self whiteLayer]; 268 | [_lineLayer0 addSublayer:_linePoint0]; 269 | } 270 | lineLayer = _lineLayer0; 271 | textlabel = _lineLabel0; 272 | linePoint = _linePoint0; 273 | { 274 | if (_lineLayer1) { 275 | [_lineLayer1 removeFromSuperlayer]; 276 | _lineLayer1 = nil; 277 | [_linePoint1 removeFromSuperlayer]; 278 | _linePoint1 = nil; 279 | [_lineLabel1 removeFromSuperview]; 280 | _lineLabel1 = nil; 281 | } 282 | if (_lineLayer2) { 283 | [_lineLayer2 removeFromSuperlayer]; 284 | _lineLayer2 = nil; 285 | [_linePoint2 removeFromSuperlayer]; 286 | _linePoint2 = nil; 287 | [_lineLabel2 removeFromSuperview]; 288 | _lineLabel2 = nil; 289 | } 290 | } 291 | 292 | //清空面板 293 | lineLayer.path = nil; 294 | textlabel.frame = CGRectZero; 295 | lineLayer.strokeColor = ktagColor.CGColor; 296 | textlabel.text = nil; 297 | textlabel.textColor = ktagColor; 298 | textlabel.textAlignment = NSTextAlignmentCenter; 299 | // 指定frame,只是为了设置宽度和高度 300 | // 设置居中显示 301 | // 设置填充颜色 302 | lineLayer.fillColor = [UIColor clearColor].CGColor; 303 | // 设置线宽 304 | lineLayer.lineWidth = kLineValue; 305 | 306 | // 使用UIBezierPath创建路径 307 | UIBezierPath *linePath = [UIBezierPath bezierPath]; 308 | 309 | [points enumerateObjectsUsingBlock:^(NSValue *_Nonnull pointNumber, 310 | NSUInteger idx, BOOL *_Nonnull stop) { 311 | 312 | CGPoint point = pointNumber.CGPointValue; 313 | if (idx == 0) { 314 | [linePath moveToPoint:point]; 315 | } else { 316 | [linePath addLineToPoint:point]; 317 | } 318 | 319 | }]; 320 | 321 | // 设置CAShapeLayer与UIBezierPath关联 322 | lineLayer.path = linePath.CGPath; 323 | 324 | //创建动画 325 | CABasicAnimation *animation = [CABasicAnimation 326 | animationWithKeyPath:NSStringFromSelector(@selector(strokeEnd))]; 327 | animation.fromValue = @0.0; 328 | animation.toValue = @1.0; 329 | animation.delegate = self; 330 | animation.duration = 0.8; 331 | 332 | [lineLayer addAnimation:animation forKey:nil]; 333 | 334 | linePoint.hidden = YES; 335 | linePoint.frame = CGRectMake(0, 0, 6.f, 6.f); 336 | NSValue *point = [points lastObject]; 337 | linePoint.position = point.CGPointValue; 338 | 339 | //添加 文字显示 340 | switch (self.type) { 341 | case kMaxTagGroupOneTagTypeRight: 342 | case kMaxTagGroupOneTagTypeRightBottom: { 343 | [textlabel 344 | setFrame:CGRectMake(lastPoint.x + kWithePointWidth, lastPoint.y - kLabelHeight / 2, 345 | lineWidth - kWithePointWidth, kLabelHeight)]; 346 | } break; 347 | case kMaxTagGroupOneTagTypeLeft: 348 | case kMaxTagGroupOneTagTypeLeftBottom: { 349 | [textlabel setFrame:CGRectMake(lastPoint.x - lineWidth, 350 | lastPoint.y - kLabelHeight / 2, lineWidth - kWithePointWidth, 351 | kLabelHeight)]; 352 | } break; 353 | default: 354 | break; 355 | } 356 | 357 | textlabel.text = self.tagGroup[idx]; 358 | textlabel.font = [UIFont systemFontOfSize:13]; 359 | textlabel.hidden = YES; 360 | }]; 361 | } 362 | 363 | - (void)drawLineTwo { 364 | 365 | CGPoint point = CGPointMake(0, 0); 366 | //添加 文字显示 367 | CGFloat maxLength = [NSString maxestWidthWithStringArray:self.tagGroup]; 368 | NSMutableDictionary *tagPointsArry = 369 | [NSMutableDictionary dictionaryWithCapacity:self.tagGroup.count]; 370 | 371 | if (self.type == kMaxTagGroupTwoTagTypeBrokenRight) { 372 | //这里需要考虑右侧是不是在父视图外侧,这个时候要整体往左侧移动,但是可能存在左侧移除父视图的外部(要定义规则) 373 | 374 | self.frame = CGRectMake( 375 | self.point.x, self.point.y - kHeight50DPDistance + kLabelHeight / 2, 376 | kSlash50DPLineWidth + kSlash30DPLineWidth + maxLength, 377 | 2 * kHeight50DPDistance + kLabelHeight); 378 | 379 | point = CGPointMake(0, CGRectGetHeight(self.frame) / 2); 380 | for (int idx = 0; idx < self.tagGroup.count; idx++) { 381 | // CGFloat lineWidth = 382 | // [NSString widthWithAttributes:nil text:self.tagGroup[idx]]; 383 | NSMutableArray *lineBranch; 384 | switch (idx) { 385 | case 0: { 386 | lineBranch = [NSMutableArray 387 | arrayWithObjects: 388 | [NSValue valueWithCGPoint:point], 389 | [NSValue valueWithCGPoint:CGPointMake( 390 | point.x + kSlash50DPLineWidth, 391 | point.y - kHeight50DPDistance)], 392 | [NSValue valueWithCGPoint:CGPointMake( 393 | point.x + kSlash50DPLineWidth + 394 | kSlash30DPLineWidth, 395 | point.y - kHeight50DPDistance)], 396 | nil]; 397 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 398 | } break; 399 | case 1: { 400 | lineBranch = [NSMutableArray 401 | arrayWithObjects: 402 | [NSValue valueWithCGPoint:point], 403 | [NSValue valueWithCGPoint:CGPointMake( 404 | point.x + kSlash50DPLineWidth, 405 | point.y + kHeight50DPDistance)], 406 | [NSValue valueWithCGPoint:CGPointMake( 407 | point.x + kSlash50DPLineWidth + 408 | kSlash30DPLineWidth, 409 | point.y + kHeight50DPDistance)], 410 | nil]; 411 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 412 | } break; 413 | } 414 | } 415 | } else if (self.type == kMaxTagGroupTypeBrokenBrokenLeft) { 416 | 417 | //这里要考虑左侧是不是在父视图的外侧,这个时候要整体往右侧移动,但是这个时候可能存在右侧在父视图的外部 418 | self.frame = CGRectMake( 419 | self.point.x - maxLength - kSlash50DPLineWidth - kSlash30DPLineWidth, 420 | self.point.y - kHeight50DPDistance - kLabelHeight / 2, 421 | kSlash50DPLineWidth + kSlash30DPLineWidth + maxLength, 422 | 2 * kHeight50DPDistance + kLabelHeight); 423 | 424 | point = CGPointMake(CGRectGetWidth(self.frame), 425 | CGRectGetHeight(self.frame) / 2); 426 | 427 | for (int idx = 0; idx < self.tagGroup.count; idx++) { 428 | NSMutableArray *lineBranch; 429 | switch (idx) { 430 | case 0: { 431 | lineBranch = [NSMutableArray 432 | arrayWithObjects: 433 | [NSValue valueWithCGPoint:point], 434 | [NSValue valueWithCGPoint:CGPointMake( 435 | point.x - kSlash50DPLineWidth, 436 | point.y - kHeight50DPDistance)], 437 | [NSValue valueWithCGPoint:CGPointMake( 438 | point.x - kSlash50DPLineWidth - 439 | kSlash30DPLineWidth, 440 | point.y - kHeight50DPDistance)], 441 | nil]; 442 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 443 | } break; 444 | case 1: { 445 | lineBranch = [NSMutableArray 446 | arrayWithObjects: 447 | [NSValue valueWithCGPoint:point], 448 | [NSValue valueWithCGPoint:CGPointMake( 449 | point.x - kSlash50DPLineWidth, 450 | point.y + kHeight50DPDistance)], 451 | [NSValue valueWithCGPoint:CGPointMake( 452 | point.x - kSlash50DPLineWidth - 453 | kSlash30DPLineWidth, 454 | point.y + kHeight50DPDistance)], 455 | nil]; 456 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 457 | } break; 458 | } 459 | } 460 | } else if (self.type == kMaxTagGroupTwoTagTypeRight) { 461 | //这里需要考虑右侧是不是在父视图外侧,这个时候要整体往左侧移动,但是可能存在左侧移除父视图的外部(要定义规则) 462 | 463 | self.frame = CGRectMake(self.point.x, self.point.y - kSlash40DPLineWidth + 464 | kLabelHeight / 2, 465 | kSlash40DPLineWidth + maxLength, 466 | 2 * kHeight50DPDistance + kLabelHeight); 467 | 468 | point = CGPointMake(0, CGRectGetHeight(self.frame) / 2); 469 | for (int idx = 0; idx < self.tagGroup.count; idx++) { 470 | // CGFloat lineWidth = 471 | // [NSString widthWithAttributes:nil text:self.tagGroup[idx]]; 472 | NSMutableArray *lineBranch; 473 | switch (idx) { 474 | case 0: { 475 | lineBranch = [NSMutableArray 476 | arrayWithObjects:[NSValue valueWithCGPoint:point], 477 | [NSValue 478 | valueWithCGPoint:CGPointMake( 479 | point.x, 480 | point.y - 481 | kHeight50DPDistance)], 482 | [NSValue 483 | valueWithCGPoint:CGPointMake( 484 | point.x + 485 | kSlash40DPLineWidth, 486 | point.y - 487 | kHeight50DPDistance)], 488 | nil]; 489 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 490 | } break; 491 | case 1: { 492 | lineBranch = [NSMutableArray 493 | arrayWithObjects:[NSValue valueWithCGPoint:point], 494 | [NSValue 495 | valueWithCGPoint:CGPointMake( 496 | point.x, 497 | point.y + 498 | kHeight50DPDistance)], 499 | [NSValue 500 | valueWithCGPoint:CGPointMake( 501 | point.x + 502 | kSlash40DPLineWidth, 503 | point.y + 504 | kHeight50DPDistance)], 505 | nil]; 506 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 507 | } break; 508 | } 509 | } 510 | } else if (self.type == kMaxTagGroupTwoTagTypeLeft) { 511 | //这里需要考虑右侧是不是在父视图外侧,这个时候要整体往左侧移动,但是可能存在左侧移除父视图的外部(要定义规则) 512 | 513 | self.frame = 514 | CGRectMake(self.point.x - (kSlash40DPLineWidth + maxLength), 515 | self.point.y - kHeight50DPDistance + kLabelHeight / 2, 516 | kSlash40DPLineWidth + maxLength, 517 | 2 * kHeight50DPDistance + kLabelHeight); 518 | 519 | point = CGPointMake(CGRectGetWidth(self.frame), 520 | CGRectGetHeight(self.frame) / 2); 521 | for (int idx = 0; idx < self.tagGroup.count; idx++) { 522 | 523 | NSMutableArray *lineBranch; 524 | switch (idx) { 525 | case 0: { 526 | lineBranch = [NSMutableArray 527 | arrayWithObjects:[NSValue valueWithCGPoint:point], 528 | [NSValue 529 | valueWithCGPoint:CGPointMake( 530 | point.x, 531 | point.y - 532 | kHeight50DPDistance)], 533 | [NSValue 534 | valueWithCGPoint:CGPointMake( 535 | point.x - 536 | kSlash40DPLineWidth, 537 | point.y - 538 | kHeight50DPDistance)], 539 | nil]; 540 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 541 | } break; 542 | case 1: { 543 | lineBranch = [NSMutableArray 544 | arrayWithObjects:[NSValue valueWithCGPoint:point], 545 | [NSValue 546 | valueWithCGPoint:CGPointMake( 547 | point.x, 548 | point.y + 549 | kHeight50DPDistance)], 550 | [NSValue 551 | valueWithCGPoint:CGPointMake( 552 | point.x - 553 | kSlash40DPLineWidth, 554 | point.y + 555 | kHeight50DPDistance)], 556 | nil]; 557 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 558 | } break; 559 | } 560 | } 561 | } 562 | 563 | self.lightingView.centerPoint = point; 564 | 565 | if (self.frame.origin.x < 0) { 566 | self.frame = CGRectMake(0, self.frame.origin.y, self.frame.size.width, 567 | self.frame.size.height); 568 | } 569 | 570 | if (self.frame.origin.y < 0) { 571 | self.frame = CGRectMake(self.frame.origin.x, 0, self.frame.size.width, 572 | self.frame.size.height); 573 | } 574 | if (CGRectGetMaxX(self.frame) > _superFrame.size.width) { 575 | self.frame = CGRectMake(_superFrame.size.width - self.frame.size.width, 576 | self.frame.origin.y, self.frame.size.width, 577 | self.frame.size.height); 578 | } 579 | 580 | if (CGRectGetMaxY(self.frame) > _superFrame.size.height) { 581 | self.frame = CGRectMake(self.frame.origin.x, 582 | _superFrame.size.height - self.frame.size.height, 583 | self.frame.size.width, self.frame.size.height); 584 | } 585 | 586 | [tagPointsArry enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, 587 | NSArray *_Nonnull points, 588 | BOOL *_Nonnull stop) { 589 | 590 | NSInteger idx = [key integerValue]; 591 | NSInteger currentTagIndex = 0; 592 | CGPoint lastPoint = [[points lastObject] CGPointValue]; 593 | 594 | CAShapeLayer *lineLayer = nil; 595 | CAShapeLayer *linePoint = nil; 596 | UILabel *textlabel = nil; 597 | switch (idx) { 598 | case 0: { 599 | if (!_lineLayer0) { 600 | _lineLabel0 = [[UILabel alloc] init]; 601 | _lineLayer0 = [CAShapeLayer layer]; 602 | [self.layer addSublayer:_lineLayer0]; 603 | [self addSubview:_lineLabel0]; 604 | 605 | _label0TapGestureRecognizer = [[UITapGestureRecognizer alloc] init]; 606 | [_label0TapGestureRecognizer addTarget:self 607 | action:@selector(gestureRecognizerHandle:)]; 608 | _lineLabel0.userInteractionEnabled = YES; 609 | [_lineLabel0 addGestureRecognizer:_label0TapGestureRecognizer]; 610 | _linePoint0 = [self whiteLayer]; 611 | [_lineLayer0 addSublayer:_linePoint0]; 612 | } 613 | lineLayer = _lineLayer0; 614 | linePoint = _linePoint0; 615 | textlabel = _lineLabel0; 616 | currentTagIndex = 0; 617 | } break; 618 | case 1: { 619 | if (!_lineLayer1) { 620 | _lineLabel1 = [[UILabel alloc] init]; 621 | _lineLayer1 = [CAShapeLayer layer]; 622 | [self.layer addSublayer:_lineLayer1]; 623 | [self addSubview:_lineLabel1]; 624 | 625 | _label1TapGestureRecognizer = [[UITapGestureRecognizer alloc] init]; 626 | [_label1TapGestureRecognizer addTarget:self 627 | action:@selector(gestureRecognizerHandle:)]; 628 | _lineLabel1.userInteractionEnabled = YES; 629 | [_lineLabel1 addGestureRecognizer:_label1TapGestureRecognizer]; 630 | 631 | _linePoint1 = [self whiteLayer]; 632 | [_lineLayer1 addSublayer:_linePoint1]; 633 | } 634 | lineLayer = _lineLayer1; 635 | linePoint = _linePoint1; 636 | textlabel = _lineLabel1; 637 | currentTagIndex = 1; 638 | } break; 639 | default: 640 | lineLayer = [CAShapeLayer layer]; 641 | break; 642 | } 643 | 644 | //清空面板 645 | lineLayer.path = nil; 646 | textlabel.frame = CGRectZero; 647 | lineLayer.strokeColor = ktagColor.CGColor; 648 | textlabel.text = nil; 649 | textlabel.textColor = ktagColor; 650 | textlabel.textAlignment = NSTextAlignmentCenter; 651 | // 指定frame,只是为了设置宽度和高度 652 | // 设置居中显示 653 | // 设置填充颜色 654 | lineLayer.fillColor = [UIColor clearColor].CGColor; 655 | // 设置线宽 656 | lineLayer.lineWidth = kLineValue; 657 | 658 | // 使用UIBezierPath创建路径 659 | UIBezierPath *linePath = [UIBezierPath bezierPath]; 660 | 661 | [points enumerateObjectsUsingBlock:^(NSValue *_Nonnull pointNumber, 662 | NSUInteger idx, BOOL *_Nonnull stop) { 663 | 664 | CGPoint point = pointNumber.CGPointValue; 665 | if (idx == 0) { 666 | [linePath moveToPoint:point]; 667 | } else { 668 | [linePath addLineToPoint:point]; 669 | } 670 | 671 | }]; 672 | 673 | // 设置CAShapeLayer与UIBezierPath关联 674 | lineLayer.path = linePath.CGPath; 675 | 676 | //创建动画 677 | CABasicAnimation *animation = [CABasicAnimation 678 | animationWithKeyPath:NSStringFromSelector(@selector(strokeEnd))]; 679 | animation.fromValue = @0.0; 680 | animation.toValue = @1.0; 681 | animation.delegate = self; 682 | animation.duration = 0.8; 683 | 684 | [lineLayer addAnimation:animation forKey:nil]; 685 | 686 | linePoint.hidden = YES; 687 | linePoint.frame = CGRectMake(0, 0, 6.f, 6.f); 688 | NSValue *point = [points lastObject]; 689 | linePoint.position = point.CGPointValue; 690 | 691 | CGFloat lineWidth = 692 | [NSString widthWithAttributes:nil text:self.tagGroup[currentTagIndex]]; 693 | //添加 文字显示 694 | //添加 文字显示 695 | switch (self.type) { 696 | case kMaxTagGroupTwoTagTypeBrokenRight: 697 | case kMaxTagGroupTwoTagTypeRight: { 698 | [textlabel 699 | setFrame:CGRectMake(lastPoint.x + kWithePointWidth, lastPoint.y - kLabelHeight / 2, 700 | lineWidth - kWithePointWidth, kLabelHeight)]; 701 | } break; 702 | case kMaxTagGroupTypeBrokenBrokenLeft: 703 | case kMaxTagGroupTwoTagTypeLeft: { 704 | [textlabel setFrame:CGRectMake(lastPoint.x - lineWidth, 705 | lastPoint.y - kLabelHeight / 2, lineWidth - kWithePointWidth, 706 | kLabelHeight)]; 707 | } break; 708 | default: 709 | break; 710 | } 711 | 712 | textlabel.text = self.tagGroup[currentTagIndex]; 713 | textlabel.font = [UIFont systemFontOfSize:12]; 714 | textlabel.hidden = YES; 715 | }]; 716 | } 717 | 718 | - (void)drawLineThree { 719 | CGPoint point; 720 | //添加 文字显示 721 | 722 | CGFloat maxTotleMaxLength = 723 | [NSString maxestWidthWithStringArray:self.tagGroup]; 724 | CGFloat maxSingleSideLength = [NSString 725 | maxestWidthWithStringArray:@[ self.tagGroup[0], self.tagGroup[1] ]]; 726 | 727 | NSString *moneyString = [self.tagGroup lastObject]; 728 | CGFloat moneyLength = [NSString maxestWidthWithStringArray:@[ moneyString ]]; 729 | NSMutableDictionary *tagPointsArry = 730 | [NSMutableDictionary dictionaryWithCapacity:self.tagGroup.count]; 731 | 732 | if (self.type == kMaxTagGroupThreeTagTypeLeftBottom) { 733 | //这里需要考虑右侧是不是在父视图外侧,这个时候要整体往左侧移动,但是可能存在左侧移除父视图的外部(要定义规则) 734 | 735 | self.frame = 736 | CGRectMake(self.point.x - (kSlash50DPLineWidth + kSlash30DPLineWidth + 737 | moneyLength), 738 | self.point.y - kHegiht60DPDistance - kLabelHeight / 2, 739 | 2 * (kSlash50DPLineWidth + kSlash30DPLineWidth) + 740 | moneyLength + maxSingleSideLength, 741 | 2 * kHegiht60DPDistance + kLabelHeight); 742 | 743 | point = CGPointMake(moneyLength + kSlash50DPLineWidth + kSlash30DPLineWidth, 744 | CGRectGetHeight(self.frame) / 2); 745 | for (int idx = 0; idx < self.tagGroup.count; idx++) { 746 | 747 | NSMutableArray *lineBranch; 748 | switch (idx) { 749 | case 0: { 750 | lineBranch = [NSMutableArray 751 | arrayWithObjects: 752 | [NSValue valueWithCGPoint:point], 753 | [NSValue valueWithCGPoint:CGPointMake( 754 | point.x + kSlash50DPLineWidth, 755 | point.y - kHegiht60DPDistance)], 756 | [NSValue valueWithCGPoint:CGPointMake( 757 | point.x + kSlash50DPLineWidth + 758 | kSlash30DPLineWidth, 759 | point.y - kHegiht60DPDistance)], 760 | nil]; 761 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 762 | } break; 763 | case 1: { 764 | lineBranch = [NSMutableArray 765 | arrayWithObjects: 766 | [NSValue valueWithCGPoint:point], 767 | [NSValue valueWithCGPoint:CGPointMake( 768 | point.x + kSlash50DPLineWidth, 769 | point.y + kHegiht60DPDistance)], 770 | [NSValue valueWithCGPoint:CGPointMake( 771 | point.x + kSlash50DPLineWidth + 772 | kSlash30DPLineWidth, 773 | point.y + kHegiht60DPDistance)], 774 | nil]; 775 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 776 | } break; 777 | case 2: { 778 | lineBranch = [NSMutableArray 779 | arrayWithObjects: 780 | [NSValue valueWithCGPoint:point], 781 | [NSValue valueWithCGPoint:CGPointMake( 782 | point.x - kSlash50DPLineWidth, 783 | point.y + kHegiht60DPDistance)], 784 | [NSValue valueWithCGPoint:CGPointMake( 785 | point.x - kSlash50DPLineWidth - 786 | kSlash30DPLineWidth, 787 | point.y + kHegiht60DPDistance)], 788 | nil]; 789 | [tagPointsArry setObject:lineBranch forKey:@(2)]; 790 | } break; 791 | } 792 | } 793 | } else if (self.type == kMaxTagGroupThreeTagTypeLeftTop) { 794 | //这里需要考虑右侧是不是在父视图外侧,这个时候要整体往左侧移动,但是可能存在左侧移除父视图的外部(要定义规则) 795 | 796 | self.frame = 797 | CGRectMake(self.point.x - (kSlash50DPLineWidth + kSlash30DPLineWidth + 798 | moneyLength), 799 | self.point.y - kHegiht60DPDistance - kLabelHeight / 2, 800 | 2 * (kSlash50DPLineWidth + kSlash30DPLineWidth) + 801 | moneyLength + maxSingleSideLength, 802 | 2 * kHegiht60DPDistance + kLabelHeight); 803 | 804 | point = CGPointMake(moneyLength + kSlash50DPLineWidth + kSlash30DPLineWidth, 805 | CGRectGetHeight(self.frame) / 2); 806 | for (int idx = 0; idx < self.tagGroup.count; idx++) { 807 | 808 | NSMutableArray *lineBranch; 809 | switch (idx) { 810 | case 0: { 811 | lineBranch = [NSMutableArray 812 | arrayWithObjects: 813 | [NSValue valueWithCGPoint:point], 814 | [NSValue valueWithCGPoint:CGPointMake( 815 | point.x + kSlash50DPLineWidth, 816 | point.y - kHegiht60DPDistance)], 817 | [NSValue valueWithCGPoint:CGPointMake( 818 | point.x + kSlash50DPLineWidth + 819 | kSlash30DPLineWidth, 820 | point.y - kHegiht60DPDistance)], 821 | nil]; 822 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 823 | } break; 824 | case 1: { 825 | lineBranch = [NSMutableArray 826 | arrayWithObjects: 827 | [NSValue valueWithCGPoint:point], 828 | [NSValue valueWithCGPoint:CGPointMake( 829 | point.x + kSlash50DPLineWidth, 830 | point.y + kHegiht60DPDistance)], 831 | [NSValue valueWithCGPoint:CGPointMake( 832 | point.x + kSlash50DPLineWidth + 833 | kSlash30DPLineWidth, 834 | point.y + kHegiht60DPDistance)], 835 | nil]; 836 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 837 | } break; 838 | case 2: { 839 | lineBranch = [NSMutableArray 840 | arrayWithObjects: 841 | [NSValue valueWithCGPoint:point], 842 | [NSValue valueWithCGPoint:CGPointMake( 843 | point.x - kSlash50DPLineWidth, 844 | point.y - kHegiht60DPDistance)], 845 | [NSValue valueWithCGPoint:CGPointMake( 846 | point.x - kSlash50DPLineWidth - 847 | kSlash30DPLineWidth, 848 | point.y - kHegiht60DPDistance)], 849 | nil]; 850 | [tagPointsArry setObject:lineBranch forKey:@(2)]; 851 | } break; 852 | } 853 | } 854 | } else if (self.type == kMaxTagGroupThreeTagTypeRightTop) { 855 | //这里需要考虑右侧是不是在父视图外侧,这个时候要整体往左侧移动,但是可能存在左侧移除父视图的外部(要定义规则) 856 | self.frame = 857 | CGRectMake(self.point.x - (kSlash50DPLineWidth + kSlash30DPLineWidth + 858 | maxSingleSideLength), 859 | self.point.y - kHegiht60DPDistance - kLabelHeight / 2, 860 | 2 * (kSlash50DPLineWidth + kSlash30DPLineWidth) + 861 | moneyLength + maxSingleSideLength, 862 | 2 * kHegiht60DPDistance + kLabelHeight); 863 | 864 | point = CGPointMake(maxSingleSideLength + kSlash50DPLineWidth + 865 | kSlash30DPLineWidth, 866 | CGRectGetHeight(self.frame) / 2); 867 | for (int idx = 0; idx < self.tagGroup.count; idx++) { 868 | 869 | NSMutableArray *lineBranch; 870 | switch (idx) { 871 | case 0: { 872 | lineBranch = [NSMutableArray 873 | arrayWithObjects: 874 | [NSValue valueWithCGPoint:point], 875 | [NSValue valueWithCGPoint:CGPointMake( 876 | point.x - kSlash50DPLineWidth, 877 | point.y - kHegiht60DPDistance)], 878 | [NSValue valueWithCGPoint:CGPointMake( 879 | point.x - kSlash50DPLineWidth - 880 | kSlash30DPLineWidth, 881 | point.y - kHegiht60DPDistance)], 882 | nil]; 883 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 884 | } break; 885 | case 1: { 886 | lineBranch = [NSMutableArray 887 | arrayWithObjects: 888 | [NSValue valueWithCGPoint:point], 889 | [NSValue valueWithCGPoint:CGPointMake( 890 | point.x - kSlash50DPLineWidth, 891 | point.y + kHegiht60DPDistance)], 892 | [NSValue valueWithCGPoint:CGPointMake( 893 | point.x - kSlash50DPLineWidth - 894 | kSlash30DPLineWidth, 895 | point.y + kHegiht60DPDistance)], 896 | nil]; 897 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 898 | } break; 899 | case 2: { 900 | lineBranch = [NSMutableArray 901 | arrayWithObjects: 902 | [NSValue valueWithCGPoint:point], 903 | [NSValue valueWithCGPoint:CGPointMake( 904 | point.x + kSlash50DPLineWidth, 905 | point.y - kHegiht60DPDistance)], 906 | [NSValue valueWithCGPoint:CGPointMake( 907 | point.x + kSlash50DPLineWidth + 908 | kSlash30DPLineWidth, 909 | point.y - kHegiht60DPDistance)], 910 | nil]; 911 | [tagPointsArry setObject:lineBranch forKey:@(2)]; 912 | } break; 913 | } 914 | } 915 | } else if (self.type == kMaxTagGroupThreeTagTypeRightBottom) { 916 | //这里需要考虑右侧是不是在父视图外侧,这个时候要整体往左侧移动,但是可能存在左侧移除父视图的外部(要定义规则) 917 | 918 | self.frame = 919 | CGRectMake(self.point.x - (kSlash50DPLineWidth + kSlash30DPLineWidth + 920 | maxSingleSideLength), 921 | self.point.y - kHegiht60DPDistance - kLabelHeight / 2, 922 | 2 * (kSlash50DPLineWidth + kSlash30DPLineWidth) + 923 | moneyLength + maxSingleSideLength, 924 | 2 * kHegiht60DPDistance + kLabelHeight); 925 | 926 | point = CGPointMake(maxSingleSideLength + kSlash50DPLineWidth + 927 | kSlash30DPLineWidth, 928 | CGRectGetHeight(self.frame) / 2); 929 | for (int idx = 0; idx < self.tagGroup.count; idx++) { 930 | 931 | NSMutableArray *lineBranch; 932 | switch (idx) { 933 | case 0: { 934 | lineBranch = [NSMutableArray 935 | arrayWithObjects: 936 | [NSValue valueWithCGPoint:point], 937 | [NSValue valueWithCGPoint:CGPointMake( 938 | point.x - kSlash50DPLineWidth, 939 | point.y - kHegiht60DPDistance)], 940 | [NSValue valueWithCGPoint:CGPointMake( 941 | point.x - kSlash50DPLineWidth - 942 | kSlash30DPLineWidth, 943 | point.y - kHegiht60DPDistance)], 944 | nil]; 945 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 946 | } break; 947 | case 1: { 948 | lineBranch = [NSMutableArray 949 | arrayWithObjects: 950 | [NSValue valueWithCGPoint:point], 951 | [NSValue valueWithCGPoint:CGPointMake( 952 | point.x - kSlash50DPLineWidth, 953 | point.y + kHegiht60DPDistance)], 954 | [NSValue valueWithCGPoint:CGPointMake( 955 | point.x - kSlash50DPLineWidth - 956 | kSlash30DPLineWidth, 957 | point.y + kHegiht60DPDistance)], 958 | nil]; 959 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 960 | } break; 961 | case 2: { 962 | lineBranch = [NSMutableArray 963 | arrayWithObjects: 964 | [NSValue valueWithCGPoint:point], 965 | [NSValue valueWithCGPoint:CGPointMake( 966 | point.x + kSlash50DPLineWidth, 967 | point.y + kHegiht60DPDistance)], 968 | [NSValue valueWithCGPoint:CGPointMake( 969 | point.x + kSlash50DPLineWidth + 970 | kSlash30DPLineWidth, 971 | point.y + kHegiht60DPDistance)], 972 | nil]; 973 | [tagPointsArry setObject:lineBranch forKey:@(2)]; 974 | } break; 975 | } 976 | } 977 | } else if (self.type == kMaxTagGroupThreeTagTypeBrokenRight) { 978 | //这里需要考虑右侧是不是在父视图外侧,这个时候要整体往左侧移动,但是可能存在左侧移除父视图的外部(要定义规则) 979 | 980 | self.frame = CGRectMake( 981 | self.point.x, self.point.y - kHegiht60DPDistance + kLabelHeight / 2, 982 | kSlash50DPLineWidth + kSlash30DPLineWidth + maxTotleMaxLength, 983 | 2 * kHegiht60DPDistance + kLabelHeight); 984 | 985 | point = CGPointMake(0, CGRectGetHeight(self.frame) / 2); 986 | for (int idx = 0; idx < self.tagGroup.count; idx++) { 987 | 988 | NSMutableArray *lineBranch; 989 | switch (idx) { 990 | case 0: { 991 | lineBranch = [NSMutableArray 992 | arrayWithObjects: 993 | [NSValue valueWithCGPoint:point], 994 | [NSValue valueWithCGPoint:CGPointMake(point.x + kSlash50DPLineWidth, 995 | point.y - kHegiht60DPDistance)], 996 | [NSValue valueWithCGPoint:CGPointMake(point.x + kSlash50DPLineWidth + 997 | kSlash30DPLineWidth, 998 | point.y - kHegiht60DPDistance)], 999 | nil]; 1000 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 1001 | } break; 1002 | case 1: { 1003 | lineBranch = [NSMutableArray 1004 | arrayWithObjects:[NSValue valueWithCGPoint:point], 1005 | [NSValue 1006 | valueWithCGPoint:CGPointMake(point.x + 1007 | kSlash70DPLineWidth, 1008 | point.y)], 1009 | nil]; 1010 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 1011 | } break; 1012 | case 2: { 1013 | lineBranch = [NSMutableArray 1014 | arrayWithObjects: 1015 | [NSValue valueWithCGPoint:point], 1016 | [NSValue valueWithCGPoint:CGPointMake(point.x + kSlash50DPLineWidth, 1017 | point.y + kHegiht60DPDistance)], 1018 | [NSValue valueWithCGPoint:CGPointMake(point.x + kSlash50DPLineWidth + 1019 | kSlash30DPLineWidth, 1020 | point.y + kHegiht60DPDistance)], 1021 | nil]; 1022 | [tagPointsArry setObject:lineBranch forKey:@(2)]; 1023 | } break; 1024 | } 1025 | } 1026 | } 1027 | else if (self.type == kMaxTagGroupThreeTagTypeBrokenLeft) 1028 | { 1029 | self.frame = CGRectMake(self.point.x - 1030 | (kSlash30DPLineWidth + maxTotleMaxLength + kSlash50DPLineWidth), 1031 | self.point.y - kHegiht60DPDistance - kLabelHeight / 2, 1032 | kSlash30DPLineWidth + maxTotleMaxLength + kSlash50DPLineWidth, 1033 | 2 * kHegiht60DPDistance + kLabelHeight); 1034 | 1035 | point = CGPointMake(CGRectGetWidth(self.frame), 1036 | CGRectGetHeight(self.frame) / 2); 1037 | for (int idx = 0; idx < self.tagGroup.count; idx++) 1038 | { 1039 | NSMutableArray *lineBranch; 1040 | switch (idx) { 1041 | case 0: { 1042 | lineBranch = [NSMutableArray 1043 | arrayWithObjects: 1044 | [NSValue valueWithCGPoint:point], 1045 | [NSValue valueWithCGPoint:CGPointMake(point.x - kSlash50DPLineWidth, 1046 | point.y - kHegiht60DPDistance)], 1047 | [NSValue valueWithCGPoint:CGPointMake(point.x - kSlash50DPLineWidth - 1048 | kSlash30DPLineWidth, 1049 | point.y - kHegiht60DPDistance)], 1050 | nil]; 1051 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 1052 | } break; 1053 | case 1: { 1054 | lineBranch = [NSMutableArray 1055 | arrayWithObjects:[NSValue valueWithCGPoint:point], 1056 | [NSValue 1057 | valueWithCGPoint:CGPointMake(point.x - 1058 | kSlash70DPLineWidth, 1059 | point.y)], 1060 | nil]; 1061 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 1062 | } break; 1063 | case 2: { 1064 | lineBranch = [NSMutableArray 1065 | arrayWithObjects: 1066 | [NSValue valueWithCGPoint:point], 1067 | [NSValue valueWithCGPoint:CGPointMake(point.x - kSlash50DPLineWidth, 1068 | point.y + kHegiht60DPDistance)], 1069 | [NSValue valueWithCGPoint:CGPointMake(point.x - kSlash50DPLineWidth - 1070 | kSlash30DPLineWidth, 1071 | point.y + kHegiht60DPDistance)], 1072 | nil]; 1073 | [tagPointsArry setObject:lineBranch forKey:@(2)]; 1074 | } break; 1075 | } 1076 | } 1077 | } 1078 | else if (self.type == kMaxTagGroupThreeTagTypeRight) 1079 | { 1080 | //这里需要考虑右侧是不是在父视图外侧,这个时候要整体往左侧移动,但是可能存在左侧移除父视图的外部(要定义规则) 1081 | 1082 | self.frame = CGRectMake(self.point.x, self.point.y - kHegiht60DPDistance + 1083 | kLabelHeight / 2, 1084 | kSlash40DPLineWidth + maxTotleMaxLength, 1085 | 2 * kHegiht60DPDistance + kLabelHeight); 1086 | 1087 | point = CGPointMake(0, CGRectGetHeight(self.frame) / 2); 1088 | for (int idx = 0; idx < self.tagGroup.count; idx++) 1089 | { 1090 | NSMutableArray *lineBranch; 1091 | switch (idx) { 1092 | case 0: { 1093 | lineBranch = [NSMutableArray 1094 | arrayWithObjects:[NSValue valueWithCGPoint:point], 1095 | [NSValue 1096 | valueWithCGPoint:CGPointMake(point.x, 1097 | point.y - 1098 | kHegiht60DPDistance)], 1099 | [NSValue 1100 | valueWithCGPoint:CGPointMake(point.x + 1101 | kSlash40DPLineWidth, 1102 | point.y - 1103 | kHegiht60DPDistance)], 1104 | nil]; 1105 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 1106 | } break; 1107 | case 1: { 1108 | lineBranch = [NSMutableArray 1109 | arrayWithObjects:[NSValue valueWithCGPoint:point], 1110 | [NSValue 1111 | valueWithCGPoint:CGPointMake(point.x + 1112 | kSlash40DPLineWidth, 1113 | point.y)], 1114 | nil]; 1115 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 1116 | } break; 1117 | case 2: { 1118 | lineBranch = [NSMutableArray 1119 | arrayWithObjects:[NSValue valueWithCGPoint:point], 1120 | [NSValue 1121 | valueWithCGPoint:CGPointMake(point.x, 1122 | point.y + 1123 | kHegiht60DPDistance)], 1124 | [NSValue 1125 | valueWithCGPoint:CGPointMake(point.x + 1126 | kSlash40DPLineWidth, 1127 | point.y + 1128 | kHegiht60DPDistance)], 1129 | nil]; 1130 | [tagPointsArry setObject:lineBranch forKey:@(2)]; 1131 | } break; 1132 | } 1133 | } 1134 | } 1135 | else if (self.type == kMaxTagGroupThreeTagTypeLeft) 1136 | { 1137 | self.frame = 1138 | CGRectMake(self.point.x - (kSlash40DPLineWidth + maxTotleMaxLength), 1139 | self.point.y - kHegiht60DPDistance - kLabelHeight / 2, 1140 | kSlash40DPLineWidth + maxTotleMaxLength, 1141 | 2 * kHegiht60DPDistance + kLabelHeight); 1142 | 1143 | point = CGPointMake(CGRectGetWidth(self.frame), 1144 | CGRectGetHeight(self.frame) / 2); 1145 | for (int idx = 0; idx < self.tagGroup.count; idx++) 1146 | { 1147 | NSMutableArray *lineBranch; 1148 | switch (idx) { 1149 | case 0: { 1150 | lineBranch = [NSMutableArray 1151 | arrayWithObjects:[NSValue valueWithCGPoint:point], 1152 | [NSValue 1153 | valueWithCGPoint:CGPointMake(point.x, 1154 | point.y - 1155 | kHegiht60DPDistance)], 1156 | [NSValue 1157 | valueWithCGPoint:CGPointMake(point.x - 1158 | kSlash40DPLineWidth, 1159 | point.y - 1160 | kHegiht60DPDistance)], 1161 | nil]; 1162 | [tagPointsArry setObject:lineBranch forKey:@(0)]; 1163 | } break; 1164 | case 1: { 1165 | lineBranch = [NSMutableArray 1166 | arrayWithObjects:[NSValue valueWithCGPoint:point], 1167 | [NSValue 1168 | valueWithCGPoint:CGPointMake(point.x - 1169 | kSlash40DPLineWidth, 1170 | point.y)], 1171 | nil]; 1172 | [tagPointsArry setObject:lineBranch forKey:@(1)]; 1173 | } break; 1174 | case 2: { 1175 | lineBranch = [NSMutableArray 1176 | arrayWithObjects:[NSValue valueWithCGPoint:point], 1177 | [NSValue 1178 | valueWithCGPoint:CGPointMake(point.x, 1179 | point.y + 1180 | kHegiht60DPDistance)], 1181 | [NSValue 1182 | valueWithCGPoint:CGPointMake(point.x - 1183 | kSlash40DPLineWidth, 1184 | point.y + 1185 | kHegiht60DPDistance)], 1186 | nil]; 1187 | [tagPointsArry setObject:lineBranch forKey:@(2)]; 1188 | } break; 1189 | } 1190 | } 1191 | } 1192 | 1193 | self.lightingView.centerPoint = point; 1194 | 1195 | if (self.frame.origin.x < 0) 1196 | { 1197 | self.frame = CGRectMake(0, 1198 | self.frame.origin.y, 1199 | self.frame.size.width, 1200 | self.frame.size.height); 1201 | } 1202 | 1203 | if (self.frame.origin.y < 0) 1204 | { 1205 | self.frame = CGRectMake(self.frame.origin.x, 1206 | 0, 1207 | self.frame.size.width, 1208 | self.frame.size.height); 1209 | } 1210 | 1211 | if (CGRectGetMaxX(self.frame) > _superFrame.size.width) 1212 | { 1213 | self.frame = CGRectMake(_superFrame.size.width - self.frame.size.width, 1214 | self.frame.origin.y, 1215 | self.frame.size.width, 1216 | self.frame.size.height); 1217 | } 1218 | 1219 | if (CGRectGetMaxY(self.frame) > _superFrame.size.height) 1220 | { 1221 | self.frame = CGRectMake(self.frame.origin.x, 1222 | _superFrame.size.height - self.frame.size.height, 1223 | self.frame.size.width, 1224 | self.frame.size.height); 1225 | } 1226 | 1227 | [tagPointsArry enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, 1228 | NSArray *_Nonnull points, 1229 | BOOL *_Nonnull stop) { 1230 | 1231 | NSInteger idx = [key integerValue]; 1232 | CGPoint lastPoint = [[points lastObject] CGPointValue]; 1233 | NSInteger currentTagIndex = 0; 1234 | 1235 | CAShapeLayer *lineLayer = nil; 1236 | CAShapeLayer *linePoint = nil; 1237 | UILabel *textlabel = nil; 1238 | switch (idx) { 1239 | case 0: { 1240 | if (!_lineLayer0) 1241 | { 1242 | _lineLabel0 = [[UILabel alloc] init]; 1243 | _lineLayer0 = [CAShapeLayer layer]; 1244 | [self.layer addSublayer:_lineLayer0]; 1245 | [self addSubview:_lineLabel0]; 1246 | 1247 | _label0TapGestureRecognizer = [[UITapGestureRecognizer alloc] init]; 1248 | [_label0TapGestureRecognizer addTarget:self 1249 | action:@selector(gestureRecognizerHandle:)]; 1250 | _lineLabel0.userInteractionEnabled = YES; 1251 | [_lineLabel0 addGestureRecognizer:_label0TapGestureRecognizer]; 1252 | 1253 | _linePoint0 = [self whiteLayer]; 1254 | [_lineLayer0 addSublayer:_linePoint0]; 1255 | } 1256 | currentTagIndex = idx; 1257 | lineLayer = _lineLayer0; 1258 | linePoint = _linePoint0; 1259 | textlabel = _lineLabel0; 1260 | } break; 1261 | case 1: { 1262 | if (!_lineLayer1) 1263 | { 1264 | _lineLabel1 = [[UILabel alloc] init]; 1265 | _lineLayer1 = [CAShapeLayer layer]; 1266 | [self.layer addSublayer:_lineLayer1]; 1267 | [self addSubview:_lineLabel1]; 1268 | 1269 | _label1TapGestureRecognizer = [[UITapGestureRecognizer alloc] init]; 1270 | [_label1TapGestureRecognizer addTarget:self 1271 | action:@selector(gestureRecognizerHandle:)]; 1272 | _lineLabel1.userInteractionEnabled = YES; 1273 | [_lineLabel1 addGestureRecognizer:_label1TapGestureRecognizer]; 1274 | 1275 | _linePoint1 = [self whiteLayer]; 1276 | [_lineLayer1 addSublayer:_linePoint1]; 1277 | } 1278 | currentTagIndex = idx; 1279 | lineLayer = _lineLayer1; 1280 | linePoint = _linePoint1; 1281 | textlabel = _lineLabel1; 1282 | } break; 1283 | case 2: { 1284 | if (!_lineLayer2) 1285 | { 1286 | _lineLabel2 = [[UILabel alloc] init]; 1287 | _lineLayer2 = [CAShapeLayer layer]; 1288 | [self.layer addSublayer:_lineLayer2]; 1289 | [self addSubview:_lineLabel2]; 1290 | 1291 | _label2TapGestureRecognizer = [[UITapGestureRecognizer alloc] init]; 1292 | [_label2TapGestureRecognizer addTarget:self 1293 | action:@selector(gestureRecognizerHandle:)]; 1294 | _lineLabel2.userInteractionEnabled = YES; 1295 | [_lineLabel2 addGestureRecognizer:_label2TapGestureRecognizer]; 1296 | 1297 | _linePoint2 = [self whiteLayer]; 1298 | [_lineLayer2 addSublayer:_linePoint2]; 1299 | } 1300 | currentTagIndex = idx; 1301 | lineLayer = _lineLayer2; 1302 | linePoint = _linePoint2; 1303 | textlabel = _lineLabel2; 1304 | } break; 1305 | default: 1306 | lineLayer = [CAShapeLayer layer]; 1307 | break; 1308 | } 1309 | 1310 | //清空面板 1311 | lineLayer.path = nil; 1312 | textlabel.frame = CGRectZero; 1313 | lineLayer.strokeColor = ktagColor.CGColor; 1314 | textlabel.text = nil; 1315 | textlabel.textColor = ktagColor; 1316 | textlabel.textAlignment = NSTextAlignmentCenter; 1317 | // 指定frame,只是为了设置宽度和高度 1318 | // 设置居中显示 1319 | // 设置填充颜色 1320 | lineLayer.fillColor = [UIColor clearColor].CGColor; 1321 | // 设置线宽 1322 | lineLayer.lineWidth = kLineValue; 1323 | // 使用UIBezierPath创建路径 1324 | UIBezierPath *linePath = [UIBezierPath bezierPath]; 1325 | 1326 | [points enumerateObjectsUsingBlock:^(NSValue *_Nonnull pointNumber, NSUInteger idx, BOOL *_Nonnull stop) { 1327 | 1328 | CGPoint point = pointNumber.CGPointValue; 1329 | if (idx == 0) 1330 | { 1331 | [linePath moveToPoint:point]; 1332 | } 1333 | else 1334 | { 1335 | [linePath addLineToPoint:point]; 1336 | } 1337 | 1338 | }]; 1339 | 1340 | // 设置CAShapeLayer与UIBezierPath关联 1341 | lineLayer.path = linePath.CGPath; 1342 | //创建动画 1343 | CABasicAnimation *animation = [CABasicAnimation 1344 | animationWithKeyPath:NSStringFromSelector(@selector(strokeEnd))]; 1345 | animation.fromValue = @0.0; 1346 | animation.toValue = @1.0; 1347 | animation.delegate = self; 1348 | animation.duration = 0.8; 1349 | 1350 | [lineLayer addAnimation:animation forKey:nil]; 1351 | 1352 | linePoint.hidden = YES; 1353 | linePoint.frame = CGRectMake(0, 0, 6.f, 6.f); 1354 | NSValue *point = [points lastObject]; 1355 | linePoint.position = point.CGPointValue; 1356 | 1357 | CGFloat lineWidth = [NSString widthWithAttributes:nil text:self.tagGroup[currentTagIndex]]; 1358 | 1359 | //添加 文字显示 1360 | switch (self.type) { 1361 | case kMaxTagGroupThreeTagTypeRight: 1362 | case kMaxTagGroupThreeTagTypeBrokenRight: { 1363 | [textlabel 1364 | setFrame:CGRectMake(lastPoint.x + kWithePointWidth, 1365 | lastPoint.y - kLabelHeight / 2, 1366 | lineWidth - kWithePointWidth, 1367 | kLabelHeight)]; 1368 | } break; 1369 | case kMaxTagGroupThreeTagTypeLeft: 1370 | case kMaxTagGroupThreeTagTypeBrokenLeft: { 1371 | [textlabel setFrame:CGRectMake(lastPoint.x - lineWidth, 1372 | lastPoint.y - kLabelHeight / 2, 1373 | lineWidth - kWithePointWidth, 1374 | kLabelHeight)]; 1375 | } break; 1376 | case kMaxTagGroupThreeTagTypeRightTop: 1377 | case kMaxTagGroupThreeTagTypeRightBottom: { 1378 | if (currentTagIndex == 2) 1379 | { 1380 | [textlabel setFrame:CGRectMake(lastPoint.x + kWithePointWidth, 1381 | lastPoint.y - kLabelHeight / 2, 1382 | lineWidth - kWithePointWidth, 1383 | kLabelHeight)]; 1384 | 1385 | } 1386 | else 1387 | { 1388 | [textlabel setFrame:CGRectMake(lastPoint.x - lineWidth, 1389 | lastPoint.y - kLabelHeight / 2, 1390 | lineWidth - kWithePointWidth, 1391 | kLabelHeight)]; 1392 | } 1393 | 1394 | } break; 1395 | case kMaxTagGroupThreeTagTypeLeftTop: 1396 | case kMaxTagGroupThreeTagTypeLeftBottom: { 1397 | 1398 | if (currentTagIndex != 2) 1399 | { 1400 | [textlabel setFrame:CGRectMake(lastPoint.x + kWithePointWidth, 1401 | lastPoint.y - kLabelHeight / 2, 1402 | lineWidth - kWithePointWidth, 1403 | kLabelHeight)]; 1404 | 1405 | } 1406 | else 1407 | { 1408 | [textlabel setFrame:CGRectMake(lastPoint.x - lineWidth, 1409 | lastPoint.y - kLabelHeight / 2, 1410 | lineWidth - kWithePointWidth, 1411 | kLabelHeight)]; 1412 | } 1413 | 1414 | } break; 1415 | default:{ 1416 | 1417 | }break; 1418 | } 1419 | 1420 | textlabel.text = self.tagGroup[idx]; 1421 | textlabel.font = [UIFont systemFontOfSize:12]; 1422 | textlabel.hidden = YES; 1423 | }]; 1424 | } 1425 | 1426 | #pragma mark - CABasicAnimation delegate 1427 | - (void)animationDidStart:(CAAnimation *)anim 1428 | { 1429 | 1430 | } 1431 | 1432 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag 1433 | { 1434 | _lineLabel0.hidden = NO; 1435 | _lineLabel1.hidden = NO; 1436 | _lineLabel2.hidden = NO; 1437 | 1438 | _linePoint0.hidden = NO; 1439 | _linePoint1.hidden = NO; 1440 | _linePoint2.hidden = NO; 1441 | } 1442 | 1443 | #pragma mark - Ges 1444 | 1445 | - (void)gestureRecognizerHandle:(UIGestureRecognizer *)gestureRecognizer 1446 | { 1447 | if (gestureRecognizer == _longPressGestureRecognizer) 1448 | { 1449 | if ([gestureRecognizer state] == UIGestureRecognizerStateBegan) 1450 | { 1451 | if (_longPressBlock) 1452 | { 1453 | _longPressBlock(self); 1454 | } 1455 | } 1456 | } 1457 | else if (gestureRecognizer == _tapGestureRecognizer) 1458 | { 1459 | if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) 1460 | { 1461 | [self changeDirection]; 1462 | } 1463 | } 1464 | else if (gestureRecognizer == _label0TapGestureRecognizer) 1465 | { 1466 | if (gestureRecognizer.state == UIGestureRecognizerStateEnded) 1467 | { 1468 | if (_tapGestureRecognizer) 1469 | { 1470 | if (_tapBlock) 1471 | { 1472 | _tapBlock(self, _lineLabel0); 1473 | } 1474 | } 1475 | } 1476 | } 1477 | else if (gestureRecognizer == _label1TapGestureRecognizer) 1478 | { 1479 | if (gestureRecognizer.state == UIGestureRecognizerStateEnded) 1480 | { 1481 | if (_tapGestureRecognizer) 1482 | { 1483 | if (_tapBlock) 1484 | { 1485 | _tapBlock(self, _lineLabel1); 1486 | } 1487 | } 1488 | } 1489 | } 1490 | else if (gestureRecognizer == _label2TapGestureRecognizer) 1491 | { 1492 | if (gestureRecognizer.state == UIGestureRecognizerStateEnded) 1493 | { 1494 | if (_tapGestureRecognizer) 1495 | { 1496 | if (_tapBlock) 1497 | { 1498 | _tapBlock(self, _lineLabel2); 1499 | } 1500 | } 1501 | } 1502 | } 1503 | } 1504 | 1505 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 1506 | { 1507 | _isDragging = NO; 1508 | 1509 | UITouch *touch = [touches anyObject]; 1510 | self.beginpoint = [touch locationInView:self]; 1511 | [super touchesBegan:touches withEvent:event]; 1512 | } 1513 | 1514 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 1515 | { 1516 | _isDragging = YES; 1517 | UITouch *touch = [touches anyObject]; 1518 | CGPoint currentLocation = [touch locationInView:self]; 1519 | CGRect frame = self.frame; 1520 | 1521 | CGFloat offsetX = currentLocation.x - self.beginpoint.x; 1522 | CGFloat offsetY = currentLocation.y - self.beginpoint.y; 1523 | frame.origin.x += offsetX; 1524 | frame.origin.y += offsetY; 1525 | 1526 | self.point = CGPointMake(self.point.x + offsetX, self.point.y + offsetY); 1527 | self.frame = frame; 1528 | 1529 | if (self.frame.origin.x < 0) 1530 | { 1531 | self.frame = CGRectMake(0, 1532 | self.frame.origin.y, 1533 | self.frame.size.width, 1534 | self.frame.size.height); 1535 | } 1536 | 1537 | if (self.frame.origin.y < 0) 1538 | { 1539 | self.frame = CGRectMake(self.frame.origin.x, 1540 | 0, 1541 | self.frame.size.width, 1542 | self.frame.size.height); 1543 | } 1544 | 1545 | if (CGRectGetMaxX(self.frame) > _superFrame.size.width) 1546 | { 1547 | self.frame = CGRectMake(_superFrame.size.width - self.frame.size.width, 1548 | self.frame.origin.y, 1549 | self.frame.size.width, 1550 | self.frame.size.height); 1551 | } 1552 | 1553 | if (CGRectGetMaxY(self.frame) > _superFrame.size.height) 1554 | { 1555 | self.frame = CGRectMake(self.frame.origin.x, 1556 | _superFrame.size.height - self.frame.size.height, 1557 | self.frame.size.width, 1558 | self.frame.size.height); 1559 | } 1560 | } 1561 | 1562 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 1563 | { 1564 | [super touchesEnded:touches withEvent:event]; 1565 | if (_isDragging && _dragDoneBlock) 1566 | { 1567 | _dragDoneBlock(self); 1568 | } 1569 | _isDragging = NO; 1570 | } 1571 | 1572 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 1573 | { 1574 | [super touchesCancelled:touches withEvent:event]; 1575 | 1576 | if (_dragCancelBlock) 1577 | { 1578 | _dragCancelBlock(self); 1579 | } 1580 | } 1581 | 1582 | - (CAShapeLayer *)whiteLayer 1583 | { 1584 | UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 6.f, 6.f) cornerRadius:3.f]; 1585 | CAShapeLayer *layer = [CAShapeLayer layer]; 1586 | layer.path = path.CGPath; 1587 | layer.fillColor = [UIColor whiteColor].CGColor; 1588 | return layer; 1589 | } 1590 | 1591 | - (void)changeDirection 1592 | { 1593 | kMaxTagGroupType value; 1594 | if (self.tagGroup.count == 1) 1595 | { 1596 | value = self.type; 1597 | if (value == kMaxTagGroupTypeDefault) 1598 | { 1599 | value = kMaxTagGroupOneTagTypeRight; 1600 | } 1601 | value++; 1602 | if (value == kMaxTagGroupOneTagTypeLeftBottom+1) 1603 | { 1604 | value = kMaxTagGroupOneTagTypeRight; 1605 | } 1606 | self.type = value; 1607 | } 1608 | else if (self.tagGroup.count == 2) 1609 | { 1610 | value = self.type; 1611 | if (value == kMaxTagGroupTypeDefault) 1612 | { 1613 | value = kMaxTagGroupTwoTagTypeBrokenRight; 1614 | } 1615 | value++; 1616 | if (value == kMaxTagGroupTwoTagTypeLeft+1) 1617 | { 1618 | value = kMaxTagGroupTwoTagTypeBrokenRight; 1619 | } 1620 | self.type = value; 1621 | } 1622 | else if (self.tagGroup.count == 3) 1623 | { 1624 | value = self.type; 1625 | if (value == kMaxTagGroupTypeDefault) 1626 | { 1627 | value = kMaxTagGroupThreeTagTypeLeftBottom; 1628 | } 1629 | value++; 1630 | if (value == kMaxTagGroupThreeTagTypeLeft+1) 1631 | { 1632 | value = kMaxTagGroupThreeTagTypeLeftBottom; 1633 | } 1634 | self.type = value; 1635 | } 1636 | [self drawLine]; 1637 | } 1638 | @end 1639 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/NSString+SizeWithFont.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+SizeWithFont.h 3 | // TagGroupDemo 4 | // 5 | // Created by chanli on 16/3/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights 7 | // reserved. 8 | // 9 | 10 | #import 11 | #import 12 | 13 | @interface NSString (SizeWithFont) 14 | 15 | + (CGFloat)widthWithAttributes:(NSDictionary *)attrs 16 | text:(NSString *)string; 17 | 18 | + (CGFloat)maxestWidthWithStringArray:(NSArray *)array; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/NSString+SizeWithFont.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+SizeWithFont.m 3 | // TagGroupDemo 4 | // 5 | // Created by chanli on 16/3/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights 7 | // reserved. 8 | // 9 | 10 | #import "NSString+SizeWithFont.h" 11 | #define kEdgeDistance 5 12 | 13 | @implementation NSString (SizeWithFont) 14 | 15 | + (CGFloat)widthWithAttributes:(NSDictionary *)attrs 16 | text:(NSString *)string { 17 | 18 | NSMutableDictionary *attrsDic = 19 | [NSMutableDictionary dictionaryWithDictionary:@{ 20 | NSFontAttributeName : [UIFont systemFontOfSize:12], 21 | NSForegroundColorAttributeName : [UIColor redColor] 22 | }]; 23 | if (attrs != nil) { 24 | attrsDic = [NSMutableDictionary dictionaryWithDictionary:attrs]; 25 | } 26 | 27 | CGRect rect = 28 | [string boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 15) 29 | options:NSStringDrawingUsesLineFragmentOrigin | 30 | NSStringDrawingUsesFontLeading 31 | attributes:attrsDic 32 | context:nil]; 33 | //6是小白点宽度 34 | return rect.size.width + 2 * kEdgeDistance + 6; 35 | } 36 | 37 | + (CGFloat)maxestWidthWithStringArray:(NSArray *)array { 38 | 39 | __block CGFloat maxLength = 0; 40 | 41 | [array enumerateObjectsUsingBlock:^(NSString *_Nonnull obj, NSUInteger idx, 42 | BOOL *_Nonnull stop) { 43 | 44 | CGFloat length = [NSString widthWithAttributes:nil text:obj]; 45 | maxLength = maxLength > length ? maxLength : length; 46 | 47 | }]; 48 | 49 | return maxLength; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/NSTimer/NSTimer+Addition.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSTimer+Addition.h 3 | // YXLScrollView 4 | // 5 | // Created by Yexinglong on 14/10/9. 6 | // Copyright (c) 2014年 Yexinglong. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSTimer (Addition) 12 | //关闭定时器 13 | - (void)pauseTimer; 14 | //启动定时器 15 | - (void)resumeTimer; 16 | //添加一个定时器 17 | - (void)resumeTimerAfterTimeInterval:(NSTimeInterval)interval; 18 | @end 19 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/NSTimer/NSTimer+Addition.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSTimer+Addition.m 3 | // YXLScrollView 4 | // 5 | // Created by Yexinglong on 14/10/9. 6 | // Copyright (c) 2014年 Yexinglong. All rights reserved. 7 | // 8 | 9 | #import "NSTimer+Addition.h" 10 | 11 | @implementation NSTimer (Addition) 12 | 13 | -(void)pauseTimer 14 | { 15 | if (![self isValid]) { 16 | return ; 17 | } 18 | [self setFireDate:[NSDate distantFuture]]; 19 | } 20 | 21 | -(void)resumeTimer 22 | { 23 | if (![self isValid]) { 24 | return ; 25 | } 26 | [self setFireDate:[NSDate date]]; 27 | } 28 | 29 | - (void)resumeTimerAfterTimeInterval:(NSTimeInterval)interval 30 | { 31 | if (![self isValid]) { 32 | return ; 33 | } 34 | [self setFireDate:[NSDate dateWithTimeIntervalSinceNow:interval]]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TagGroupDemo 4 | // 5 | // Created by chanli on 16/3/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // TagGroupDemo 4 | // 5 | // Created by chanli on 16/3/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights 7 | // reserved. 8 | // 9 | 10 | #import "MaxShapeView.h" 11 | #import "ViewController.h" 12 | #import "MaxLightingView.h" 13 | 14 | @interface ViewController () 15 | 16 | @property(strong, nonatomic) UIImageView *imageView; 17 | @property (strong, nonatomic) MaxShapeView *pathShapeView; 18 | @end 19 | 20 | @implementation ViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | // Do any additional setup after loading the view, typically from a nib. 26 | // [self buildWebView]; 27 | [self buildTag]; 28 | } 29 | 30 | - (void)buildTag { 31 | self.imageView = 32 | [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"meinv.jpg"]]; 33 | self.imageView.userInteractionEnabled = YES; 34 | 35 | self.imageView.frame = self.view.bounds; 36 | 37 | [self.view addSubview:self.imageView]; 38 | self.view.backgroundColor = [UIColor whiteColor]; 39 | 40 | CGPoint point = CGPointMake(100, 200); 41 | 42 | NSArray *tagGroup = @[ @"Moschino", @"裤子", @"¥2000" ]; 43 | // tagGroup = @[ @"Moschino", @"裤子"]; 44 | tagGroup = @[ @"Moschino"]; 45 | 46 | //添加path的UIView 47 | self.pathShapeView = 48 | [[MaxShapeView alloc] initWithFrame:CGRectZero 49 | point:point 50 | tagGroup:tagGroup 51 | tagType:kMaxTagGroupTypeDefault 52 | superFrame:self.view.frame]; 53 | 54 | // pathShapeView.backgroundColor = [UIColor grayColor]; 55 | 56 | [self.view addSubview:self.pathShapeView]; 57 | 58 | 59 | __weak typeof(self) weakSelf = self; 60 | self.pathShapeView.tapBlock = ^(MaxShapeView *shapeView, UILabel *tapLabel) { 61 | 62 | if (tapLabel) 63 | { 64 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"选择后标签个数" message:@"" delegate:weakSelf cancelButtonTitle:@"取消" otherButtonTitles:@"0", @"1", @"2", @"3", nil]; 65 | [alertView show]; 66 | } 67 | }; 68 | 69 | self.pathShapeView.longPressBlock = ^(MaxShapeView *shapeView){ 70 | 71 | //长按 72 | NSLog(@"%s__%d", __func__, __LINE__); 73 | }; 74 | } 75 | 76 | - (void)didReceiveMemoryWarning { 77 | [super didReceiveMemoryWarning]; 78 | // Dispose of any resources that can be recreated. 79 | } 80 | 81 | #pragma mark - alertView 82 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 83 | { 84 | if (buttonIndex == 1) 85 | { 86 | //删除 87 | [self.pathShapeView removeFromSuperview]; 88 | } 89 | else if (buttonIndex == 2) 90 | { 91 | self.pathShapeView.tagGroup = @[@"Moschino"]; 92 | } 93 | else if (buttonIndex == 3) 94 | { 95 | self.pathShapeView.tagGroup = @[ @"Moschino", @"裤子"]; 96 | } 97 | else if (buttonIndex == 4) 98 | { 99 | self.pathShapeView.tagGroup = @[ @"Moschino", @"裤子", @"¥2000"]; 100 | } 101 | 102 | if (self.pathShapeView.tagGroup.count == 1) 103 | { 104 | self.pathShapeView.type = kMaxTagGroupOneTagTypeRight; 105 | } else if (self.pathShapeView.tagGroup.count == 2) { 106 | self.pathShapeView.type = kMaxTagGroupTwoTagTypeBrokenRight; 107 | } else if (self.pathShapeView.tagGroup.count == 3) { 108 | self.pathShapeView.type = kMaxTagGroupThreeTagTypeLeftBottom; 109 | } 110 | 111 | [self.pathShapeView drawLine]; 112 | } 113 | @end 114 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TagGroupDemo 4 | // 5 | // Created by chanli on 16/3/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. 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 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemo/meinv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmw123/ShapeView/b9128210270bba5d50aece18a8efe6014cfa0861/TagGroupDemo/TagGroupDemo/meinv.jpg -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemoTests/TagGroupDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // TagGroupDemoTests.m 3 | // TagGroupDemoTests 4 | // 5 | // Created by chanli on 16/3/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TagGroupDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation TagGroupDemoTests 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 | // Use XCTAssert and related functions to verify your tests produce the correct results. 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 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /TagGroupDemo/TagGroupDemoUITests/TagGroupDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // TagGroupDemoUITests.m 3 | // TagGroupDemoUITests 4 | // 5 | // Created by chanli on 16/3/3. 6 | // Copyright © 2016年 Beijing ChunFengShiLi Technology Co., Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TagGroupDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation TagGroupDemoUITests 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 | -------------------------------------------------------------------------------- /gif/Untitled.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmw123/ShapeView/b9128210270bba5d50aece18a8efe6014cfa0861/gif/Untitled.gif --------------------------------------------------------------------------------