├── .gitignore ├── AnyCornerRadius ├── AnyCornerRadius.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── AnyCornerRadius │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── CYCustomArcImageView.h │ ├── CYCustomArcImageView.m │ ├── Info.plist │ ├── Util │ │ ├── CYAnyCornerRadiusUtil.h │ │ └── CYAnyCornerRadiusUtil.m │ ├── ViewController.h │ ├── ViewController.m │ ├── main.m │ └── timg.jpeg ├── AnyCornerRadiusTests │ ├── AnyCornerRadiusTests.m │ └── Info.plist └── AnyCornerRadiusUITests │ ├── AnyCornerRadiusUITests.m │ └── Info.plist ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 41178D6A208DC87600690F88 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 41178D69208DC87600690F88 /* AppDelegate.m */; }; 11 | 41178D6D208DC87600690F88 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 41178D6C208DC87600690F88 /* ViewController.m */; }; 12 | 41178D70208DC87600690F88 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 41178D6E208DC87600690F88 /* Main.storyboard */; }; 13 | 41178D72208DC87B00690F88 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 41178D71208DC87B00690F88 /* Assets.xcassets */; }; 14 | 41178D75208DC87B00690F88 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 41178D73208DC87B00690F88 /* LaunchScreen.storyboard */; }; 15 | 41178D78208DC87B00690F88 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 41178D77208DC87B00690F88 /* main.m */; }; 16 | 41178D82208DC87C00690F88 /* AnyCornerRadiusTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 41178D81208DC87C00690F88 /* AnyCornerRadiusTests.m */; }; 17 | 41178D8D208DC87C00690F88 /* AnyCornerRadiusUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 41178D8C208DC87C00690F88 /* AnyCornerRadiusUITests.m */; }; 18 | 41178D9D208DC89D00690F88 /* CYAnyCornerRadiusUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 41178D9C208DC89D00690F88 /* CYAnyCornerRadiusUtil.m */; }; 19 | 41178DA0208DC8AC00690F88 /* CYCustomArcImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 41178D9E208DC8AC00690F88 /* CYCustomArcImageView.m */; }; 20 | 41178DA2208DC8BC00690F88 /* timg.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 41178DA1208DC8BC00690F88 /* timg.jpeg */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 41178D7E208DC87C00690F88 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 41178D5D208DC87600690F88 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 41178D64208DC87600690F88; 29 | remoteInfo = AnyCornerRadius; 30 | }; 31 | 41178D89208DC87C00690F88 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = 41178D5D208DC87600690F88 /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 41178D64208DC87600690F88; 36 | remoteInfo = AnyCornerRadius; 37 | }; 38 | /* End PBXContainerItemProxy section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 41178D65208DC87600690F88 /* AnyCornerRadius.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AnyCornerRadius.app; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 41178D68208DC87600690F88 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 43 | 41178D69208DC87600690F88 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 44 | 41178D6B208DC87600690F88 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 45 | 41178D6C208DC87600690F88 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 46 | 41178D6F208DC87600690F88 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 47 | 41178D71208DC87B00690F88 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 48 | 41178D74208DC87B00690F88 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 49 | 41178D76208DC87B00690F88 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 41178D77208DC87B00690F88 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | 41178D7D208DC87C00690F88 /* AnyCornerRadiusTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AnyCornerRadiusTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 41178D81208DC87C00690F88 /* AnyCornerRadiusTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AnyCornerRadiusTests.m; sourceTree = ""; }; 53 | 41178D83208DC87C00690F88 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | 41178D88208DC87C00690F88 /* AnyCornerRadiusUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AnyCornerRadiusUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 41178D8C208DC87C00690F88 /* AnyCornerRadiusUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AnyCornerRadiusUITests.m; sourceTree = ""; }; 56 | 41178D8E208DC87C00690F88 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | 41178D9B208DC89D00690F88 /* CYAnyCornerRadiusUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYAnyCornerRadiusUtil.h; sourceTree = ""; }; 58 | 41178D9C208DC89D00690F88 /* CYAnyCornerRadiusUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYAnyCornerRadiusUtil.m; sourceTree = ""; }; 59 | 41178D9E208DC8AC00690F88 /* CYCustomArcImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYCustomArcImageView.m; sourceTree = ""; }; 60 | 41178D9F208DC8AC00690F88 /* CYCustomArcImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYCustomArcImageView.h; sourceTree = ""; }; 61 | 41178DA1208DC8BC00690F88 /* timg.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = timg.jpeg; sourceTree = ""; }; 62 | /* End PBXFileReference section */ 63 | 64 | /* Begin PBXFrameworksBuildPhase section */ 65 | 41178D62208DC87600690F88 /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | 41178D7A208DC87C00690F88 /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | 41178D85208DC87C00690F88 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | /* End PBXFrameworksBuildPhase section */ 87 | 88 | /* Begin PBXGroup section */ 89 | 41178D5C208DC87600690F88 = { 90 | isa = PBXGroup; 91 | children = ( 92 | 41178D67208DC87600690F88 /* AnyCornerRadius */, 93 | 41178D80208DC87C00690F88 /* AnyCornerRadiusTests */, 94 | 41178D8B208DC87C00690F88 /* AnyCornerRadiusUITests */, 95 | 41178D66208DC87600690F88 /* Products */, 96 | ); 97 | sourceTree = ""; 98 | }; 99 | 41178D66208DC87600690F88 /* Products */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 41178D65208DC87600690F88 /* AnyCornerRadius.app */, 103 | 41178D7D208DC87C00690F88 /* AnyCornerRadiusTests.xctest */, 104 | 41178D88208DC87C00690F88 /* AnyCornerRadiusUITests.xctest */, 105 | ); 106 | name = Products; 107 | sourceTree = ""; 108 | }; 109 | 41178D67208DC87600690F88 /* AnyCornerRadius */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 41178DA1208DC8BC00690F88 /* timg.jpeg */, 113 | 41178D9A208DC88D00690F88 /* Util */, 114 | 41178D9F208DC8AC00690F88 /* CYCustomArcImageView.h */, 115 | 41178D9E208DC8AC00690F88 /* CYCustomArcImageView.m */, 116 | 41178D68208DC87600690F88 /* AppDelegate.h */, 117 | 41178D69208DC87600690F88 /* AppDelegate.m */, 118 | 41178D6B208DC87600690F88 /* ViewController.h */, 119 | 41178D6C208DC87600690F88 /* ViewController.m */, 120 | 41178D6E208DC87600690F88 /* Main.storyboard */, 121 | 41178D71208DC87B00690F88 /* Assets.xcassets */, 122 | 41178D73208DC87B00690F88 /* LaunchScreen.storyboard */, 123 | 41178D76208DC87B00690F88 /* Info.plist */, 124 | 41178D77208DC87B00690F88 /* main.m */, 125 | ); 126 | path = AnyCornerRadius; 127 | sourceTree = ""; 128 | }; 129 | 41178D80208DC87C00690F88 /* AnyCornerRadiusTests */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 41178D81208DC87C00690F88 /* AnyCornerRadiusTests.m */, 133 | 41178D83208DC87C00690F88 /* Info.plist */, 134 | ); 135 | path = AnyCornerRadiusTests; 136 | sourceTree = ""; 137 | }; 138 | 41178D8B208DC87C00690F88 /* AnyCornerRadiusUITests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 41178D8C208DC87C00690F88 /* AnyCornerRadiusUITests.m */, 142 | 41178D8E208DC87C00690F88 /* Info.plist */, 143 | ); 144 | path = AnyCornerRadiusUITests; 145 | sourceTree = ""; 146 | }; 147 | 41178D9A208DC88D00690F88 /* Util */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 41178D9B208DC89D00690F88 /* CYAnyCornerRadiusUtil.h */, 151 | 41178D9C208DC89D00690F88 /* CYAnyCornerRadiusUtil.m */, 152 | ); 153 | path = Util; 154 | sourceTree = ""; 155 | }; 156 | /* End PBXGroup section */ 157 | 158 | /* Begin PBXNativeTarget section */ 159 | 41178D64208DC87600690F88 /* AnyCornerRadius */ = { 160 | isa = PBXNativeTarget; 161 | buildConfigurationList = 41178D91208DC87C00690F88 /* Build configuration list for PBXNativeTarget "AnyCornerRadius" */; 162 | buildPhases = ( 163 | 41178D61208DC87600690F88 /* Sources */, 164 | 41178D62208DC87600690F88 /* Frameworks */, 165 | 41178D63208DC87600690F88 /* Resources */, 166 | ); 167 | buildRules = ( 168 | ); 169 | dependencies = ( 170 | ); 171 | name = AnyCornerRadius; 172 | productName = AnyCornerRadius; 173 | productReference = 41178D65208DC87600690F88 /* AnyCornerRadius.app */; 174 | productType = "com.apple.product-type.application"; 175 | }; 176 | 41178D7C208DC87C00690F88 /* AnyCornerRadiusTests */ = { 177 | isa = PBXNativeTarget; 178 | buildConfigurationList = 41178D94208DC87C00690F88 /* Build configuration list for PBXNativeTarget "AnyCornerRadiusTests" */; 179 | buildPhases = ( 180 | 41178D79208DC87C00690F88 /* Sources */, 181 | 41178D7A208DC87C00690F88 /* Frameworks */, 182 | 41178D7B208DC87C00690F88 /* Resources */, 183 | ); 184 | buildRules = ( 185 | ); 186 | dependencies = ( 187 | 41178D7F208DC87C00690F88 /* PBXTargetDependency */, 188 | ); 189 | name = AnyCornerRadiusTests; 190 | productName = AnyCornerRadiusTests; 191 | productReference = 41178D7D208DC87C00690F88 /* AnyCornerRadiusTests.xctest */; 192 | productType = "com.apple.product-type.bundle.unit-test"; 193 | }; 194 | 41178D87208DC87C00690F88 /* AnyCornerRadiusUITests */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = 41178D97208DC87C00690F88 /* Build configuration list for PBXNativeTarget "AnyCornerRadiusUITests" */; 197 | buildPhases = ( 198 | 41178D84208DC87C00690F88 /* Sources */, 199 | 41178D85208DC87C00690F88 /* Frameworks */, 200 | 41178D86208DC87C00690F88 /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | 41178D8A208DC87C00690F88 /* PBXTargetDependency */, 206 | ); 207 | name = AnyCornerRadiusUITests; 208 | productName = AnyCornerRadiusUITests; 209 | productReference = 41178D88208DC87C00690F88 /* AnyCornerRadiusUITests.xctest */; 210 | productType = "com.apple.product-type.bundle.ui-testing"; 211 | }; 212 | /* End PBXNativeTarget section */ 213 | 214 | /* Begin PBXProject section */ 215 | 41178D5D208DC87600690F88 /* Project object */ = { 216 | isa = PBXProject; 217 | attributes = { 218 | LastUpgradeCheck = 0930; 219 | ORGANIZATIONNAME = Mr.GCY; 220 | TargetAttributes = { 221 | 41178D64208DC87600690F88 = { 222 | CreatedOnToolsVersion = 9.3; 223 | }; 224 | 41178D7C208DC87C00690F88 = { 225 | CreatedOnToolsVersion = 9.3; 226 | TestTargetID = 41178D64208DC87600690F88; 227 | }; 228 | 41178D87208DC87C00690F88 = { 229 | CreatedOnToolsVersion = 9.3; 230 | TestTargetID = 41178D64208DC87600690F88; 231 | }; 232 | }; 233 | }; 234 | buildConfigurationList = 41178D60208DC87600690F88 /* Build configuration list for PBXProject "AnyCornerRadius" */; 235 | compatibilityVersion = "Xcode 9.3"; 236 | developmentRegion = en; 237 | hasScannedForEncodings = 0; 238 | knownRegions = ( 239 | en, 240 | Base, 241 | ); 242 | mainGroup = 41178D5C208DC87600690F88; 243 | productRefGroup = 41178D66208DC87600690F88 /* Products */; 244 | projectDirPath = ""; 245 | projectRoot = ""; 246 | targets = ( 247 | 41178D64208DC87600690F88 /* AnyCornerRadius */, 248 | 41178D7C208DC87C00690F88 /* AnyCornerRadiusTests */, 249 | 41178D87208DC87C00690F88 /* AnyCornerRadiusUITests */, 250 | ); 251 | }; 252 | /* End PBXProject section */ 253 | 254 | /* Begin PBXResourcesBuildPhase section */ 255 | 41178D63208DC87600690F88 /* Resources */ = { 256 | isa = PBXResourcesBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | 41178D75208DC87B00690F88 /* LaunchScreen.storyboard in Resources */, 260 | 41178D72208DC87B00690F88 /* Assets.xcassets in Resources */, 261 | 41178DA2208DC8BC00690F88 /* timg.jpeg in Resources */, 262 | 41178D70208DC87600690F88 /* Main.storyboard in Resources */, 263 | ); 264 | runOnlyForDeploymentPostprocessing = 0; 265 | }; 266 | 41178D7B208DC87C00690F88 /* Resources */ = { 267 | isa = PBXResourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | 41178D86208DC87C00690F88 /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | /* End PBXResourcesBuildPhase section */ 281 | 282 | /* Begin PBXSourcesBuildPhase section */ 283 | 41178D61208DC87600690F88 /* Sources */ = { 284 | isa = PBXSourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | 41178D6D208DC87600690F88 /* ViewController.m in Sources */, 288 | 41178DA0208DC8AC00690F88 /* CYCustomArcImageView.m in Sources */, 289 | 41178D9D208DC89D00690F88 /* CYAnyCornerRadiusUtil.m in Sources */, 290 | 41178D78208DC87B00690F88 /* main.m in Sources */, 291 | 41178D6A208DC87600690F88 /* AppDelegate.m in Sources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | 41178D79208DC87C00690F88 /* Sources */ = { 296 | isa = PBXSourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | 41178D82208DC87C00690F88 /* AnyCornerRadiusTests.m in Sources */, 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | 41178D84208DC87C00690F88 /* Sources */ = { 304 | isa = PBXSourcesBuildPhase; 305 | buildActionMask = 2147483647; 306 | files = ( 307 | 41178D8D208DC87C00690F88 /* AnyCornerRadiusUITests.m in Sources */, 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | /* End PBXSourcesBuildPhase section */ 312 | 313 | /* Begin PBXTargetDependency section */ 314 | 41178D7F208DC87C00690F88 /* PBXTargetDependency */ = { 315 | isa = PBXTargetDependency; 316 | target = 41178D64208DC87600690F88 /* AnyCornerRadius */; 317 | targetProxy = 41178D7E208DC87C00690F88 /* PBXContainerItemProxy */; 318 | }; 319 | 41178D8A208DC87C00690F88 /* PBXTargetDependency */ = { 320 | isa = PBXTargetDependency; 321 | target = 41178D64208DC87600690F88 /* AnyCornerRadius */; 322 | targetProxy = 41178D89208DC87C00690F88 /* PBXContainerItemProxy */; 323 | }; 324 | /* End PBXTargetDependency section */ 325 | 326 | /* Begin PBXVariantGroup section */ 327 | 41178D6E208DC87600690F88 /* Main.storyboard */ = { 328 | isa = PBXVariantGroup; 329 | children = ( 330 | 41178D6F208DC87600690F88 /* Base */, 331 | ); 332 | name = Main.storyboard; 333 | sourceTree = ""; 334 | }; 335 | 41178D73208DC87B00690F88 /* LaunchScreen.storyboard */ = { 336 | isa = PBXVariantGroup; 337 | children = ( 338 | 41178D74208DC87B00690F88 /* Base */, 339 | ); 340 | name = LaunchScreen.storyboard; 341 | sourceTree = ""; 342 | }; 343 | /* End PBXVariantGroup section */ 344 | 345 | /* Begin XCBuildConfiguration section */ 346 | 41178D8F208DC87C00690F88 /* Debug */ = { 347 | isa = XCBuildConfiguration; 348 | buildSettings = { 349 | ALWAYS_SEARCH_USER_PATHS = NO; 350 | CLANG_ANALYZER_NONNULL = YES; 351 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 352 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 353 | CLANG_CXX_LIBRARY = "libc++"; 354 | CLANG_ENABLE_MODULES = YES; 355 | CLANG_ENABLE_OBJC_ARC = YES; 356 | CLANG_ENABLE_OBJC_WEAK = YES; 357 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 358 | CLANG_WARN_BOOL_CONVERSION = YES; 359 | CLANG_WARN_COMMA = YES; 360 | CLANG_WARN_CONSTANT_CONVERSION = YES; 361 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 362 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 363 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 364 | CLANG_WARN_EMPTY_BODY = YES; 365 | CLANG_WARN_ENUM_CONVERSION = YES; 366 | CLANG_WARN_INFINITE_RECURSION = YES; 367 | CLANG_WARN_INT_CONVERSION = YES; 368 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 369 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 370 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 371 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 372 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 373 | CLANG_WARN_STRICT_PROTOTYPES = YES; 374 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 375 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 376 | CLANG_WARN_UNREACHABLE_CODE = YES; 377 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 378 | CODE_SIGN_IDENTITY = "iPhone Developer"; 379 | COPY_PHASE_STRIP = NO; 380 | DEBUG_INFORMATION_FORMAT = dwarf; 381 | ENABLE_STRICT_OBJC_MSGSEND = YES; 382 | ENABLE_TESTABILITY = YES; 383 | GCC_C_LANGUAGE_STANDARD = gnu11; 384 | GCC_DYNAMIC_NO_PIC = NO; 385 | GCC_NO_COMMON_BLOCKS = YES; 386 | GCC_OPTIMIZATION_LEVEL = 0; 387 | GCC_PREPROCESSOR_DEFINITIONS = ( 388 | "DEBUG=1", 389 | "$(inherited)", 390 | ); 391 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 392 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 393 | GCC_WARN_UNDECLARED_SELECTOR = YES; 394 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 395 | GCC_WARN_UNUSED_FUNCTION = YES; 396 | GCC_WARN_UNUSED_VARIABLE = YES; 397 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 398 | MTL_ENABLE_DEBUG_INFO = YES; 399 | ONLY_ACTIVE_ARCH = YES; 400 | SDKROOT = iphoneos; 401 | }; 402 | name = Debug; 403 | }; 404 | 41178D90208DC87C00690F88 /* Release */ = { 405 | isa = XCBuildConfiguration; 406 | buildSettings = { 407 | ALWAYS_SEARCH_USER_PATHS = NO; 408 | CLANG_ANALYZER_NONNULL = YES; 409 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 410 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 411 | CLANG_CXX_LIBRARY = "libc++"; 412 | CLANG_ENABLE_MODULES = YES; 413 | CLANG_ENABLE_OBJC_ARC = YES; 414 | CLANG_ENABLE_OBJC_WEAK = YES; 415 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 416 | CLANG_WARN_BOOL_CONVERSION = YES; 417 | CLANG_WARN_COMMA = YES; 418 | CLANG_WARN_CONSTANT_CONVERSION = YES; 419 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 420 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 421 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 422 | CLANG_WARN_EMPTY_BODY = YES; 423 | CLANG_WARN_ENUM_CONVERSION = YES; 424 | CLANG_WARN_INFINITE_RECURSION = YES; 425 | CLANG_WARN_INT_CONVERSION = YES; 426 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 427 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 428 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 429 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 430 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 431 | CLANG_WARN_STRICT_PROTOTYPES = YES; 432 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 433 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 434 | CLANG_WARN_UNREACHABLE_CODE = YES; 435 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 436 | CODE_SIGN_IDENTITY = "iPhone Developer"; 437 | COPY_PHASE_STRIP = NO; 438 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 439 | ENABLE_NS_ASSERTIONS = NO; 440 | ENABLE_STRICT_OBJC_MSGSEND = YES; 441 | GCC_C_LANGUAGE_STANDARD = gnu11; 442 | GCC_NO_COMMON_BLOCKS = YES; 443 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 444 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 445 | GCC_WARN_UNDECLARED_SELECTOR = YES; 446 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 447 | GCC_WARN_UNUSED_FUNCTION = YES; 448 | GCC_WARN_UNUSED_VARIABLE = YES; 449 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 450 | MTL_ENABLE_DEBUG_INFO = NO; 451 | SDKROOT = iphoneos; 452 | VALIDATE_PRODUCT = YES; 453 | }; 454 | name = Release; 455 | }; 456 | 41178D92208DC87C00690F88 /* Debug */ = { 457 | isa = XCBuildConfiguration; 458 | buildSettings = { 459 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 460 | CODE_SIGN_STYLE = Automatic; 461 | INFOPLIST_FILE = AnyCornerRadius/Info.plist; 462 | LD_RUNPATH_SEARCH_PATHS = ( 463 | "$(inherited)", 464 | "@executable_path/Frameworks", 465 | ); 466 | PRODUCT_BUNDLE_IDENTIFIER = mr.gcy.AnyCornerRadius; 467 | PRODUCT_NAME = "$(TARGET_NAME)"; 468 | TARGETED_DEVICE_FAMILY = "1,2"; 469 | }; 470 | name = Debug; 471 | }; 472 | 41178D93208DC87C00690F88 /* Release */ = { 473 | isa = XCBuildConfiguration; 474 | buildSettings = { 475 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 476 | CODE_SIGN_STYLE = Automatic; 477 | INFOPLIST_FILE = AnyCornerRadius/Info.plist; 478 | LD_RUNPATH_SEARCH_PATHS = ( 479 | "$(inherited)", 480 | "@executable_path/Frameworks", 481 | ); 482 | PRODUCT_BUNDLE_IDENTIFIER = mr.gcy.AnyCornerRadius; 483 | PRODUCT_NAME = "$(TARGET_NAME)"; 484 | TARGETED_DEVICE_FAMILY = "1,2"; 485 | }; 486 | name = Release; 487 | }; 488 | 41178D95208DC87C00690F88 /* Debug */ = { 489 | isa = XCBuildConfiguration; 490 | buildSettings = { 491 | BUNDLE_LOADER = "$(TEST_HOST)"; 492 | CODE_SIGN_STYLE = Automatic; 493 | INFOPLIST_FILE = AnyCornerRadiusTests/Info.plist; 494 | LD_RUNPATH_SEARCH_PATHS = ( 495 | "$(inherited)", 496 | "@executable_path/Frameworks", 497 | "@loader_path/Frameworks", 498 | ); 499 | PRODUCT_BUNDLE_IDENTIFIER = mr.gcy.AnyCornerRadiusTests; 500 | PRODUCT_NAME = "$(TARGET_NAME)"; 501 | TARGETED_DEVICE_FAMILY = "1,2"; 502 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AnyCornerRadius.app/AnyCornerRadius"; 503 | }; 504 | name = Debug; 505 | }; 506 | 41178D96208DC87C00690F88 /* Release */ = { 507 | isa = XCBuildConfiguration; 508 | buildSettings = { 509 | BUNDLE_LOADER = "$(TEST_HOST)"; 510 | CODE_SIGN_STYLE = Automatic; 511 | INFOPLIST_FILE = AnyCornerRadiusTests/Info.plist; 512 | LD_RUNPATH_SEARCH_PATHS = ( 513 | "$(inherited)", 514 | "@executable_path/Frameworks", 515 | "@loader_path/Frameworks", 516 | ); 517 | PRODUCT_BUNDLE_IDENTIFIER = mr.gcy.AnyCornerRadiusTests; 518 | PRODUCT_NAME = "$(TARGET_NAME)"; 519 | TARGETED_DEVICE_FAMILY = "1,2"; 520 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AnyCornerRadius.app/AnyCornerRadius"; 521 | }; 522 | name = Release; 523 | }; 524 | 41178D98208DC87C00690F88 /* Debug */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | CODE_SIGN_STYLE = Automatic; 528 | INFOPLIST_FILE = AnyCornerRadiusUITests/Info.plist; 529 | LD_RUNPATH_SEARCH_PATHS = ( 530 | "$(inherited)", 531 | "@executable_path/Frameworks", 532 | "@loader_path/Frameworks", 533 | ); 534 | PRODUCT_BUNDLE_IDENTIFIER = mr.gcy.AnyCornerRadiusUITests; 535 | PRODUCT_NAME = "$(TARGET_NAME)"; 536 | TARGETED_DEVICE_FAMILY = "1,2"; 537 | TEST_TARGET_NAME = AnyCornerRadius; 538 | }; 539 | name = Debug; 540 | }; 541 | 41178D99208DC87C00690F88 /* Release */ = { 542 | isa = XCBuildConfiguration; 543 | buildSettings = { 544 | CODE_SIGN_STYLE = Automatic; 545 | INFOPLIST_FILE = AnyCornerRadiusUITests/Info.plist; 546 | LD_RUNPATH_SEARCH_PATHS = ( 547 | "$(inherited)", 548 | "@executable_path/Frameworks", 549 | "@loader_path/Frameworks", 550 | ); 551 | PRODUCT_BUNDLE_IDENTIFIER = mr.gcy.AnyCornerRadiusUITests; 552 | PRODUCT_NAME = "$(TARGET_NAME)"; 553 | TARGETED_DEVICE_FAMILY = "1,2"; 554 | TEST_TARGET_NAME = AnyCornerRadius; 555 | }; 556 | name = Release; 557 | }; 558 | /* End XCBuildConfiguration section */ 559 | 560 | /* Begin XCConfigurationList section */ 561 | 41178D60208DC87600690F88 /* Build configuration list for PBXProject "AnyCornerRadius" */ = { 562 | isa = XCConfigurationList; 563 | buildConfigurations = ( 564 | 41178D8F208DC87C00690F88 /* Debug */, 565 | 41178D90208DC87C00690F88 /* Release */, 566 | ); 567 | defaultConfigurationIsVisible = 0; 568 | defaultConfigurationName = Release; 569 | }; 570 | 41178D91208DC87C00690F88 /* Build configuration list for PBXNativeTarget "AnyCornerRadius" */ = { 571 | isa = XCConfigurationList; 572 | buildConfigurations = ( 573 | 41178D92208DC87C00690F88 /* Debug */, 574 | 41178D93208DC87C00690F88 /* Release */, 575 | ); 576 | defaultConfigurationIsVisible = 0; 577 | defaultConfigurationName = Release; 578 | }; 579 | 41178D94208DC87C00690F88 /* Build configuration list for PBXNativeTarget "AnyCornerRadiusTests" */ = { 580 | isa = XCConfigurationList; 581 | buildConfigurations = ( 582 | 41178D95208DC87C00690F88 /* Debug */, 583 | 41178D96208DC87C00690F88 /* Release */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | defaultConfigurationName = Release; 587 | }; 588 | 41178D97208DC87C00690F88 /* Build configuration list for PBXNativeTarget "AnyCornerRadiusUITests" */ = { 589 | isa = XCConfigurationList; 590 | buildConfigurations = ( 591 | 41178D98208DC87C00690F88 /* Debug */, 592 | 41178D99208DC87C00690F88 /* Release */, 593 | ); 594 | defaultConfigurationIsVisible = 0; 595 | defaultConfigurationName = Release; 596 | }; 597 | /* End XCConfigurationList section */ 598 | }; 599 | rootObject = 41178D5D208DC87600690F88 /* Project object */; 600 | } 601 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // AnyCornerRadius 4 | // 5 | // Created by Mr.GCY on 2018/4/23. 6 | // Copyright © 2018年 Mr.GCY. 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 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // AnyCornerRadius 4 | // 5 | // Created by Mr.GCY on 2018/4/23. 6 | // Copyright © 2018年 Mr.GCY. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/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 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/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 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/CYCustomArcImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CYCustomArcImageView.h 3 | // ProjectComponentDemo 4 | // 5 | // Created by Mr.GCY on 2018/4/20. 6 | // Copyright © 2018年 Mr.GCY. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface CYCustomArcImageView : UIView 13 | /** 14 | * Border radii. 15 | */ 16 | @property (nonatomic, assign) CGFloat borderRadius; 17 | @property (nonatomic, assign) CGFloat borderTopLeftRadius; 18 | @property (nonatomic, assign) CGFloat borderTopRightRadius; 19 | @property (nonatomic, assign) CGFloat borderBottomLeftRadius; 20 | @property (nonatomic, assign) CGFloat borderBottomRightRadius; 21 | 22 | 23 | /** 24 | * Border colors (actually retained). 25 | */ 26 | @property (nonatomic, assign) CGColorRef borderTopColor; 27 | @property (nonatomic, assign) CGColorRef borderRightColor; 28 | @property (nonatomic, assign) CGColorRef borderBottomColor; 29 | @property (nonatomic, assign) CGColorRef borderLeftColor; 30 | @property (nonatomic, assign) CGColorRef borderColor; 31 | 32 | /** 33 | * Border widths. 34 | */ 35 | @property (nonatomic, assign) CGFloat borderTopWidth; 36 | @property (nonatomic, assign) CGFloat borderRightWidth; 37 | @property (nonatomic, assign) CGFloat borderBottomWidth; 38 | @property (nonatomic, assign) CGFloat borderLeftWidth; 39 | @property (nonatomic, assign) CGFloat borderWidth; 40 | 41 | 42 | 43 | @property (nonatomic, strong) UIImage * image; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/CYCustomArcImageView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CYCustomArcImageView.m 3 | // ProjectComponentDemo 4 | // 5 | // Created by Mr.GCY on 2018/4/20. 6 | // Copyright © 2018年 Mr.GCY. All rights reserved. 7 | // 8 | 9 | #import "CYCustomArcImageView.h" 10 | #import "CYAnyCornerRadiusUtil.h" 11 | @interface CYCustomArcImageView() 12 | @property (nonatomic, assign) CornerRadii cornerRadii; 13 | @end 14 | @implementation CYCustomArcImageView 15 | -(instancetype)init{ 16 | if (self = [super init]) { 17 | [self setupUI]; 18 | } 19 | return self; 20 | } 21 | -(instancetype)initWithCoder:(NSCoder *)aDecoder{ 22 | if (self = [super initWithCoder:aDecoder]) { 23 | [self setupUI]; 24 | } 25 | return self; 26 | } 27 | -(instancetype)initWithFrame:(CGRect)frame{ 28 | if (self = [super initWithFrame:frame]) { 29 | [self setupUI]; 30 | } 31 | return self; 32 | } 33 | -(void)layoutSubviews{ 34 | 35 | } 36 | -(CGSize)sizeThatFits:(CGSize)size{ 37 | if (self.image) { 38 | return self.image.size; 39 | } 40 | return size; 41 | } 42 | #pragma mark- 初始化视图 43 | -(void)setupUI{ 44 | 45 | } 46 | #pragma mark- setter getter 47 | /** 48 | * Border radii. 49 | */ 50 | -(void)setBorderRadius:(CGFloat)borderRadius{ 51 | _borderRadius = borderRadius; 52 | self.borderBottomRightRadius = borderRadius; 53 | self.borderBottomLeftRadius = borderRadius; 54 | self.borderTopRightRadius = borderRadius; 55 | self.borderTopLeftRadius = borderRadius; 56 | } 57 | /** 58 | * Border colors (actually retained). 59 | */ 60 | -(void)setBorderColor:(CGColorRef)borderColor{ 61 | _borderColor = borderColor; 62 | self.borderTopColor = borderColor; 63 | self.borderRightColor = borderColor; 64 | self.borderBottomColor = borderColor; 65 | self.borderLeftColor = borderColor; 66 | } 67 | /** 68 | * Border widths. 69 | */ 70 | -(void)setBorderWidth:(CGFloat)borderWidth{ 71 | _borderWidth = borderWidth; 72 | self.borderTopWidth = borderWidth; 73 | self.borderRightWidth = borderWidth; 74 | self.borderBottomWidth = borderWidth; 75 | self.borderLeftWidth = borderWidth; 76 | } 77 | #pragma mark- 绘制方法 78 | - (void)drawRect:(CGRect)rect { 79 | //切圆角 80 | CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 81 | self.cornerRadii = CornerRadiiMake(self.borderTopLeftRadius, self.borderTopRightRadius, self.borderBottomLeftRadius, self.borderBottomRightRadius); 82 | CGPathRef path = CYPathCreateWithRoundedRect(self.bounds,self.cornerRadii); 83 | shapeLayer.path = path; 84 | CGPathRelease(path); 85 | self.layer.mask = shapeLayer; 86 | 87 | // 绘制图片 88 | if (self.image) { 89 | [self.image drawInRect:self.bounds];//在坐标中画出图片 90 | // CGContextDrawImage(context, self.bounds, self.image.CGImage); 会出现图片上下颠倒 91 | } 92 | 93 | //An opaque type that represents a Quartz 2D drawing environment. 94 | //一个不透明类型的Quartz 2D绘画环境,相当于一个画布,你可以在上面任意绘画 95 | CGContextRef context = UIGraphicsGetCurrentContext(); 96 | //画线 97 | [self drawGradientLineWithContent:context]; 98 | //内侧线 99 | [self drawLineWithContent:context]; 100 | } 101 | -(void)drawLineWithContent:(CGContextRef)context{ 102 | //画线 103 | const CGFloat minX = CGRectGetMinX(self.bounds); 104 | const CGFloat minY = CGRectGetMinY(self.bounds); 105 | const CGFloat maxX = CGRectGetMaxX(self.bounds); 106 | const CGFloat maxY = CGRectGetMaxY(self.bounds); 107 | 108 | 109 | 110 | const CGFloat topLeftCenterX = minX + self.borderTopLeftRadius; 111 | const CGFloat topLeftCenterY = minY + self.borderTopLeftRadius; 112 | 113 | const CGFloat topRightCenterX = maxX - self.borderTopRightRadius; 114 | const CGFloat topRightCenterY = minY + self.borderTopRightRadius; 115 | 116 | const CGFloat bottomLeftCenterX = minX + self.borderBottomLeftRadius; 117 | const CGFloat bottomLeftCenterY = maxY - self.borderBottomLeftRadius; 118 | 119 | const CGFloat bottomRightCenterX = maxX - self.borderBottomRightRadius; 120 | const CGFloat bottomRightCenterY = maxY - self.borderBottomRightRadius; 121 | 122 | CGFloat lineW = 5; 123 | CGFloat topSpaceY = (self.borderTopWidth + lineW)/2; 124 | CGFloat rightSpaceX = (self.borderRightWidth + lineW)/2; 125 | CGFloat bottomSpaceY = (self.borderBottomWidth + lineW)/2; 126 | CGFloat leftSpaceX = (self.borderLeftWidth + lineW)/2; 127 | 128 | self.borderTopLeftRadius -= topSpaceY; 129 | self.borderTopRightRadius -= rightSpaceX; 130 | self.borderBottomLeftRadius -= bottomSpaceY; 131 | self.borderBottomRightRadius -= leftSpaceX; 132 | 133 | 134 | //黄色 135 | UIColor * color = [UIColor colorWithRed:234/255.0 green:254/255.0 blue:254/255.0 alpha:1.0]; 136 | //1.0 顶左 画圆弧 137 | drawLineArc(context, color.CGColor, lineW, CGPointMake(topLeftCenterX, topLeftCenterY), self.borderTopLeftRadius, M_PI, 3 * M_PI_2, NO); 138 | //2.0 顶部划线 139 | drawLine(context, color.CGColor, lineW, CGPointMake(topLeftCenterX, topSpaceY), CGPointMake(topRightCenterX, topSpaceY)); 140 | //3.0 顶右 画圆弧 141 | drawLineArc(context, color.CGColor, lineW, CGPointMake(topRightCenterX, topRightCenterY), self.borderTopRightRadius, 3 * M_PI_2, 0, NO); 142 | //4.0 右部划线 143 | drawLine(context, color.CGColor, lineW, CGPointMake(maxX - rightSpaceX, topRightCenterY), CGPointMake(maxX - rightSpaceX, bottomRightCenterY)); 144 | //5.0 底右 画圆弧 145 | drawLineArc(context, color.CGColor, lineW, CGPointMake(bottomRightCenterX, bottomRightCenterY), self.borderBottomRightRadius, 0, M_PI_2, NO); 146 | //6.0 底部划线 147 | drawLine(context, color.CGColor, lineW, CGPointMake(bottomRightCenterX, maxY - bottomSpaceY), CGPointMake(bottomLeftCenterX, maxY - bottomSpaceY)); 148 | 149 | //7.0 底左 画圆弧 150 | drawLineArc(context, color.CGColor, lineW, CGPointMake(bottomLeftCenterX, bottomLeftCenterY), self.borderBottomLeftRadius, M_PI_2, M_PI, NO); 151 | 152 | //8.0 左边划线 153 | drawLine(context, color.CGColor, lineW, CGPointMake(minX + leftSpaceX, bottomLeftCenterY), CGPointMake(minX + leftSpaceX, topLeftCenterY)); 154 | 155 | } 156 | 157 | //画渐变线 158 | -(void)drawGradientLineWithContent:(CGContextRef)context{ 159 | 160 | 161 | //画线 162 | const CGFloat minX = CGRectGetMinX(self.bounds); 163 | const CGFloat minY = CGRectGetMinY(self.bounds); 164 | const CGFloat maxX = CGRectGetMaxX(self.bounds); 165 | const CGFloat maxY = CGRectGetMaxY(self.bounds); 166 | 167 | const CGFloat topLeftCenterX = minX + self.borderTopLeftRadius; 168 | const CGFloat topLeftCenterY = minY + self.borderTopLeftRadius; 169 | 170 | const CGFloat topRightCenterX = maxX - self.borderTopRightRadius; 171 | const CGFloat topRightCenterY = minY + self.borderTopRightRadius; 172 | 173 | const CGFloat bottomLeftCenterX = minX + self.borderBottomLeftRadius; 174 | const CGFloat bottomLeftCenterY = maxY - self.borderBottomLeftRadius; 175 | 176 | const CGFloat bottomRightCenterX = maxX - self.borderBottomRightRadius; 177 | const CGFloat bottomRightCenterY = maxY - self.borderBottomRightRadius; 178 | 179 | //渐变色数组 180 | CGFloat colors[] = 181 | { 182 | 245/255.0,213/255.0,79/255.0, 1.00, 183 | 231/255.0,108/255.0,0, 1.00, 184 | }; 185 | //黄色 186 | UIColor * color = [UIColor colorWithRed:245/255.0 green:213/255.0 blue:79/255.0 alpha:1.0]; 187 | //1.0 顶左 画圆弧 188 | drawLineArc(context, color.CGColor, self.borderTopWidth, CGPointMake(topLeftCenterX, topLeftCenterY), self.borderTopLeftRadius, M_PI, 3 * M_PI_2, NO); 189 | //2.0 顶部划线 190 | drawLine(context, color.CGColor, self.borderTopWidth, CGPointMake(topLeftCenterX, 0), CGPointMake(topRightCenterX, 0)); 191 | //3.0 顶右 画圆弧 192 | drawLineArc(context, color.CGColor, self.borderRightWidth, CGPointMake(topRightCenterX, topRightCenterY), self.borderTopRightRadius, 3 * M_PI_2, 0, NO); 193 | //4.0 右部划线 194 | drawLinearGradient(context, colors,sizeof(colors)/(sizeof(colors[0])), self.borderRightWidth ,CGPointMake(maxX, topRightCenterY), CGPointMake(maxX, bottomRightCenterY),kCGGradientDrawsAfterEndLocation); 195 | 196 | color = [UIColor colorWithRed:231/255.0 green:108/255.0 blue:0 alpha:1.0]; 197 | //5.0 底右 画圆弧 198 | drawLineArc(context, color.CGColor, self.borderBottomWidth, CGPointMake(bottomRightCenterX, bottomRightCenterY), self.borderBottomRightRadius, 0, M_PI_2, NO); 199 | //6.0 底部划线 200 | drawLine(context, color.CGColor, self.borderBottomWidth, CGPointMake(bottomRightCenterX, maxY), CGPointMake(bottomLeftCenterX, maxY)); 201 | 202 | //7.0 底左 画圆弧 203 | drawLineArc(context, color.CGColor, self.borderLeftWidth, CGPointMake(bottomLeftCenterX, bottomLeftCenterY), self.borderBottomLeftRadius, M_PI_2, M_PI, NO); 204 | 205 | //8.0 左边划线 206 | CGFloat colors1[] = { 207 | 231/255.0,108/255.0,0, 1.00, 208 | 245/255.0,213/255.0,79/255.0, 1.00, 209 | }; 210 | drawLinearGradient(context, colors1,sizeof(colors1)/(sizeof(colors1[0])),self.borderLeftWidth,CGPointMake(minX, bottomLeftCenterY), CGPointMake(minX, topLeftCenterY),kCGGradientDrawsAfterEndLocation); 211 | 212 | } 213 | @end 214 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/Util/CYAnyCornerRadiusUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // CYAnyCornerRadiusUtil.h 3 | // ProjectComponentDemo 4 | // 5 | // Created by Mr.GCY on 2018/4/23. 6 | // Copyright © 2018年 Mr.GCY. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef struct { 13 | CGFloat topLeft; 14 | CGFloat topRight; 15 | CGFloat bottomLeft; 16 | CGFloat bottomRight; 17 | } CornerRadii; 18 | @interface CYAnyCornerRadiusUtil : NSObject 19 | CornerRadii CornerRadiiMake(CGFloat topLeft,CGFloat topRight,CGFloat bottomLeft,CGFloat bottomRight); 20 | //切圆角函数 21 | CGPathRef CYPathCreateWithRoundedRect(CGRect bounds, 22 | CornerRadii cornerRadii); 23 | /** 24 | 画渐变线 25 | 26 | @param context 上下文 27 | @param components 渐变颜色数组 28 | @param componentCount 数组大小 29 | @param width 线宽 30 | @param startPoint 起始位置 31 | @param endPoint 结束位置 32 | */ 33 | void drawLinearGradient(CGContextRef cg_nullable context,const CGFloat * cg_nullable components,int componentCount,CGFloat width,CGPoint startPoint,CGPoint endPoint,CGGradientDrawingOptions options); 34 | /** 35 | 画线 36 | 37 | @param context 上下文 38 | @param color 线颜色 39 | @param width 线宽 40 | @param startPoint 起始位置 41 | @param endPoint 结束位置 42 | */ 43 | void drawLine(CGContextRef cg_nullable context,CGColorRef color,CGFloat width,CGPoint startPoint,CGPoint endPoint); 44 | 45 | /** 46 | 画弧线 47 | 48 | @param context 上下文 49 | @param color 线颜色 50 | @param width 线宽 51 | @param centerPoint 圆心位置 52 | @param radius 半径 53 | @param startAngle 起始角度 54 | @param endAngle 结束角度 55 | @param clockwise 是否闭合 56 | */ 57 | void drawLineArc(CGContextRef cg_nullable context,CGColorRef color,CGFloat width,CGPoint centerPoint,CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise); 58 | @end 59 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/Util/CYAnyCornerRadiusUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // CYAnyCornerRadiusUtil.m 3 | // ProjectComponentDemo 4 | // 5 | // Created by Mr.GCY on 2018/4/23. 6 | // Copyright © 2018年 Mr.GCY. All rights reserved. 7 | // 8 | 9 | #import "CYAnyCornerRadiusUtil.h" 10 | 11 | @implementation CYAnyCornerRadiusUtil 12 | CornerRadii CornerRadiiMake(CGFloat topLeft,CGFloat topRight,CGFloat bottomLeft,CGFloat bottomRight){ 13 | return (CornerRadii){ 14 | topLeft, 15 | topRight, 16 | bottomLeft, 17 | bottomRight, 18 | }; 19 | } 20 | //切圆角函数 21 | CGPathRef CYPathCreateWithRoundedRect(CGRect bounds, 22 | CornerRadii cornerRadii) 23 | { 24 | const CGFloat minX = CGRectGetMinX(bounds); 25 | const CGFloat minY = CGRectGetMinY(bounds); 26 | const CGFloat maxX = CGRectGetMaxX(bounds); 27 | const CGFloat maxY = CGRectGetMaxY(bounds); 28 | 29 | const CGFloat topLeftCenterX = minX + cornerRadii.topLeft; 30 | const CGFloat topLeftCenterY = minY + cornerRadii.topLeft; 31 | 32 | const CGFloat topRightCenterX = maxX - cornerRadii.topRight; 33 | const CGFloat topRightCenterY = minY + cornerRadii.topRight; 34 | 35 | const CGFloat bottomLeftCenterX = minX + cornerRadii.bottomLeft; 36 | const CGFloat bottomLeftCenterY = maxY - cornerRadii.bottomLeft; 37 | 38 | const CGFloat bottomRightCenterX = maxX - cornerRadii.bottomRight; 39 | const CGFloat bottomRightCenterY = maxY - cornerRadii.bottomRight; 40 | /* 41 | path : 路径 42 | m : 变换 43 | x y : 画圆的圆心点 44 | radius : 圆的半径 45 | startAngle : 起始角度 46 | endAngle : 结束角度 47 | clockwise : 是否是顺时针 48 | void CGPathAddArc(CGMutablePathRef cg_nullable path, 49 | const CGAffineTransform * __nullable m, 50 | CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, 51 | bool clockwise) 52 | */ 53 | //虽然顺时针参数是YES,在iOS中的UIView中,这里实际是逆时针 54 | 55 | CGMutablePathRef path = CGPathCreateMutable(); 56 | //顶 左 57 | CGPathAddArc(path, NULL, topLeftCenterX, topLeftCenterY,cornerRadii.topLeft, M_PI, 3 * M_PI_2, NO); 58 | //顶 右 59 | CGPathAddArc(path, NULL, topRightCenterX , topRightCenterY, cornerRadii.topRight, 3 * M_PI_2, 0, NO); 60 | //底 右 61 | CGPathAddArc(path, NULL, bottomRightCenterX, bottomRightCenterY, cornerRadii.bottomRight,0, M_PI_2, NO); 62 | //底 左 63 | CGPathAddArc(path, NULL, bottomLeftCenterX, bottomLeftCenterY, cornerRadii.bottomLeft, M_PI_2,M_PI, NO); 64 | CGPathCloseSubpath(path); 65 | return path; 66 | } 67 | //画渐变线 68 | void drawLinearGradient(CGContextRef cg_nullable context,const CGFloat * cg_nullable components,int componentCount,CGFloat width,CGPoint startPoint,CGPoint endPoint,CGGradientDrawingOptions options){ 69 | CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB(); 70 | CGFloat colors[componentCount]; 71 | for (int i = 0; i < componentCount; i++) { 72 | colors[i] = components[i]; 73 | } 74 | CGGradientRef gradient = CGGradientCreateWithColorComponents 75 | (rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));//形成梯形,渐变的效果 76 | CGColorSpaceRelease(rgb); 77 | CGContextSaveGState(context); 78 | 79 | CGContextMoveToPoint(context, startPoint.x, startPoint.y); 80 | CGContextAddLineToPoint(context, endPoint.x, endPoint.y); 81 | CGContextSetLineWidth(context, width); 82 | CGContextReplacePathWithStrokedPath(context); 83 | CGContextClip(context); 84 | 85 | //gradient渐变颜色,startPoint开始渐变的起始位置,endPoint结束坐标,options开始坐标之前or开始之后开始渐变 86 | CGContextDrawLinearGradient(context, gradient,startPoint ,endPoint,options); 87 | CGContextRestoreGState(context);// 恢复到之前的context 88 | 89 | CGGradientRelease(gradient); 90 | } 91 | //画线 92 | void drawLine(CGContextRef cg_nullable context,CGColorRef color,CGFloat width,CGPoint startPoint,CGPoint endPoint){ 93 | CGContextMoveToPoint(context, startPoint.x , startPoint.y); 94 | CGContextAddLineToPoint(context, endPoint.x,endPoint.y); 95 | CGContextSetLineWidth(context, width); 96 | CGContextSetStrokeColorWithColor(context, color); 97 | CGContextDrawPath(context, kCGPathStroke); 98 | } 99 | //画弧线 100 | void drawLineArc(CGContextRef cg_nullable context,CGColorRef color,CGFloat width,CGPoint centerPoint,CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise){ 101 | CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, startAngle, endAngle, clockwise); 102 | //划线宽度 103 | CGContextSetLineWidth(context, width); 104 | //划线颜色 105 | CGContextSetStrokeColorWithColor(context, color); 106 | CGContextDrawPath(context, kCGPathStroke); 107 | } 108 | @end 109 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // AnyCornerRadius 4 | // 5 | // Created by Mr.GCY on 2018/4/23. 6 | // Copyright © 2018年 Mr.GCY. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // AnyCornerRadius 4 | // 5 | // Created by Mr.GCY on 2018/4/23. 6 | // Copyright © 2018年 Mr.GCY. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "CYCustomArcImageView.h" 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | CYCustomArcImageView * imageView = [[CYCustomArcImageView alloc] initWithFrame:CGRectMake(0, 0, 250, 400)]; 20 | imageView.center = self.view.center; 21 | imageView.borderTopLeftRadius = 50; 22 | imageView.borderTopRightRadius = 20; 23 | imageView.borderBottomLeftRadius = 20; 24 | imageView.borderBottomRightRadius = 35; 25 | imageView.borderWidth = 3; 26 | imageView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"timg" ofType:@"jpeg"]]; 27 | 28 | [self.view addSubview:imageView]; 29 | } 30 | @end 31 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AnyCornerRadius 4 | // 5 | // Created by Mr.GCY on 2018/4/23. 6 | // Copyright © 2018年 Mr.GCY. 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 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadius/timg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrGCY/AnyCornerRadius/0f3b9519fff0f9399432b54efc8c734396dd68d6/AnyCornerRadius/AnyCornerRadius/timg.jpeg -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadiusTests/AnyCornerRadiusTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // AnyCornerRadiusTests.m 3 | // AnyCornerRadiusTests 4 | // 5 | // Created by Mr.GCY on 2018/4/23. 6 | // Copyright © 2018年 Mr.GCY. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AnyCornerRadiusTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation AnyCornerRadiusTests 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 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadiusTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadiusUITests/AnyCornerRadiusUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // AnyCornerRadiusUITests.m 3 | // AnyCornerRadiusUITests 4 | // 5 | // Created by Mr.GCY on 2018/4/23. 6 | // Copyright © 2018年 Mr.GCY. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AnyCornerRadiusUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation AnyCornerRadiusUITests 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 | -------------------------------------------------------------------------------- /AnyCornerRadius/AnyCornerRadiusUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mr.GCY 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AnyCornerRadius 2 | iOS中对任意视图切圆角 ,可以切任意一个角任意大小 3 | 4 | 5 | 最近要做一个新项目,产品需求刚过完,UI的效果图也就随之而出了,拿到效果图之后,看到首页就让我大吃一惊了,因为里面出现好多不同大小和个数的圆角,这让我着实头疼,大家可以看看UI效果图。 6 | ![首页.png](https://upload-images.jianshu.io/upload_images/2517741-eae4775b66c8b8e2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 7 | 可以看到页面确实很炫,但是实现也比较费劲。 8 | 9 | ###之前圆角方案 10 | ######1.使用layer的cornerRadius属性进行设置 11 | ``` 12 | self.view.layer.cornerRadius = 5.f; 13 | self.view.layer.masksToBounds = YES; 14 | ```` 15 | 16 | ######缺点: 17 | 1).当图片数量比较多的时候,这种添加圆角方式特别消耗性能,比如在UITableViewCell 18 | 添加过多圆角的话,甚至会带来视觉可见的卡顿. 19 | 2).无法配置圆角数量(只能添加view的四个角全为圆角),无法配置某个圆角大小. 20 | 第一个问题实际上是由于数量太多的情况下,系统会频繁的调用GPU的离屏渲染(Offscreen Rendering)机制,导致内存损耗严重. 21 | ######解决: 22 | 第一个问题: 采取预先生成圆角图片,并缓存起来这个方法才是比较好的手段。预处理圆角图片可以在后台处理,处理完毕后缓存起来,再在主线程显示,这就避免了不必要的离屏渲染了,更多关于离屏渲染的详解,大家可以看[这里](https://link.jianshu.com?t=http://objccn.io/issue-3-1/),本文不多赘述. 23 | 24 | ``` 25 | self.view.layer.cornerRadius = 5.f; 26 | self.view.layer.masksToBounds = YES; // 裁剪 27 | self.view.layer.shouldRasterize = YES; // 缓存 28 | self.view.layer.rasterizationScale = [UIScreen mainScreen].scale; 29 | ``` 30 | 当shouldRasterize设成true时,layer被渲染成一个bitmap,并缓存起来,等下次使用时不会再重新去渲染了。实现圆角本 身就是在做颜色混合(blending),如果每次页面出来时都blending,消耗太大,这时shouldRasterize = yes,下次就只是简单的从渲染引擎的cache里读取那张bitmap,节约[系统](https://link.jianshu.com?t=http://www.2cto.com/os/)资源。 31 | ######2.使用UIBezierPath进行切圆角 32 | 这种方案可以完美的解决方案一中第二个问题不能实现配置任意圆角数量。 33 | 实现过程 34 | 35 | ``` 36 | UIView * view = [[UIView alloc] initWithFrame:CGRectMake(0, 100, 100, 50)]; 37 | view.backgroundColor = [UIColor redColor]; 38 | UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomLeft cornerRadii:CGSizeMake(25, 0)]; 39 | CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; 40 | maskLayer.frame = view.bounds; 41 | maskLayer.path = maskPath.CGPath; 42 | view.layer.mask = maskLayer; 43 | [self.view addSubview:view]; 44 | ``` 45 | 其中想配置不同数量圆角可以设置UIRectCorner枚举属性进行配置。 46 | ``` 47 | UIRectCornerTopLeft = 1 << 0,//顶左 48 | UIRectCornerTopRight = 1 << 1,//顶右 49 | UIRectCornerBottomLeft = 1 << 2,//底左 50 | UIRectCornerBottomRight = 1 << 3,//底右 51 | UIRectCornerAllCorners = ~0UL//所有 52 | ``` 53 | ######缺点: 54 | 1. 通过UIBezierPath虽然解决了配置不同数量圆角,但是还是没有能解决配置不同大小的圆角 55 | ######解决: 56 | 下面就到了主角亮相的时刻了。 57 | ######插曲 58 | 与第二种方案很类似的一个是在iOS11.0之后对于圆角出来了一个新特性 59 | ``` 60 | @property CACornerMask maskedCorners 61 | CA_AVAILABLE_STARTING (10.13, 11.0, 11.0, 4.0); 62 | ``` 63 | 就是在layer新增了一个maskedCorners属性,其中CACornerMask是一个结构体 64 | ``` 65 | typedef NS_OPTIONS (NSUInteger, CACornerMask) 66 | { 67 | kCALayerMinXMinYCorner = 1U << 0, 68 | kCALayerMaxXMinYCorner = 1U << 1, 69 | kCALayerMinXMaxYCorner = 1U << 2, 70 | kCALayerMaxXMaxYCorner = 1U << 3, 71 | }; 72 | ``` 73 | 这个属性用于设置不同位置的圆角 74 | ``` 75 | UIView * view = [[UIView alloc] initWithFrame:CGRectMake(0, 100, 100, 50)]; 76 | view.backgroundColor = [UIColor redColor]; 77 | if (@available(iOS 11.0, *)) { 78 | view.layer.maskedCorners = kCALayerMaxXMaxYCorner |kCALayerMaxXMinYCorner; 79 | } else { 80 | // Fallback on earlier versions 81 | } 82 | view.layer.cornerRadius = 25.f; 83 | view.layer.masksToBounds = YES; 84 | [self.view addSubview:view]; 85 | ``` 86 | 但是他跟方案二有相同的缺点 87 | ###问题解决思路 88 | 看到效果图之后,我首先想到了第二种方案,在模糊的记忆中首先想到它可以配置 不同数量的圆角,然后就是想看看它能不能同时实现配置不同大小的圆角,找了很久也看了layer的一些属性没有找到,相关属性,网上也找了很多文章(可能没有找对关键字)也没有找到,很多都是方案一方案二的方法,没有具体解决不同大小的圆角方案,后面我一度以为iOS中不能实现(可能我太菜了),在我陷入迷茫的时候,我的同事突然提醒了我,说reactnative 中可以实现配置任意数量圆角并同时配置不同大小的方式(到这块可能了解RN工作原理的人已经大概知道该怎么去做了,RN的项目其实最终展示的控件还是原生控件,他们内部通过js来实现原生交互,将RN代码创建的控件转化成原生的控件,在RN中的任何组件,在原生都可以找到对应的原生组件,既然RN可以实现,那代表着原生也能实现),我之前也用过RN,写代码很快(用熟了之后)很方便,像效果图中的那个效果,很快就能实现。 89 | ######1.于是我赶紧找RN的原生代码 90 | ![1.png](https://upload-images.jianshu.io/upload_images/2517741-edc7671c877713fc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 91 | 这个主要是RN的在原生中的代码库,我们最主要的是看红框中的内容 92 | ![2.png](https://upload-images.jianshu.io/upload_images/2517741-dfdc094d60ab7c3b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 93 | 因为主要是view及它的子类有这种属性,所有我们只需要在view对应的那个文件中找就可以 94 | ``` 95 | - (void)updateClippingForLayer:(CALayer *)layer 96 | { 97 | CALayer *mask = nil; 98 | CGFloat cornerRadius = 0; 99 | 100 | if (self.clipsToBounds) { 101 | 102 | const RCTCornerRadii cornerRadii = [self cornerRadii]; 103 | if (RCTCornerRadiiAreEqual(cornerRadii)) { 104 | 105 | cornerRadius = cornerRadii.topLeft; 106 | 107 | } else { 108 | //切圆角的代码 109 | CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 110 | CGPathRef path = RCTPathCreateWithRoundedRect(self.bounds, RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero), NULL); 111 | shapeLayer.path = path; 112 | CGPathRelease(path); 113 | mask = shapeLayer; 114 | } 115 | } 116 | 117 | layer.cornerRadius = cornerRadius; 118 | layer.mask = mask; 119 | } 120 | ``` 121 | 这是它里面的一段代码,主要的切圆角方式再标注的地方,不难看出还是用了类似方案二中添加路径的方式去切圆角只是和UIBezierPath不一样,点击RCTPathCreateWithRoundedRect这个方法,我们就可以看到具体切圆角的过程了。 122 | ``` 123 | CGPathRef RCTPathCreateWithRoundedRect(CGRect bounds, 124 | RCTCornerInsets cornerInsets, 125 | const CGAffineTransform *transform) 126 | { 127 | const CGFloat minX = CGRectGetMinX(bounds); 128 | const CGFloat minY = CGRectGetMinY(bounds); 129 | const CGFloat maxX = CGRectGetMaxX(bounds); 130 | const CGFloat maxY = CGRectGetMaxY(bounds); 131 | 132 | const CGSize topLeft = { 133 | MAX(0, MIN(cornerInsets.topLeft.width, bounds.size.width - cornerInsets.topRight.width)), 134 | MAX(0, MIN(cornerInsets.topLeft.height, bounds.size.height - cornerInsets.bottomLeft.height)), 135 | }; 136 | const CGSize topRight = { 137 | MAX(0, MIN(cornerInsets.topRight.width, bounds.size.width - cornerInsets.topLeft.width)), 138 | MAX(0, MIN(cornerInsets.topRight.height, bounds.size.height - cornerInsets.bottomRight.height)), 139 | }; 140 | const CGSize bottomLeft = { 141 | MAX(0, MIN(cornerInsets.bottomLeft.width, bounds.size.width - cornerInsets.bottomRight.width)), 142 | MAX(0, MIN(cornerInsets.bottomLeft.height, bounds.size.height - cornerInsets.topLeft.height)), 143 | }; 144 | const CGSize bottomRight = { 145 | MAX(0, MIN(cornerInsets.bottomRight.width, bounds.size.width - cornerInsets.bottomLeft.width)), 146 | MAX(0, MIN(cornerInsets.bottomRight.height, bounds.size.height - cornerInsets.topRight.height)), 147 | }; 148 | 149 | CGMutablePathRef path = CGPathCreateMutable(); 150 | RCTPathAddEllipticArc(path, transform, (CGPoint){ 151 | minX + topLeft.width, minY + topLeft.height 152 | }, topLeft, M_PI, 3 * M_PI_2, NO); 153 | RCTPathAddEllipticArc(path, transform, (CGPoint){ 154 | maxX - topRight.width, minY + topRight.height 155 | }, topRight, 3 * M_PI_2, 0, NO); 156 | RCTPathAddEllipticArc(path, transform, (CGPoint){ 157 | maxX - bottomRight.width, maxY - bottomRight.height 158 | }, bottomRight, 0, M_PI_2, NO); 159 | RCTPathAddEllipticArc(path, transform, (CGPoint){ 160 | minX + bottomLeft.width, maxY - bottomLeft.height 161 | }, bottomLeft, M_PI_2, M_PI, NO); 162 | CGPathCloseSubpath(path); 163 | return path; 164 | } 165 | static void RCTPathAddEllipticArc(CGMutablePathRef path, 166 | const CGAffineTransform *m, 167 | CGPoint origin, 168 | CGSize size, 169 | CGFloat startAngle, 170 | CGFloat endAngle, 171 | BOOL clockwise) 172 | { 173 | CGFloat xScale = 1, yScale = 1, radius = 0; 174 | if (size.width != 0) { 175 | xScale = 1; 176 | yScale = size.height / size.width; 177 | radius = size.width; 178 | } else if (size.height != 0) { 179 | xScale = size.width / size.height; 180 | yScale = 1; 181 | radius = size.height; 182 | } 183 | 184 | CGAffineTransform t = CGAffineTransformMakeTranslation(origin.x, origin.y); 185 | t = CGAffineTransformScale(t, xScale, yScale); 186 | if (m != NULL) { 187 | t = CGAffineTransformConcat(t, *m); 188 | } 189 | 190 | CGPathAddArc(path, &t, 0, 0, radius, startAngle, endAngle, clockwise); 191 | } 192 | ``` 193 | 上面就是RN中视图切圆角的具体代码,主要执行过程大家可以自己看源码 194 | 主要文件名和路径看下图: 195 | ![3.png](https://upload-images.jianshu.io/upload_images/2517741-392f6bfb39606132.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 196 | 主要是这两个文件,最主要的代码就是这句 197 | ``` 198 | /* Add an arc of a circle to `path', possibly preceded by a straight line 199 | segment. The arc is approximated by a sequence of Bézier curves. `(x, y)' 200 | is the center of the arc; `radius' is its radius; `startAngle' is the 201 | angle to the first endpoint of the arc; `endAngle' is the angle to the 202 | second endpoint of the arc; and `clockwise' is true if the arc is to be 203 | drawn clockwise, false otherwise. `startAngle' and `endAngle' are 204 | measured in radians. If `m' is non-NULL, then the constructed Bézier 205 | curves representing the arc will be transformed by `m' before they are 206 | added to `path'. 207 | 208 | Note that using values very near 2π can be problematic. For example, 209 | setting `startAngle' to 0, `endAngle' to 2π, and `clockwise' to true will 210 | draw nothing. (It's easy to see this by considering, instead of 0 and 2π, 211 | the values ε and 2π - ε, where ε is very small.) Due to round-off error, 212 | however, it's possible that passing the value `2 * M_PI' to approximate 213 | 2π will numerically equal to 2π + δ, for some small δ; this will cause a 214 | full circle to be drawn. 215 | 216 | If you want a full circle to be drawn clockwise, you should set 217 | `startAngle' to 2π, `endAngle' to 0, and `clockwise' to true. This avoids 218 | the instability problems discussed above. */ 219 | 220 | /* 221 | path : 路径 222 | m : 变换 223 | x y : 画圆的圆心点 224 | radius : 圆的半径 225 | startAngle : 起始角度 226 | endAngle : 结束角度 227 | clockwise : 是否是顺时针 228 | void CGPathAddArc(CGMutablePathRef cg_nullable path, 229 | const CGAffineTransform * __nullable m, 230 | CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, 231 | bool clockwise) 232 | */ 233 | CG_EXTERN void CGPathAddArc(CGMutablePathRef cg_nullable path, 234 | const CGAffineTransform * __nullable m, 235 | CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, 236 | bool clockwise) 237 | CG_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_2_0); 238 | ``` 239 | 注:再API中写到clockwise默认是YES,即是顺时针,但是再iOS中的UIView中,这实际是逆时针,所有有时候看代码中写的感觉有问题,但运行出来确实正确的,不知道为什么。 240 | 241 | ######2.开始参考RN的代码写自己圆角代码 242 | 通过了解和熟悉整个RN的代码实现过程,我就开始写这块的代码,具体代码如下: 243 | ``` 244 | CornerRadii CornerRadiiMake(CGFloat topLeft,CGFloat topRight,CGFloat bottomLeft,CGFloat bottomRight){ 245 | return (CornerRadii){ 246 | topLeft, 247 | topRight, 248 | bottomLeft, 249 | bottomRight, 250 | }; 251 | } 252 | //切圆角函数 253 | CGPathRef CYPathCreateWithRoundedRect(CGRect bounds, 254 | CornerRadii cornerRadii) 255 | { 256 | const CGFloat minX = CGRectGetMinX(bounds); 257 | const CGFloat minY = CGRectGetMinY(bounds); 258 | const CGFloat maxX = CGRectGetMaxX(bounds); 259 | const CGFloat maxY = CGRectGetMaxY(bounds); 260 | 261 | const CGFloat topLeftCenterX = minX + cornerRadii.topLeft; 262 | const CGFloat topLeftCenterY = minY + cornerRadii.topLeft; 263 | 264 | const CGFloat topRightCenterX = maxX - cornerRadii.topRight; 265 | const CGFloat topRightCenterY = minY + cornerRadii.topRight; 266 | 267 | const CGFloat bottomLeftCenterX = minX + cornerRadii.bottomLeft; 268 | const CGFloat bottomLeftCenterY = maxY - cornerRadii.bottomLeft; 269 | 270 | const CGFloat bottomRightCenterX = maxX - cornerRadii.bottomRight; 271 | const CGFloat bottomRightCenterY = maxY - cornerRadii.bottomRight; 272 | //虽然顺时针参数是YES,在iOS中的UIView中,这里实际是逆时针 273 | 274 | CGMutablePathRef path = CGPathCreateMutable(); 275 | //顶 左 276 | CGPathAddArc(path, NULL, topLeftCenterX, topLeftCenterY,cornerRadii.topLeft, M_PI, 3 * M_PI_2, NO); 277 | //顶 右 278 | CGPathAddArc(path, NULL, topRightCenterX , topRightCenterY, cornerRadii.topRight, 3 * M_PI_2, 0, NO); 279 | //底 右 280 | CGPathAddArc(path, NULL, bottomRightCenterX, bottomRightCenterY, cornerRadii.bottomRight,0, M_PI_2, NO); 281 | //底 左 282 | CGPathAddArc(path, NULL, bottomLeftCenterX, bottomLeftCenterY, cornerRadii.bottomLeft, M_PI_2,M_PI, NO); 283 | CGPathCloseSubpath(path); 284 | return path; 285 | } 286 | ``` 287 | 具体应用部分代码: 288 | ``` 289 | //切圆角 290 | CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 291 | self.cornerRadii = CornerRadiiMake(self.borderTopLeftRadius, self.borderTopRightRadius, self.borderBottomLeftRadius, self.borderBottomRightRadius); 292 | CGPathRef path = CYPathCreateWithRoundedRect(self.bounds,self.cornerRadii); 293 | shapeLayer.path = path; 294 | CGPathRelease(path); 295 | self.layer.mask = shapeLayer; 296 | ``` 297 | 最中解决了这个问题可以实现配置不同数量不同大小的圆角,对于性能这块,它采用的也是路径去处理,跟方案二很类似,所以大体差不多,具体的性能对比还没有详细比较过,后面我也实现了效果图中的效果 298 | ![4.png](https://upload-images.jianshu.io/upload_images/2517741-b0f6a1b41f49289b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 299 | 其中的颜色渐变边框我才用的是路径绘制渐变线的方式实现的,这块的代码比较多,写的比较繁琐(还不知道有什么简单的处理方式),如果有比较好的解决思路可以评论留言交流交流。 300 | 具体代码[这里](https://github.com/MrGCY/AnyCornerRadius),可以具体看看实现过程。 301 | ###总结 302 | 通过这次切不同大小圆角的问题,发现了之前自己真的是只做业务层,做最简单的东西,对于稍微深入一点的东西,一点都不知道,可能有些知道,但也仅仅限于这是个什么,但要用它做什么东西就不知道,上层的东西很方便很快捷但是局限性太大,要想做一些很炫很酷的效果还是得深入底层了解每个属性每个方法是什么?有什么用?主要使用在哪些方面?,这些概念的了解是最基本的,最最重要的还是我们怎么能把一个具体的事物转换成我们代码需要实现的抽象的事物,并且运用我们所知道的所有东西,用最好的方式将它转化成代码,这整个过程是最值得我们深究的,我们需要有思路,需要哪个地方该用什么怎么实现等等,我觉得这可能是我(也可能是和我有同感的程序员)认为最最重要的东西了 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | --------------------------------------------------------------------------------