├── .gitignore ├── .swift-version ├── DesignableButton ├── DesignableButton.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── fraser.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── fraser.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist └── DesignableButton │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-40@2x.png │ │ ├── Icon-40@3x.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-76.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-83.5@2x.png │ │ └── Logo-1024.png │ ├── Button.imageset │ │ ├── Button.png │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Color.swift │ ├── Colors.xcassets │ ├── Contents.json │ ├── Gray.colorset │ │ └── Contents.json │ ├── GrayDarker.colorset │ │ └── Contents.json │ ├── GrayLight.colorset │ │ └── Contents.json │ ├── GrayLightest.colorset │ │ └── Contents.json │ ├── GreyLighter.colorset │ │ └── Contents.json │ ├── Red.colorset │ │ └── Contents.json │ └── RedSelected.colorset │ │ └── Contents.json │ ├── DesignableButton+Styles.swift │ ├── Info.plist │ └── ViewController.swift ├── IHDesignableButton.podspec ├── LICENSE ├── Package.swift ├── README.md └── Sources └── DesignableButton.swift /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | DesignableButton/DesignableButton.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist 3 | DesignableButton/DesignableButton.xcodeproj/project.xcworkspace/xcuserdata/fraser.xcuserdatad/UserInterfaceState.xcuserstate 4 | DesignableButton/DesignableButton.xcodeproj/xcshareddata/xcschemes/DesignableButton.xcscheme 5 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4C0D43901F7B34600096F625 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0D438F1F7B34600096F625 /* AppDelegate.swift */; }; 11 | 4C0D43921F7B34600096F625 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0D43911F7B34600096F625 /* ViewController.swift */; }; 12 | 4C0D43951F7B34600096F625 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4C0D43931F7B34600096F625 /* Main.storyboard */; }; 13 | 4C0D43971F7B34600096F625 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C0D43961F7B34600096F625 /* Assets.xcassets */; }; 14 | 4C0D439A1F7B34600096F625 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4C0D43981F7B34600096F625 /* LaunchScreen.storyboard */; }; 15 | 4C0D43A41F7B35EB0096F625 /* DesignableButton+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0D43A31F7B35EB0096F625 /* DesignableButton+Styles.swift */; }; 16 | 4C0D43A61F7B361B0096F625 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0D43A51F7B361B0096F625 /* Color.swift */; }; 17 | 4C0D43A71F7B369C0096F625 /* DesignableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0D43A21F7B348B0096F625 /* DesignableButton.swift */; }; 18 | 4C65B79721A21BF300D05488 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 4C65B79621A21BF300D05488 /* README.md */; }; 19 | 4CE432F822540BE60086BE5A /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4CE432F722540BE60086BE5A /* Colors.xcassets */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 4C0D438C1F7B34600096F625 /* DesignableButton.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DesignableButton.app; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | 4C0D438F1F7B34600096F625 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 25 | 4C0D43911F7B34600096F625 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 26 | 4C0D43941F7B34600096F625 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 27 | 4C0D43961F7B34600096F625 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 28 | 4C0D43991F7B34600096F625 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 29 | 4C0D439B1F7B34600096F625 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | 4C0D43A21F7B348B0096F625 /* DesignableButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesignableButton.swift; sourceTree = ""; }; 31 | 4C0D43A31F7B35EB0096F625 /* DesignableButton+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DesignableButton+Styles.swift"; sourceTree = ""; }; 32 | 4C0D43A51F7B361B0096F625 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; 33 | 4C194A851F7B48C100210C36 /* IHDesignableButton.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; name = IHDesignableButton.podspec; path = ../../IHDesignableButton.podspec; sourceTree = ""; }; 34 | 4C65B79621A21BF300D05488 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../README.md; sourceTree = ""; }; 35 | 4CE432F722540BE60086BE5A /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; 36 | /* End PBXFileReference section */ 37 | 38 | /* Begin PBXFrameworksBuildPhase section */ 39 | 4C0D43891F7B34600096F625 /* Frameworks */ = { 40 | isa = PBXFrameworksBuildPhase; 41 | buildActionMask = 2147483647; 42 | files = ( 43 | ); 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | /* End PBXFrameworksBuildPhase section */ 47 | 48 | /* Begin PBXGroup section */ 49 | 4C0D43831F7B34600096F625 = { 50 | isa = PBXGroup; 51 | children = ( 52 | 4C0D438E1F7B34600096F625 /* DesignableButton */, 53 | 4C0D438D1F7B34600096F625 /* Products */, 54 | ); 55 | sourceTree = ""; 56 | }; 57 | 4C0D438D1F7B34600096F625 /* Products */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | 4C0D438C1F7B34600096F625 /* DesignableButton.app */, 61 | ); 62 | name = Products; 63 | sourceTree = ""; 64 | }; 65 | 4C0D438E1F7B34600096F625 /* DesignableButton */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 4C0D43A11F7B348B0096F625 /* Sources */, 69 | 4C0D438F1F7B34600096F625 /* AppDelegate.swift */, 70 | 4C0D43911F7B34600096F625 /* ViewController.swift */, 71 | 4C0D43A31F7B35EB0096F625 /* DesignableButton+Styles.swift */, 72 | 4C0D43A51F7B361B0096F625 /* Color.swift */, 73 | 4C0D43931F7B34600096F625 /* Main.storyboard */, 74 | 4C0D43961F7B34600096F625 /* Assets.xcassets */, 75 | 4CE432F722540BE60086BE5A /* Colors.xcassets */, 76 | 4C0D43981F7B34600096F625 /* LaunchScreen.storyboard */, 77 | 4C0D439B1F7B34600096F625 /* Info.plist */, 78 | 4C194A851F7B48C100210C36 /* IHDesignableButton.podspec */, 79 | 4C65B79621A21BF300D05488 /* README.md */, 80 | ); 81 | path = DesignableButton; 82 | sourceTree = ""; 83 | }; 84 | 4C0D43A11F7B348B0096F625 /* Sources */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 4C0D43A21F7B348B0096F625 /* DesignableButton.swift */, 88 | ); 89 | name = Sources; 90 | path = ../../Sources; 91 | sourceTree = ""; 92 | }; 93 | /* End PBXGroup section */ 94 | 95 | /* Begin PBXNativeTarget section */ 96 | 4C0D438B1F7B34600096F625 /* DesignableButton */ = { 97 | isa = PBXNativeTarget; 98 | buildConfigurationList = 4C0D439E1F7B34600096F625 /* Build configuration list for PBXNativeTarget "DesignableButton" */; 99 | buildPhases = ( 100 | 4C0D43881F7B34600096F625 /* Sources */, 101 | 4C0D43891F7B34600096F625 /* Frameworks */, 102 | 4C0D438A1F7B34600096F625 /* Resources */, 103 | ); 104 | buildRules = ( 105 | ); 106 | dependencies = ( 107 | ); 108 | name = DesignableButton; 109 | productName = DesignableButton; 110 | productReference = 4C0D438C1F7B34600096F625 /* DesignableButton.app */; 111 | productType = "com.apple.product-type.application"; 112 | }; 113 | /* End PBXNativeTarget section */ 114 | 115 | /* Begin PBXProject section */ 116 | 4C0D43841F7B34600096F625 /* Project object */ = { 117 | isa = PBXProject; 118 | attributes = { 119 | LastSwiftUpdateCheck = 0900; 120 | LastUpgradeCheck = 1010; 121 | ORGANIZATIONNAME = IdleHandsApps; 122 | TargetAttributes = { 123 | 4C0D438B1F7B34600096F625 = { 124 | CreatedOnToolsVersion = 9.0; 125 | LastSwiftMigration = 1020; 126 | ProvisioningStyle = Automatic; 127 | }; 128 | }; 129 | }; 130 | buildConfigurationList = 4C0D43871F7B34600096F625 /* Build configuration list for PBXProject "DesignableButton" */; 131 | compatibilityVersion = "Xcode 8.0"; 132 | developmentRegion = en; 133 | hasScannedForEncodings = 0; 134 | knownRegions = ( 135 | en, 136 | Base, 137 | ); 138 | mainGroup = 4C0D43831F7B34600096F625; 139 | productRefGroup = 4C0D438D1F7B34600096F625 /* Products */; 140 | projectDirPath = ""; 141 | projectRoot = ""; 142 | targets = ( 143 | 4C0D438B1F7B34600096F625 /* DesignableButton */, 144 | ); 145 | }; 146 | /* End PBXProject section */ 147 | 148 | /* Begin PBXResourcesBuildPhase section */ 149 | 4C0D438A1F7B34600096F625 /* Resources */ = { 150 | isa = PBXResourcesBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | 4CE432F822540BE60086BE5A /* Colors.xcassets in Resources */, 154 | 4C0D439A1F7B34600096F625 /* LaunchScreen.storyboard in Resources */, 155 | 4C0D43971F7B34600096F625 /* Assets.xcassets in Resources */, 156 | 4C65B79721A21BF300D05488 /* README.md in Resources */, 157 | 4C0D43951F7B34600096F625 /* Main.storyboard in Resources */, 158 | ); 159 | runOnlyForDeploymentPostprocessing = 0; 160 | }; 161 | /* End PBXResourcesBuildPhase section */ 162 | 163 | /* Begin PBXSourcesBuildPhase section */ 164 | 4C0D43881F7B34600096F625 /* Sources */ = { 165 | isa = PBXSourcesBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | 4C0D43A61F7B361B0096F625 /* Color.swift in Sources */, 169 | 4C0D43921F7B34600096F625 /* ViewController.swift in Sources */, 170 | 4C0D43A41F7B35EB0096F625 /* DesignableButton+Styles.swift in Sources */, 171 | 4C0D43A71F7B369C0096F625 /* DesignableButton.swift in Sources */, 172 | 4C0D43901F7B34600096F625 /* AppDelegate.swift in Sources */, 173 | ); 174 | runOnlyForDeploymentPostprocessing = 0; 175 | }; 176 | /* End PBXSourcesBuildPhase section */ 177 | 178 | /* Begin PBXVariantGroup section */ 179 | 4C0D43931F7B34600096F625 /* Main.storyboard */ = { 180 | isa = PBXVariantGroup; 181 | children = ( 182 | 4C0D43941F7B34600096F625 /* Base */, 183 | ); 184 | name = Main.storyboard; 185 | sourceTree = ""; 186 | }; 187 | 4C0D43981F7B34600096F625 /* LaunchScreen.storyboard */ = { 188 | isa = PBXVariantGroup; 189 | children = ( 190 | 4C0D43991F7B34600096F625 /* Base */, 191 | ); 192 | name = LaunchScreen.storyboard; 193 | sourceTree = ""; 194 | }; 195 | /* End PBXVariantGroup section */ 196 | 197 | /* Begin XCBuildConfiguration section */ 198 | 4C0D439C1F7B34600096F625 /* Debug */ = { 199 | isa = XCBuildConfiguration; 200 | buildSettings = { 201 | ALWAYS_SEARCH_USER_PATHS = NO; 202 | CLANG_ANALYZER_NONNULL = YES; 203 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 209 | CLANG_WARN_BOOL_CONVERSION = YES; 210 | CLANG_WARN_COMMA = YES; 211 | CLANG_WARN_CONSTANT_CONVERSION = YES; 212 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 213 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 214 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 215 | CLANG_WARN_EMPTY_BODY = YES; 216 | CLANG_WARN_ENUM_CONVERSION = YES; 217 | CLANG_WARN_INFINITE_RECURSION = YES; 218 | CLANG_WARN_INT_CONVERSION = YES; 219 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 220 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 221 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 222 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 223 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 224 | CLANG_WARN_STRICT_PROTOTYPES = YES; 225 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 226 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 227 | CLANG_WARN_UNREACHABLE_CODE = YES; 228 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 229 | CODE_SIGN_IDENTITY = "iPhone Developer"; 230 | COPY_PHASE_STRIP = NO; 231 | DEBUG_INFORMATION_FORMAT = dwarf; 232 | ENABLE_STRICT_OBJC_MSGSEND = YES; 233 | ENABLE_TESTABILITY = YES; 234 | GCC_C_LANGUAGE_STANDARD = gnu11; 235 | GCC_DYNAMIC_NO_PIC = NO; 236 | GCC_NO_COMMON_BLOCKS = YES; 237 | GCC_OPTIMIZATION_LEVEL = 0; 238 | GCC_PREPROCESSOR_DEFINITIONS = ( 239 | "DEBUG=1", 240 | "$(inherited)", 241 | ); 242 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 243 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 244 | GCC_WARN_UNDECLARED_SELECTOR = YES; 245 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 246 | GCC_WARN_UNUSED_FUNCTION = YES; 247 | GCC_WARN_UNUSED_VARIABLE = YES; 248 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 249 | MTL_ENABLE_DEBUG_INFO = YES; 250 | ONLY_ACTIVE_ARCH = YES; 251 | SDKROOT = iphoneos; 252 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 253 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 254 | SWIFT_VERSION = 4.0; 255 | }; 256 | name = Debug; 257 | }; 258 | 4C0D439D1F7B34600096F625 /* Release */ = { 259 | isa = XCBuildConfiguration; 260 | buildSettings = { 261 | ALWAYS_SEARCH_USER_PATHS = NO; 262 | CLANG_ANALYZER_NONNULL = YES; 263 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 264 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 265 | CLANG_CXX_LIBRARY = "libc++"; 266 | CLANG_ENABLE_MODULES = YES; 267 | CLANG_ENABLE_OBJC_ARC = YES; 268 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 269 | CLANG_WARN_BOOL_CONVERSION = YES; 270 | CLANG_WARN_COMMA = YES; 271 | CLANG_WARN_CONSTANT_CONVERSION = YES; 272 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 273 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 274 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 275 | CLANG_WARN_EMPTY_BODY = YES; 276 | CLANG_WARN_ENUM_CONVERSION = YES; 277 | CLANG_WARN_INFINITE_RECURSION = YES; 278 | CLANG_WARN_INT_CONVERSION = YES; 279 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 280 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 281 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 282 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 283 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 284 | CLANG_WARN_STRICT_PROTOTYPES = YES; 285 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 286 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 287 | CLANG_WARN_UNREACHABLE_CODE = YES; 288 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 289 | CODE_SIGN_IDENTITY = "iPhone Developer"; 290 | COPY_PHASE_STRIP = NO; 291 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 292 | ENABLE_NS_ASSERTIONS = NO; 293 | ENABLE_STRICT_OBJC_MSGSEND = YES; 294 | GCC_C_LANGUAGE_STANDARD = gnu11; 295 | GCC_NO_COMMON_BLOCKS = YES; 296 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 297 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 298 | GCC_WARN_UNDECLARED_SELECTOR = YES; 299 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 300 | GCC_WARN_UNUSED_FUNCTION = YES; 301 | GCC_WARN_UNUSED_VARIABLE = YES; 302 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 303 | MTL_ENABLE_DEBUG_INFO = NO; 304 | SDKROOT = iphoneos; 305 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 306 | SWIFT_VERSION = 4.0; 307 | VALIDATE_PRODUCT = YES; 308 | }; 309 | name = Release; 310 | }; 311 | 4C0D439F1F7B34600096F625 /* Debug */ = { 312 | isa = XCBuildConfiguration; 313 | buildSettings = { 314 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 315 | CODE_SIGN_STYLE = Automatic; 316 | DEVELOPMENT_TEAM = 2E23KCX8SU; 317 | INFOPLIST_FILE = DesignableButton/Info.plist; 318 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 319 | PRODUCT_BUNDLE_IDENTIFIER = com.DesignableButton; 320 | PRODUCT_NAME = "$(TARGET_NAME)"; 321 | SWIFT_VERSION = 5.0; 322 | TARGETED_DEVICE_FAMILY = "1,2"; 323 | }; 324 | name = Debug; 325 | }; 326 | 4C0D43A01F7B34600096F625 /* Release */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 330 | CODE_SIGN_STYLE = Automatic; 331 | DEVELOPMENT_TEAM = 2E23KCX8SU; 332 | INFOPLIST_FILE = DesignableButton/Info.plist; 333 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 334 | PRODUCT_BUNDLE_IDENTIFIER = com.DesignableButton; 335 | PRODUCT_NAME = "$(TARGET_NAME)"; 336 | SWIFT_VERSION = 5.0; 337 | TARGETED_DEVICE_FAMILY = "1,2"; 338 | }; 339 | name = Release; 340 | }; 341 | /* End XCBuildConfiguration section */ 342 | 343 | /* Begin XCConfigurationList section */ 344 | 4C0D43871F7B34600096F625 /* Build configuration list for PBXProject "DesignableButton" */ = { 345 | isa = XCConfigurationList; 346 | buildConfigurations = ( 347 | 4C0D439C1F7B34600096F625 /* Debug */, 348 | 4C0D439D1F7B34600096F625 /* Release */, 349 | ); 350 | defaultConfigurationIsVisible = 0; 351 | defaultConfigurationName = Release; 352 | }; 353 | 4C0D439E1F7B34600096F625 /* Build configuration list for PBXNativeTarget "DesignableButton" */ = { 354 | isa = XCConfigurationList; 355 | buildConfigurations = ( 356 | 4C0D439F1F7B34600096F625 /* Debug */, 357 | 4C0D43A01F7B34600096F625 /* Release */, 358 | ); 359 | defaultConfigurationIsVisible = 0; 360 | defaultConfigurationName = Release; 361 | }; 362 | /* End XCConfigurationList section */ 363 | }; 364 | rootObject = 4C0D43841F7B34600096F625 /* Project object */; 365 | } 366 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton.xcodeproj/project.xcworkspace/xcuserdata/fraser.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton.xcodeproj/project.xcworkspace/xcuserdata/fraser.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /DesignableButton/DesignableButton.xcodeproj/xcuserdata/fraser.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton.xcodeproj/xcuserdata/fraser.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DesignableButton.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | DesignableButton.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 4C0D438B1F7B34600096F625 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DesignableButton 4 | // 5 | // Created by Fraser on 27/09/17. 6 | // Copyright © 2017 IdleHandsApps. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | 20 | DesignableButton.setDesignableStyles() 21 | 22 | return true 23 | } 24 | 25 | func applicationWillResignActive(_ application: UIApplication) { 26 | // 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. 27 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 28 | } 29 | 30 | func applicationDidEnterBackground(_ application: UIApplication) { 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 | func applicationWillEnterForeground(_ application: UIApplication) { 36 | // 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. 37 | } 38 | 39 | func applicationDidBecomeActive(_ application: UIApplication) { 40 | // 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. 41 | } 42 | 43 | func applicationWillTerminate(_ application: UIApplication) { 44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 45 | } 46 | 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/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 | "size" : "40x40", 25 | "idiom" : "iphone", 26 | "filename" : "Icon-40@2x.png", 27 | "scale" : "2x" 28 | }, 29 | { 30 | "size" : "40x40", 31 | "idiom" : "iphone", 32 | "filename" : "Icon-40@3x.png", 33 | "scale" : "3x" 34 | }, 35 | { 36 | "size" : "60x60", 37 | "idiom" : "iphone", 38 | "filename" : "Icon-60@2x.png", 39 | "scale" : "2x" 40 | }, 41 | { 42 | "size" : "60x60", 43 | "idiom" : "iphone", 44 | "filename" : "Icon-60@3x.png", 45 | "scale" : "3x" 46 | }, 47 | { 48 | "idiom" : "ipad", 49 | "size" : "20x20", 50 | "scale" : "1x" 51 | }, 52 | { 53 | "idiom" : "ipad", 54 | "size" : "20x20", 55 | "scale" : "2x" 56 | }, 57 | { 58 | "idiom" : "ipad", 59 | "size" : "29x29", 60 | "scale" : "1x" 61 | }, 62 | { 63 | "idiom" : "ipad", 64 | "size" : "29x29", 65 | "scale" : "2x" 66 | }, 67 | { 68 | "idiom" : "ipad", 69 | "size" : "40x40", 70 | "scale" : "1x" 71 | }, 72 | { 73 | "idiom" : "ipad", 74 | "size" : "40x40", 75 | "scale" : "2x" 76 | }, 77 | { 78 | "size" : "76x76", 79 | "idiom" : "ipad", 80 | "filename" : "Icon-76.png", 81 | "scale" : "1x" 82 | }, 83 | { 84 | "size" : "76x76", 85 | "idiom" : "ipad", 86 | "filename" : "Icon-76@2x.png", 87 | "scale" : "2x" 88 | }, 89 | { 90 | "size" : "83.5x83.5", 91 | "idiom" : "ipad", 92 | "filename" : "Icon-83.5@2x.png", 93 | "scale" : "2x" 94 | }, 95 | { 96 | "size" : "1024x1024", 97 | "idiom" : "ios-marketing", 98 | "filename" : "Logo-1024.png", 99 | "scale" : "1x" 100 | } 101 | ], 102 | "info" : { 103 | "version" : 1, 104 | "author" : "xcode" 105 | } 106 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Logo-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton/Assets.xcassets/AppIcon.appiconset/Logo-1024.png -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/Button.imageset/Button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IdleHandsApps/DesignableButton/442b13470ff5c64262019d52f3c588fda9efb948/DesignableButton/DesignableButton/Assets.xcassets/Button.imageset/Button.png -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/Button.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "Button.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | }, 21 | "properties" : { 22 | "template-rendering-intent" : "template" 23 | } 24 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/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 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/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 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Color.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CrayonPalette.swift 3 | // Neighbourly 4 | // 5 | // Created by Fraser Scott-Morrison on 1/04/16. 6 | // Copyright © 2016 Neighbourly. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class Color: NSObject { 12 | 13 | class var red: UIColor { 14 | return UIColor(named: "Red") ?? UIColor.red 15 | } 16 | 17 | class var redSelected: UIColor { 18 | return UIColor(named: "RedSelected") ?? UIColor.black 19 | } 20 | 21 | class var grayLightest: UIColor { 22 | return UIColor(named: "GrayLightest") ?? UIColor.black 23 | } 24 | 25 | class var grayLighter: UIColor { 26 | return UIColor(named: "GrayLighter") ?? UIColor.black 27 | } 28 | 29 | class var grayLight: UIColor { 30 | return UIColor(named: "GrayLight") ?? UIColor.black 31 | } 32 | 33 | class var gray: UIColor { 34 | return UIColor(named: "Gray") ?? UIColor.black 35 | } 36 | 37 | class var grayDarker: UIColor { 38 | return UIColor(named: "GrayDarker") ?? UIColor.black 39 | } 40 | 41 | /*class func red() -> UIColor { 42 | return UIColor(red: 200/255.0, green: 29/255.0, blue: 34/255.0, alpha: 1.0) 43 | } 44 | 45 | class func redSelected() -> UIColor { 46 | return UIColor(red: 227/255.0, green: 141/255.0, blue: 145/255.0, alpha: 1.0) 47 | } 48 | 49 | class func grayLightest() -> UIColor { 50 | return UIColor(red: 240/255.0, green: 240/255.0, blue: 240/255.0, alpha: 1.0) //@gray-lightest #f0f0f0; xib equivalent 243 51 | } 52 | 53 | class func grayLighter() -> UIColor { 54 | return UIColor(red: 217/255.0, green: 217/255.0, blue: 217/255.0, alpha: 1.0) //@gray-lighter #d9d9d9; xib equivalent 224 55 | } 56 | 57 | class func grayLight() -> UIColor { 58 | return UIColor(red: 153/255.0, green: 153/255.0, blue: 153/255.0, alpha: 1.0) //@gray-light #999999; xib equivalent 169 59 | } 60 | 61 | class func gray() -> UIColor { 62 | return UIColor(red: 84/255.0, green: 84/255.0, blue: 84/255.0, alpha: 1.0) //@gray #545454; xib equivalent 103 63 | } 64 | 65 | class func grayDarker() -> UIColor { 66 | return UIColor(red: 50/255.0, green: 50/255.0, blue: 50/255.0, alpha: 1.0) //@gray-darker #323232; xib equivalent 65 67 | }*/ 68 | 69 | } 70 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Colors.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Colors.xcassets/Gray.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "84", 13 | "alpha" : "1.000", 14 | "blue" : "84", 15 | "green" : "84" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Colors.xcassets/GrayDarker.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "50", 13 | "alpha" : "1.000", 14 | "blue" : "50", 15 | "green" : "50" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Colors.xcassets/GrayLight.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "153", 13 | "alpha" : "1.000", 14 | "blue" : "153", 15 | "green" : "153" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Colors.xcassets/GrayLightest.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "240", 13 | "alpha" : "1.000", 14 | "blue" : "240", 15 | "green" : "240" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Colors.xcassets/GreyLighter.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "217", 13 | "alpha" : "1.000", 14 | "blue" : "217", 15 | "green" : "217" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Colors.xcassets/Red.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "200", 13 | "alpha" : "1.000", 14 | "blue" : "34", 15 | "green" : "29" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/Colors.xcassets/RedSelected.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "227", 13 | "alpha" : "1.000", 14 | "blue" : "145", 15 | "green" : "141" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/DesignableButton+Styles.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NeighbourlyButton.swift 3 | // IdleHandsApps 4 | // 5 | // Created by Fraser on 13/02/17. 6 | // Copyright © 2017 IdleHandsApps Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | //import IHDesignableButton 11 | 12 | extension DesignableButton { 13 | 14 | override open func prepareForInterfaceBuilder() { 15 | super.prepareForInterfaceBuilder() 16 | 17 | DesignableButton.setDesignableStyles(isInterfaceBuilder: true) 18 | } 19 | 20 | static func setDesignableStyles(isInterfaceBuilder: Bool = false) { 21 | 22 | DesignableButton.setStyle(style: { (designableButton: DesignableButton) -> Void in 23 | if designableButton.isHighlighted || designableButton.isSelected { 24 | designableButton.setTitleColor(designableButton.customTextColor ?? UIColor.white, for: UIControl.State()) 25 | designableButton.backgroundColor = designableButton.selectedColor ?? Color.redSelected 26 | designableButton.layer.borderColor = designableButton.selectedColor?.cgColor ?? Color.redSelected.cgColor 27 | designableButton.layer.borderWidth = designableButton.borderWidth ?? 0 28 | } else if designableButton.isEnabled { 29 | designableButton.setTitleColor(designableButton.customTextColor ?? UIColor.white, for: UIControl.State()) 30 | designableButton.backgroundColor = designableButton.defaultColor ?? Color.red 31 | designableButton.layer.borderColor = designableButton.defaultColor?.cgColor ?? Color.red.cgColor 32 | designableButton.layer.borderWidth = designableButton.borderWidth ?? 0 33 | } 34 | else { 35 | designableButton.setTitleColor(designableButton.customTextColor ?? Color.gray, for: UIControl.State()) 36 | designableButton.backgroundColor = designableButton.disabledColor ?? Color.grayLightest 37 | designableButton.layer.borderColor = designableButton.borderColor?.cgColor ?? Color.gray.cgColor 38 | designableButton.layer.borderWidth = designableButton.borderWidth ?? 1 39 | } 40 | designableButton.setTitle(designableButton.titleLabel?.text, for: .normal) 41 | 42 | designableButton.layer.cornerRadius = designableButton.cornerRadius ?? 12 43 | 44 | }, for: "primary") 45 | 46 | DesignableButton.setStyle(style: { (designableButton: DesignableButton) -> Void in 47 | if designableButton.isHighlighted || designableButton.isSelected { 48 | designableButton.setTitleColor(designableButton.customTextColor ?? UIColor.white, for: UIControl.State()) 49 | designableButton.backgroundColor = designableButton.selectedColor ?? Color.redSelected 50 | } else if designableButton.isEnabled { 51 | designableButton.setTitleColor(designableButton.customTextColor ?? Color.red, for: UIControl.State()) 52 | designableButton.backgroundColor = designableButton.defaultColor ?? UIColor.white 53 | } 54 | else { 55 | designableButton.setTitleColor(designableButton.customTextColor ?? Color.grayLight, for: UIControl.State()) 56 | designableButton.backgroundColor = designableButton.disabledColor ?? Color.grayLightest 57 | } 58 | designableButton.setTitle(designableButton.titleLabel?.text, for: .normal) 59 | 60 | designableButton.layer.cornerRadius = designableButton.cornerRadius ?? 12 61 | designableButton.layer.borderWidth = designableButton.borderWidth ?? 1 62 | designableButton.layer.borderColor = designableButton.borderColor != nil ? designableButton.borderColor!.cgColor : Color.red.cgColor 63 | }, for: "secondary") 64 | 65 | DesignableButton.setStyle(style: { (designableButton: DesignableButton) -> Void in 66 | if designableButton.isHighlighted { 67 | designableButton.setTitleColor(designableButton.customTextColor ?? Color.redSelected, for: UIControl.State()) 68 | designableButton.backgroundColor = designableButton.selectedColor ?? Color.red 69 | designableButton.tintColor = Color.redSelected 70 | } 71 | else if designableButton.isSelected { 72 | designableButton.setTitleColor(designableButton.customTextColor ?? Color.redSelected, for: UIControl.State()) 73 | designableButton.backgroundColor = designableButton.selectedColor ?? UIColor.clear 74 | designableButton.tintColor = Color.redSelected 75 | } else if designableButton.isEnabled { 76 | designableButton.setTitleColor(designableButton.customTextColor ?? Color.red, for: UIControl.State()) 77 | designableButton.backgroundColor = designableButton.defaultColor ?? UIColor.clear 78 | designableButton.tintColor = Color.red 79 | } 80 | else { 81 | designableButton.setTitleColor(designableButton.customTextColor ?? Color.grayLight, for: UIControl.State()) 82 | designableButton.backgroundColor = designableButton.disabledColor ?? UIColor.clear 83 | designableButton.tintColor = Color.grayLight 84 | } 85 | 86 | if isInterfaceBuilder { 87 | designableButton.setImage(designableButton.image(for: .normal)?.withRenderingMode(UIImage.RenderingMode.alwaysTemplate), for: .normal) 88 | } 89 | 90 | designableButton.alignImageAndTitleVertically() 91 | designableButton.layer.cornerRadius = designableButton.cornerRadius ?? 12 92 | //designableButton.layer.borderWidth = designableButton.borderWidth ?? 1 93 | }, for: "Icon") 94 | 95 | DesignableButton.setStyle(style: { (designableButton: DesignableButton) -> Void in 96 | if designableButton.isHighlighted || designableButton.isSelected { 97 | designableButton.backgroundColor = designableButton.selectedColor 98 | } else if designableButton.isEnabled { 99 | designableButton.backgroundColor = designableButton.defaultColor 100 | } 101 | else { 102 | designableButton.backgroundColor = designableButton.disabledColor 103 | } 104 | designableButton.layer.cornerRadius = designableButton.cornerRadius ?? 12 105 | }, for: "plain") 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/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 | 2.1 19 | CFBundleVersion 20 | 2.1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarHidden 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /DesignableButton/DesignableButton/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // DesignableButton 4 | // 5 | // Created by Fraser on 27/09/17. 6 | // Copyright © 2017 IdleHandsApps. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /IHDesignableButton.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "IHDesignableButton" 3 | s.version = "2.1" 4 | 5 | s.summary = "A Custom UIButton with Centralised Reusable UIButton Styles, Powered by Interface Builder" 6 | 7 | s.description = <<-DESC 8 | DesignableButton allows you to declare reusable button style definitions. In Interface Builder you can easily choose these style for your DesignableButtons and Interface Builder will render these styles immediately. 9 | 10 | Common button styles, such as corner radius, are also made available in Interface Builder 11 | DESC 12 | 13 | s.homepage = "https://github.com/IdleHandsApps/DesignableButton/" 14 | s.license = { :type => "MIT" } 15 | 16 | s.author = { "Fraser Scott-Morrison" => "fraserscottmorrison@me.com" } 17 | 18 | s.ios.deployment_target = "10.0" 19 | s.swift_version = '5.0' 20 | 21 | s.source = { :git => "https://github.com/IdleHandsApps/DesignableButton.git", :tag => s.version.to_s } 22 | 23 | s.source_files = "Sources/*.swift" 24 | 25 | s.framework = "UIKit" 26 | s.requires_arc = true 27 | end 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 Fraser Scott-Morrison 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | let package = Package( 4 | name: "DesignableButton" 5 | ) 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | DesignableButton 3 |

4 | 5 | DesignableButton [![Language: Swift 4.0](https://img.shields.io/badge/Swift-4.0-orange.svg)](https://swift.org) 6 | ------------------------------ 7 | 8 | ![alt demo](https://github.com/IdleHandsApps/DesignableButton/blob/files/DesButGif.gif) 9 | 10 | DesignableButton is a UIButton subclass that uses a centralised and reusable styling. In InterfaceBuilder, drag and drop a DesignableButton, choose your style and its applied instantly in InterfaceBuilder 11 | 12 | ## Features 13 | 14 | * One centralised class to define you main button styles so they can be reused 15 | * Different styles for different button states: Normal/Selected/Disabled 16 | * The centralised styles can be set in IB (no more IBOutlets needed for programatical styling) 17 | * View the style in IB in realtime. Even changing button to selected state will update IB 18 | * Individual buttons can override their centralised styles in IB 19 | * Rounded corners and borders are easy with DesignableButton 20 | * Buttons with an image above text are easy with DesignableButton 21 | 22 | ## How to install 23 | 24 | Add this to your CocoaPods Podfile. *Note the IH prefix* 25 | ``` 26 | pod 'IHDesignableButton' 27 | ``` 28 | 29 | ## How to use 30 | 31 | Create an DesignableButton+Styles.swift extension file in your project 32 | ```swift 33 | import UIKit 34 | import IHDesignableButton // if DesignableButton is in CocoaPod 35 | extension DesignableButton { 36 | 37 | override open func prepareForInterfaceBuilder() { 38 | super.prepareForInterfaceBuilder() 39 | 40 | DesignableButton.setDesignableStyles(isInterfaceBuilder: true) 41 | } 42 | 43 | static func setDesignableStyles(isInterfaceBuilder: Bool = false) { 44 | 45 | // example style 46 | DesignableButton.setStyle(style: { (designableButton: DesignableButton) -> Void in 47 | if designableButton.isHighlighted || designableButton.isSelected { 48 | // replace this with your style for selected/highlighted states 49 | designableButton.setTitleColor(designableButton.customTextColor ?? UIColor.white, for: UIControlState()) 50 | designableButton.backgroundColor = designableButton.selectedColor ?? UIColor.red 51 | designableButton.layer.borderColor = designableButton.selectedColor?.cgColor ?? UIColor.red.cgColor 52 | designableButton.layer.borderWidth = designableButton.borderWidth ?? 0 53 | } else if designableButton.isEnabled { 54 | // replace this with your style for the normal state 55 | designableButton.setTitleColor(designableButton.customTextColor ?? UIColor.white, for: UIControlState()) 56 | designableButton.backgroundColor = designableButton.defaultColor ?? UIColor.blue 57 | designableButton.layer.borderColor = designableButton.defaultColor?.cgColor ?? UIColor.blue.cgColor 58 | designableButton.layer.borderWidth = designableButton.borderWidth ?? 0 59 | } 60 | else { 61 | // replace this with your style for the disabled state 62 | designableButton.setTitleColor(designableButton.customTextColor ?? UIColor.lightGray, for: UIControlState()) 63 | designableButton.backgroundColor = designableButton.disabledColor ?? UIColor.lightGray() 64 | designableButton.layer.borderColor = designableButton.borderColor?.cgColor ?? UIColor.gray.cgColor 65 | designableButton.layer.borderWidth = designableButton.borderWidth ?? 1 66 | } 67 | 68 | // replace this with your style for all states 69 | designableButton.layer.cornerRadius = designableButton.cornerRadius ?? 12 70 | 71 | designableButton.setTitle(designableButton.titleLabel?.text, for: .normal) 72 | 73 | }, for: "primary") // this is the name/key of your style 74 | } 75 | } 76 | ``` 77 | 78 | In the ```setDesignableStyles()``` method you can call ```DesignableButton.setStyle()``` to create a new style. Most projects will only need a few button styles 79 | 80 | In you AppDelegate's ```application(_ , didFinishLaunchingWithOptions()``` call ```DesignableButton.setDesignableStyles()``` 81 | 82 | Now in Interface Builder, drag a UIButton onto a view 83 | 84 | Change the class to ```DesignableButton``` and the module to ```IHDesignableButton``` 85 | 86 | Change the button type from ```System``` to ```Custom``` 87 | 88 | Set the Button Style to "primary" or any other button style you're created 89 | 90 | 91 | ## Half price for a limited time only :) 92 | 93 | A Codable extension to decode arrays and to catch & log all decoding failures 94 | https://github.com/IdleHandsApps/SafeDecoder 95 | 96 | An elegant solution for keeping views visible when the keyboard is being shown https://github.com/IdleHandsApps/IHKeyboardAvoiding 97 | 98 | A fully automatic status bar overlay for No Internet Connection messages 99 | https://github.com/IdleHandsApps/StatusBarOverlay 100 | 101 | ## Author 102 | 103 | * Fraser Scott-Morrison (fraserscottmorrison@me.com) 104 | 105 | It'd be great to hear about any cool apps that are using DesignableButton 106 | 107 | ## License 108 | 109 | Distributed under the MIT License 110 | -------------------------------------------------------------------------------- /Sources/DesignableButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DesignableButton.swift 3 | // Idle Hands Apps 4 | // 5 | // Created by Fraser Scott-Morrison on 8/02/17. 6 | // Copyright © 2017 Idle Hands Apps. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @IBDesignable 12 | open class DesignableButton: UIButton { 13 | 14 | required public init(style buttonStyle: String) { 15 | super.init(frame: .zero) 16 | defer { 17 | // putting this in a defer as didSet is not called from initialisers 18 | self.buttonStyle = buttonStyle 19 | } 20 | } 21 | 22 | required public init?(coder aDecoder: NSCoder) { 23 | super.init(coder: aDecoder) 24 | } 25 | 26 | required public override init(frame: CGRect) { 27 | super.init(frame: frame) 28 | } 29 | 30 | private var styles = [String: (DesignableButton) -> Void]() 31 | 32 | private static var styles = ["": { (designableButton: DesignableButton) -> Void in 33 | // default "none" style 34 | if designableButton.isHighlighted || designableButton.isSelected { 35 | designableButton.backgroundColor = designableButton.selectedColor 36 | } else if designableButton.isEnabled { 37 | designableButton.backgroundColor = designableButton.defaultColor 38 | } 39 | else { 40 | designableButton.backgroundColor = designableButton.disabledColor 41 | } 42 | designableButton.layer.cornerRadius = designableButton.cornerRadius ?? 0 43 | designableButton.layer.borderWidth = designableButton.borderWidth ?? 0 44 | designableButton.layer.borderColor = designableButton.borderColor?.cgColor 45 | }] 46 | 47 | private func getStyles() -> [String: (DesignableButton) -> Void] { 48 | return self.styles.merging(DesignableButton.styles, uniquingKeysWith: { (first, _) in first }) 49 | } 50 | 51 | public func setStyle(style: @escaping (DesignableButton) -> Void, for key: String) { 52 | self.styles.updateValue(style, forKey: key.lowercased()) 53 | } 54 | 55 | public static func setStyle(style: @escaping (DesignableButton) -> Void, for key: String) { 56 | self.styles.updateValue(style, forKey: key.lowercased()) 57 | } 58 | 59 | public func setStyleForAll() { 60 | self.reversesTitleShadowWhenHighlighted = false 61 | self.showsTouchWhenHighlighted = false 62 | self.adjustsImageWhenHighlighted = false 63 | 64 | self.titleLabel?.textAlignment = .center 65 | self.titleLabel?.numberOfLines = 0 66 | self.titleLabel?.adjustsFontSizeToFitWidth = true 67 | self.titleLabel?.lineBreakMode = .byClipping //<-- MAGIC LINE 68 | } 69 | 70 | open override func awakeFromNib() { 71 | super.awakeFromNib() 72 | 73 | self.updateStyles() 74 | } 75 | 76 | @IBInspectable public var buttonStyle: String = "" { 77 | didSet { 78 | self.updateStyles() 79 | } 80 | } 81 | 82 | @IBInspectable public var defaultColor: UIColor? { 83 | didSet { 84 | self.updateStyles() 85 | } 86 | } 87 | @IBInspectable public var selectedColor: UIColor? { 88 | didSet { 89 | self.updateStyles() 90 | } 91 | } 92 | @IBInspectable public var disabledColor: UIColor? { 93 | didSet { 94 | self.updateStyles() 95 | } 96 | } 97 | public var cornerRadius: CGFloat? { 98 | return _cornerRadius != -1 ? _cornerRadius : nil 99 | } 100 | @IBInspectable public var borderColor: UIColor? { 101 | didSet { 102 | self.updateStyles() 103 | } 104 | } 105 | 106 | @IBInspectable public var _cornerRadius: CGFloat = -1 { 107 | didSet { 108 | self.updateStyles() 109 | } 110 | } 111 | 112 | @IBInspectable public var _borderWidth: CGFloat = -1 { 113 | didSet { 114 | self.updateStyles() 115 | } 116 | } 117 | public var borderWidth: CGFloat? { 118 | return _borderWidth != -1 ? _borderWidth : nil 119 | } 120 | 121 | @IBInspectable public var customTextColor: UIColor? { 122 | didSet { 123 | self.updateStyles() 124 | } 125 | } 126 | 127 | // support for Dynamic Type without allowing the text to grow too big to fit 128 | @IBInspectable public var adjustsFontSizeToFitWidth: Bool = false { 129 | didSet { 130 | self.titleLabel?.adjustsFontForContentSizeCategory = self.adjustsFontSizeToFitWidth 131 | self.titleLabel?.adjustsFontSizeToFitWidth = self.adjustsFontSizeToFitWidth 132 | self.titleLabel?.baselineAdjustment = self.adjustsFontSizeToFitWidth ? .alignCenters : .alignBaselines 133 | 134 | if self.adjustsFontSizeToFitWidth { 135 | // When dynamic text changes we need to redraw the layout 136 | NotificationCenter.default.addObserver(forName: UIContentSizeCategory.didChangeNotification, object: nil, queue: OperationQueue.main) { [weak self] notification in 137 | guard let strongSelf = self else { return } 138 | strongSelf.setNeedsLayout() 139 | } 140 | } 141 | else { 142 | NotificationCenter.default.removeObserver(self, name: UIContentSizeCategory.didChangeNotification, object: nil) 143 | } 144 | } 145 | } 146 | 147 | @IBInspectable open override var isHighlighted: Bool { 148 | didSet { 149 | self.updateStyles() 150 | } 151 | } 152 | @IBInspectable open override var isSelected: Bool { 153 | didSet { 154 | self.updateStyles() 155 | } 156 | } 157 | @IBInspectable open override var isEnabled: Bool { 158 | didSet { 159 | self.updateStyles() 160 | } 161 | } 162 | 163 | public func updateStyles() { 164 | 165 | if self.buttonStyle.count > 0 { 166 | self.setStyleForAll() 167 | } 168 | 169 | if let styleBlock = self.getStyles()[self.buttonStyle.lowercased()] { 170 | styleBlock(self) 171 | } 172 | 173 | layer.masksToBounds = layer.cornerRadius > 0 174 | 175 | assert(self.buttonType == UIButton.ButtonType.custom, "Designable Button \"\(self.titleLabel?.text ?? "?")\" buttonType must be Custom") 176 | } 177 | } 178 | 179 | // helper to put icon above text 180 | public extension UIButton { 181 | 182 | func alignImageAndTitleVertically(padding: CGFloat = 6.0) { 183 | let imageSize = self.imageView!.frame.size 184 | let titleSize = self.titleLabel!.frame.size 185 | let totalHeight = imageSize.height + titleSize.height + padding 186 | 187 | self.imageEdgeInsets = UIEdgeInsets( 188 | top: -(totalHeight - imageSize.height), 189 | left: 0, 190 | bottom: 0, 191 | right: -titleSize.width 192 | ) 193 | 194 | self.titleEdgeInsets = UIEdgeInsets( 195 | top: 0, 196 | left: -imageSize.width, 197 | bottom: -(totalHeight - titleSize.height), 198 | right: 0 199 | ) 200 | } 201 | } 202 | --------------------------------------------------------------------------------