├── .gitignore ├── JMButton.podspec ├── JMButton.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── JMButton ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── icon.imageset │ │ ├── Contents.json │ │ └── icon.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── JMBadgeViewController.h ├── JMBadgeViewController.m ├── JMBasicViewController.h ├── JMBasicViewController.m ├── JMBootstrapViewController.h ├── JMBootstrapViewController.m ├── JMButton │ ├── BaseButton │ │ ├── JMBaseButton.h │ │ ├── JMBaseButton.m │ │ ├── JMBaseButtonConfig.h │ │ └── JMBaseButtonConfig.m │ ├── BootstrapButton │ │ ├── JMBootstrapButton.h │ │ ├── JMBootstrapButton.m │ │ ├── JMBootstrapButtonConfig.h │ │ └── JMBootstrapButtonConfig.m │ ├── JMBadgeValue.h │ ├── JMBadgeValue.m │ ├── JMButton.h │ ├── JMButton.m │ ├── JMButtons.h │ ├── JMCategroy │ │ ├── JMBaseButton+CountDown.h │ │ ├── JMBaseButton+CountDown.m │ │ ├── JMDefine.h │ │ ├── JMRuntime.h │ │ ├── JMRuntime.m │ │ ├── UIColor+JM.h │ │ ├── UIColor+JM.m │ │ ├── UIView+JM.h │ │ └── UIView+JM.m │ ├── NumberButton │ │ ├── JMNumberButton.h │ │ ├── JMNumberButton.m │ │ ├── JMNumberButtonConfig.h │ │ └── JMNumberButtonConfig.m │ ├── RadioButton │ │ ├── JMRadioButton.h │ │ └── JMRadioButton.m │ └── WaveButton │ │ ├── JMWaveButton.h │ │ ├── JMWaveButton.m │ │ ├── JMWaveButtonConfig.h │ │ └── JMWaveButtonConfig.m ├── JMCountDownViewController.h ├── JMCountDownViewController.m ├── JMCustomViewController.h ├── JMCustomViewController.m ├── JMNumberViewController.h ├── JMNumberViewController.m ├── JMRadioViewController.h ├── JMRadioViewController.m ├── JMWaveViewController.h ├── JMWaveViewController.m ├── ViewController.h ├── ViewController.m └── main.m ├── 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 | -------------------------------------------------------------------------------- /JMButton.podspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pod::Spec.new do |s| 4 | 5 | s.name = "JMButton" 6 | s.version = "0.6" 7 | s.summary = "超强自定义Button" 8 | 9 | s.description = <<-DESC 10 | 修复设置tag值无效问题 11 | DESC 12 | 13 | s.homepage = "https://github.com/JunAILiang/JMButton.git" 14 | 15 | s.license = "MIT" 16 | 17 | s.author = { "LJM" => "gzliujm@163.com" } 18 | 19 | s.platform = :ios, "8.0" 20 | 21 | s.source = { :git => "https://github.com/JunAILiang/JMButton.git", :tag => "#{s.version}" } 22 | 23 | s.source_files = "JMButton/JMButton/**/*.{h,m}" 24 | 25 | s.requires_arc = true 26 | 27 | end 28 | -------------------------------------------------------------------------------- /JMButton.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | CB1862D42010ABC3001C4120 /* JMNumberButtonConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CB1862D32010ABC3001C4120 /* JMNumberButtonConfig.m */; }; 11 | CB1862D72010AD04001C4120 /* JMNumberButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CB1862D62010AD04001C4120 /* JMNumberButton.m */; }; 12 | CB1862DA2010B38D001C4120 /* JMNumberViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB1862D92010B38D001C4120 /* JMNumberViewController.m */; }; 13 | CB2FE55520061CAA001C4A14 /* JMBootstrapButtonConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CB2FE55420061CAA001C4A14 /* JMBootstrapButtonConfig.m */; }; 14 | CB2FE55820061CD2001C4A14 /* JMBootstrapButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CB2FE55720061CD2001C4A14 /* JMBootstrapButton.m */; }; 15 | CB38A2B62016E1C1001F6EF0 /* JMWaveButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CB38A2B52016E1C1001F6EF0 /* JMWaveButton.m */; }; 16 | CB38A2B92016E20D001F6EF0 /* JMWaveButtonConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CB38A2B82016E20D001F6EF0 /* JMWaveButtonConfig.m */; }; 17 | CB38A2BC2016F885001F6EF0 /* JMWaveViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB38A2BB2016F885001F6EF0 /* JMWaveViewController.m */; }; 18 | CB42C3BF201C147200F41361 /* JMRadioButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CB42C3BE201C147200F41361 /* JMRadioButton.m */; }; 19 | CB42C3C2201C29DE00F41361 /* JMRadioViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB42C3C1201C29DE00F41361 /* JMRadioViewController.m */; }; 20 | CB49FE0E20060FEB00FCCBD7 /* JMBasicViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB49FE0D20060FEA00FCCBD7 /* JMBasicViewController.m */; }; 21 | CB6F2FDC200EEEA1004E46A5 /* JMBaseButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CB6F2FD9200EEEA1004E46A5 /* JMBaseButton.m */; }; 22 | CB6F2FDD200EEEA1004E46A5 /* JMBaseButtonConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = CB6F2FDB200EEEA1004E46A5 /* JMBaseButtonConfig.m */; }; 23 | CB6F2FEA200F06E8004E46A5 /* JMBaseButton+CountDown.m in Sources */ = {isa = PBXBuildFile; fileRef = CB6F2FE9200F06E8004E46A5 /* JMBaseButton+CountDown.m */; }; 24 | CB6F2FF0200F2138004E46A5 /* JMCountDownViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB6F2FEF200F2138004E46A5 /* JMCountDownViewController.m */; }; 25 | CB6F2FF3200F2FA9004E46A5 /* JMCustomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB6F2FF2200F2FA9004E46A5 /* JMCustomViewController.m */; }; 26 | CB9CDA58200BA5530029D42F /* JMBadgeValue.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9CDA56200BA5530029D42F /* JMBadgeValue.m */; }; 27 | CB9CDA5B200BA57B0029D42F /* UIColor+JM.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9CDA5A200BA57B0029D42F /* UIColor+JM.m */; }; 28 | CB9CDA5E200BADAC0029D42F /* JMBadgeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9CDA5D200BADAC0029D42F /* JMBadgeViewController.m */; }; 29 | CB9CDAC1200D009C0029D42F /* JMBootstrapViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9CDAC0200D009C0029D42F /* JMBootstrapViewController.m */; }; 30 | CBA664BD200360DD009F12D3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CBA664BC200360DD009F12D3 /* AppDelegate.m */; }; 31 | CBA664C0200360DD009F12D3 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBA664BF200360DD009F12D3 /* ViewController.m */; }; 32 | CBA664C3200360DD009F12D3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CBA664C1200360DD009F12D3 /* Main.storyboard */; }; 33 | CBA664C5200360DD009F12D3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CBA664C4200360DD009F12D3 /* Assets.xcassets */; }; 34 | CBA664C8200360DD009F12D3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CBA664C6200360DD009F12D3 /* LaunchScreen.storyboard */; }; 35 | CBA664CB200360DD009F12D3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CBA664CA200360DD009F12D3 /* main.m */; }; 36 | CBC4461D2003629B00A2ACD2 /* JMButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CBC4461C2003629B00A2ACD2 /* JMButton.m */; }; 37 | CBC446232003648E00A2ACD2 /* JMRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = CBC4461F2003648D00A2ACD2 /* JMRuntime.m */; }; 38 | CBC446242003648E00A2ACD2 /* UIView+JM.m in Sources */ = {isa = PBXBuildFile; fileRef = CBC446202003648D00A2ACD2 /* UIView+JM.m */; }; 39 | /* End PBXBuildFile section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | CB1862D22010ABC3001C4120 /* JMNumberButtonConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMNumberButtonConfig.h; sourceTree = ""; }; 43 | CB1862D32010ABC3001C4120 /* JMNumberButtonConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMNumberButtonConfig.m; sourceTree = ""; }; 44 | CB1862D52010AD04001C4120 /* JMNumberButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMNumberButton.h; sourceTree = ""; }; 45 | CB1862D62010AD04001C4120 /* JMNumberButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMNumberButton.m; sourceTree = ""; }; 46 | CB1862D82010B38D001C4120 /* JMNumberViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMNumberViewController.h; sourceTree = ""; }; 47 | CB1862D92010B38D001C4120 /* JMNumberViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMNumberViewController.m; sourceTree = ""; }; 48 | CB2FE55320061CAA001C4A14 /* JMBootstrapButtonConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMBootstrapButtonConfig.h; sourceTree = ""; }; 49 | CB2FE55420061CAA001C4A14 /* JMBootstrapButtonConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMBootstrapButtonConfig.m; sourceTree = ""; }; 50 | CB2FE55620061CD2001C4A14 /* JMBootstrapButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMBootstrapButton.h; sourceTree = ""; }; 51 | CB2FE55720061CD2001C4A14 /* JMBootstrapButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMBootstrapButton.m; sourceTree = ""; }; 52 | CB38A2B42016E1C1001F6EF0 /* JMWaveButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMWaveButton.h; sourceTree = ""; }; 53 | CB38A2B52016E1C1001F6EF0 /* JMWaveButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMWaveButton.m; sourceTree = ""; }; 54 | CB38A2B72016E20D001F6EF0 /* JMWaveButtonConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMWaveButtonConfig.h; sourceTree = ""; }; 55 | CB38A2B82016E20D001F6EF0 /* JMWaveButtonConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMWaveButtonConfig.m; sourceTree = ""; }; 56 | CB38A2BA2016F885001F6EF0 /* JMWaveViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMWaveViewController.h; sourceTree = ""; }; 57 | CB38A2BB2016F885001F6EF0 /* JMWaveViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMWaveViewController.m; sourceTree = ""; }; 58 | CB42C3BD201C147200F41361 /* JMRadioButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMRadioButton.h; sourceTree = ""; }; 59 | CB42C3BE201C147200F41361 /* JMRadioButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMRadioButton.m; sourceTree = ""; }; 60 | CB42C3C0201C29DE00F41361 /* JMRadioViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMRadioViewController.h; sourceTree = ""; }; 61 | CB42C3C1201C29DE00F41361 /* JMRadioViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMRadioViewController.m; sourceTree = ""; }; 62 | CB49FE0C20060FEA00FCCBD7 /* JMBasicViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMBasicViewController.h; sourceTree = ""; }; 63 | CB49FE0D20060FEA00FCCBD7 /* JMBasicViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMBasicViewController.m; sourceTree = ""; }; 64 | CB6F2FD8200EEEA1004E46A5 /* JMBaseButtonConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMBaseButtonConfig.h; sourceTree = ""; }; 65 | CB6F2FD9200EEEA1004E46A5 /* JMBaseButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMBaseButton.m; sourceTree = ""; }; 66 | CB6F2FDA200EEEA1004E46A5 /* JMBaseButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMBaseButton.h; sourceTree = ""; }; 67 | CB6F2FDB200EEEA1004E46A5 /* JMBaseButtonConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMBaseButtonConfig.m; sourceTree = ""; }; 68 | CB6F2FE8200F06E8004E46A5 /* JMBaseButton+CountDown.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JMBaseButton+CountDown.h"; sourceTree = ""; }; 69 | CB6F2FE9200F06E8004E46A5 /* JMBaseButton+CountDown.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "JMBaseButton+CountDown.m"; sourceTree = ""; }; 70 | CB6F2FEE200F2138004E46A5 /* JMCountDownViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMCountDownViewController.h; sourceTree = ""; }; 71 | CB6F2FEF200F2138004E46A5 /* JMCountDownViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMCountDownViewController.m; sourceTree = ""; }; 72 | CB6F2FF1200F2FA9004E46A5 /* JMCustomViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMCustomViewController.h; sourceTree = ""; }; 73 | CB6F2FF2200F2FA9004E46A5 /* JMCustomViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMCustomViewController.m; sourceTree = ""; }; 74 | CB78E3512011F5480017567A /* JMButtons.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMButtons.h; sourceTree = ""; }; 75 | CB9CDA56200BA5530029D42F /* JMBadgeValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMBadgeValue.m; sourceTree = ""; }; 76 | CB9CDA57200BA5530029D42F /* JMBadgeValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMBadgeValue.h; sourceTree = ""; }; 77 | CB9CDA59200BA57B0029D42F /* UIColor+JM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+JM.h"; sourceTree = ""; }; 78 | CB9CDA5A200BA57B0029D42F /* UIColor+JM.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+JM.m"; sourceTree = ""; }; 79 | CB9CDA5C200BADAC0029D42F /* JMBadgeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMBadgeViewController.h; sourceTree = ""; }; 80 | CB9CDA5D200BADAC0029D42F /* JMBadgeViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMBadgeViewController.m; sourceTree = ""; }; 81 | CB9CDABF200D009C0029D42F /* JMBootstrapViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMBootstrapViewController.h; sourceTree = ""; }; 82 | CB9CDAC0200D009C0029D42F /* JMBootstrapViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMBootstrapViewController.m; sourceTree = ""; }; 83 | CBA664B8200360DD009F12D3 /* JMButton.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JMButton.app; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | CBA664BB200360DD009F12D3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 85 | CBA664BC200360DD009F12D3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 86 | CBA664BE200360DD009F12D3 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 87 | CBA664BF200360DD009F12D3 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 88 | CBA664C2200360DD009F12D3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 89 | CBA664C4200360DD009F12D3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 90 | CBA664C7200360DD009F12D3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 91 | CBA664C9200360DD009F12D3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 92 | CBA664CA200360DD009F12D3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 93 | CBC4461B2003629B00A2ACD2 /* JMButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMButton.h; sourceTree = ""; }; 94 | CBC4461C2003629B00A2ACD2 /* JMButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMButton.m; sourceTree = ""; }; 95 | CBC4461F2003648D00A2ACD2 /* JMRuntime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMRuntime.m; sourceTree = ""; }; 96 | CBC446202003648D00A2ACD2 /* UIView+JM.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+JM.m"; sourceTree = ""; }; 97 | CBC446212003648D00A2ACD2 /* UIView+JM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+JM.h"; sourceTree = ""; }; 98 | CBC446222003648D00A2ACD2 /* JMRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMRuntime.h; sourceTree = ""; }; 99 | CBC44625200364C700A2ACD2 /* JMDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMDefine.h; sourceTree = ""; }; 100 | /* End PBXFileReference section */ 101 | 102 | /* Begin PBXFrameworksBuildPhase section */ 103 | CBA664B5200360DD009F12D3 /* Frameworks */ = { 104 | isa = PBXFrameworksBuildPhase; 105 | buildActionMask = 2147483647; 106 | files = ( 107 | ); 108 | runOnlyForDeploymentPostprocessing = 0; 109 | }; 110 | /* End PBXFrameworksBuildPhase section */ 111 | 112 | /* Begin PBXGroup section */ 113 | CB1862CE2010AB22001C4120 /* NumberButton */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | CB1862D52010AD04001C4120 /* JMNumberButton.h */, 117 | CB1862D62010AD04001C4120 /* JMNumberButton.m */, 118 | CB1862D22010ABC3001C4120 /* JMNumberButtonConfig.h */, 119 | CB1862D32010ABC3001C4120 /* JMNumberButtonConfig.m */, 120 | ); 121 | path = NumberButton; 122 | sourceTree = ""; 123 | }; 124 | CB2FE54F20061C68001C4A14 /* BootstrapButton */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | CB2FE55620061CD2001C4A14 /* JMBootstrapButton.h */, 128 | CB2FE55720061CD2001C4A14 /* JMBootstrapButton.m */, 129 | CB2FE55320061CAA001C4A14 /* JMBootstrapButtonConfig.h */, 130 | CB2FE55420061CAA001C4A14 /* JMBootstrapButtonConfig.m */, 131 | ); 132 | path = BootstrapButton; 133 | sourceTree = ""; 134 | }; 135 | CB38A2B32016E1AB001F6EF0 /* WaveButton */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | CB38A2B42016E1C1001F6EF0 /* JMWaveButton.h */, 139 | CB38A2B52016E1C1001F6EF0 /* JMWaveButton.m */, 140 | CB38A2B72016E20D001F6EF0 /* JMWaveButtonConfig.h */, 141 | CB38A2B82016E20D001F6EF0 /* JMWaveButtonConfig.m */, 142 | ); 143 | path = WaveButton; 144 | sourceTree = ""; 145 | }; 146 | CB42C3BC201C144A00F41361 /* RadioButton */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | CB42C3BD201C147200F41361 /* JMRadioButton.h */, 150 | CB42C3BE201C147200F41361 /* JMRadioButton.m */, 151 | ); 152 | path = RadioButton; 153 | sourceTree = ""; 154 | }; 155 | CB6F2FD7200EEEA1004E46A5 /* BaseButton */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | CB6F2FDA200EEEA1004E46A5 /* JMBaseButton.h */, 159 | CB6F2FD9200EEEA1004E46A5 /* JMBaseButton.m */, 160 | CB6F2FD8200EEEA1004E46A5 /* JMBaseButtonConfig.h */, 161 | CB6F2FDB200EEEA1004E46A5 /* JMBaseButtonConfig.m */, 162 | ); 163 | path = BaseButton; 164 | sourceTree = ""; 165 | }; 166 | CBA664AF200360DD009F12D3 = { 167 | isa = PBXGroup; 168 | children = ( 169 | CBA664BA200360DD009F12D3 /* JMButton */, 170 | CBA664B9200360DD009F12D3 /* Products */, 171 | ); 172 | sourceTree = ""; 173 | }; 174 | CBA664B9200360DD009F12D3 /* Products */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | CBA664B8200360DD009F12D3 /* JMButton.app */, 178 | ); 179 | name = Products; 180 | sourceTree = ""; 181 | }; 182 | CBA664BA200360DD009F12D3 /* JMButton */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | CBC4461A2003628600A2ACD2 /* JMButton */, 186 | CBA664BB200360DD009F12D3 /* AppDelegate.h */, 187 | CBA664BC200360DD009F12D3 /* AppDelegate.m */, 188 | CBA664BE200360DD009F12D3 /* ViewController.h */, 189 | CBA664BF200360DD009F12D3 /* ViewController.m */, 190 | CB49FE0C20060FEA00FCCBD7 /* JMBasicViewController.h */, 191 | CB49FE0D20060FEA00FCCBD7 /* JMBasicViewController.m */, 192 | CB9CDA5C200BADAC0029D42F /* JMBadgeViewController.h */, 193 | CB9CDA5D200BADAC0029D42F /* JMBadgeViewController.m */, 194 | CB9CDABF200D009C0029D42F /* JMBootstrapViewController.h */, 195 | CB9CDAC0200D009C0029D42F /* JMBootstrapViewController.m */, 196 | CB6F2FEE200F2138004E46A5 /* JMCountDownViewController.h */, 197 | CB6F2FEF200F2138004E46A5 /* JMCountDownViewController.m */, 198 | CB6F2FF1200F2FA9004E46A5 /* JMCustomViewController.h */, 199 | CB6F2FF2200F2FA9004E46A5 /* JMCustomViewController.m */, 200 | CB1862D82010B38D001C4120 /* JMNumberViewController.h */, 201 | CB1862D92010B38D001C4120 /* JMNumberViewController.m */, 202 | CB38A2BA2016F885001F6EF0 /* JMWaveViewController.h */, 203 | CB38A2BB2016F885001F6EF0 /* JMWaveViewController.m */, 204 | CB42C3C0201C29DE00F41361 /* JMRadioViewController.h */, 205 | CB42C3C1201C29DE00F41361 /* JMRadioViewController.m */, 206 | CBA664C1200360DD009F12D3 /* Main.storyboard */, 207 | CBA664C4200360DD009F12D3 /* Assets.xcassets */, 208 | CBA664C6200360DD009F12D3 /* LaunchScreen.storyboard */, 209 | CBA664C9200360DD009F12D3 /* Info.plist */, 210 | CBA664CA200360DD009F12D3 /* main.m */, 211 | ); 212 | path = JMButton; 213 | sourceTree = ""; 214 | }; 215 | CBC4461A2003628600A2ACD2 /* JMButton */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | CB42C3BC201C144A00F41361 /* RadioButton */, 219 | CB38A2B32016E1AB001F6EF0 /* WaveButton */, 220 | CB1862CE2010AB22001C4120 /* NumberButton */, 221 | CB6F2FD7200EEEA1004E46A5 /* BaseButton */, 222 | CB2FE54F20061C68001C4A14 /* BootstrapButton */, 223 | CBC4461E2003648D00A2ACD2 /* JMCategroy */, 224 | CB78E3512011F5480017567A /* JMButtons.h */, 225 | CBC4461B2003629B00A2ACD2 /* JMButton.h */, 226 | CBC4461C2003629B00A2ACD2 /* JMButton.m */, 227 | CB9CDA57200BA5530029D42F /* JMBadgeValue.h */, 228 | CB9CDA56200BA5530029D42F /* JMBadgeValue.m */, 229 | ); 230 | path = JMButton; 231 | sourceTree = ""; 232 | }; 233 | CBC4461E2003648D00A2ACD2 /* JMCategroy */ = { 234 | isa = PBXGroup; 235 | children = ( 236 | CBC44625200364C700A2ACD2 /* JMDefine.h */, 237 | CBC446222003648D00A2ACD2 /* JMRuntime.h */, 238 | CBC4461F2003648D00A2ACD2 /* JMRuntime.m */, 239 | CBC446212003648D00A2ACD2 /* UIView+JM.h */, 240 | CBC446202003648D00A2ACD2 /* UIView+JM.m */, 241 | CB9CDA59200BA57B0029D42F /* UIColor+JM.h */, 242 | CB9CDA5A200BA57B0029D42F /* UIColor+JM.m */, 243 | CB6F2FE8200F06E8004E46A5 /* JMBaseButton+CountDown.h */, 244 | CB6F2FE9200F06E8004E46A5 /* JMBaseButton+CountDown.m */, 245 | ); 246 | path = JMCategroy; 247 | sourceTree = ""; 248 | }; 249 | /* End PBXGroup section */ 250 | 251 | /* Begin PBXNativeTarget section */ 252 | CBA664B7200360DD009F12D3 /* JMButton */ = { 253 | isa = PBXNativeTarget; 254 | buildConfigurationList = CBA664CE200360DD009F12D3 /* Build configuration list for PBXNativeTarget "JMButton" */; 255 | buildPhases = ( 256 | CBA664B4200360DD009F12D3 /* Sources */, 257 | CBA664B5200360DD009F12D3 /* Frameworks */, 258 | CBA664B6200360DD009F12D3 /* Resources */, 259 | ); 260 | buildRules = ( 261 | ); 262 | dependencies = ( 263 | ); 264 | name = JMButton; 265 | productName = JMButton; 266 | productReference = CBA664B8200360DD009F12D3 /* JMButton.app */; 267 | productType = "com.apple.product-type.application"; 268 | }; 269 | /* End PBXNativeTarget section */ 270 | 271 | /* Begin PBXProject section */ 272 | CBA664B0200360DD009F12D3 /* Project object */ = { 273 | isa = PBXProject; 274 | attributes = { 275 | LastUpgradeCheck = 0930; 276 | ORGANIZATIONNAME = JM; 277 | TargetAttributes = { 278 | CBA664B7200360DD009F12D3 = { 279 | CreatedOnToolsVersion = 9.1; 280 | ProvisioningStyle = Automatic; 281 | }; 282 | }; 283 | }; 284 | buildConfigurationList = CBA664B3200360DD009F12D3 /* Build configuration list for PBXProject "JMButton" */; 285 | compatibilityVersion = "Xcode 8.0"; 286 | developmentRegion = en; 287 | hasScannedForEncodings = 0; 288 | knownRegions = ( 289 | en, 290 | Base, 291 | ); 292 | mainGroup = CBA664AF200360DD009F12D3; 293 | productRefGroup = CBA664B9200360DD009F12D3 /* Products */; 294 | projectDirPath = ""; 295 | projectRoot = ""; 296 | targets = ( 297 | CBA664B7200360DD009F12D3 /* JMButton */, 298 | ); 299 | }; 300 | /* End PBXProject section */ 301 | 302 | /* Begin PBXResourcesBuildPhase section */ 303 | CBA664B6200360DD009F12D3 /* Resources */ = { 304 | isa = PBXResourcesBuildPhase; 305 | buildActionMask = 2147483647; 306 | files = ( 307 | CBA664C8200360DD009F12D3 /* LaunchScreen.storyboard in Resources */, 308 | CBA664C5200360DD009F12D3 /* Assets.xcassets in Resources */, 309 | CBA664C3200360DD009F12D3 /* Main.storyboard in Resources */, 310 | ); 311 | runOnlyForDeploymentPostprocessing = 0; 312 | }; 313 | /* End PBXResourcesBuildPhase section */ 314 | 315 | /* Begin PBXSourcesBuildPhase section */ 316 | CBA664B4200360DD009F12D3 /* Sources */ = { 317 | isa = PBXSourcesBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | CB9CDAC1200D009C0029D42F /* JMBootstrapViewController.m in Sources */, 321 | CB6F2FDC200EEEA1004E46A5 /* JMBaseButton.m in Sources */, 322 | CBC446232003648E00A2ACD2 /* JMRuntime.m in Sources */, 323 | CB1862D72010AD04001C4120 /* JMNumberButton.m in Sources */, 324 | CB2FE55520061CAA001C4A14 /* JMBootstrapButtonConfig.m in Sources */, 325 | CB42C3BF201C147200F41361 /* JMRadioButton.m in Sources */, 326 | CB49FE0E20060FEB00FCCBD7 /* JMBasicViewController.m in Sources */, 327 | CB2FE55820061CD2001C4A14 /* JMBootstrapButton.m in Sources */, 328 | CBC446242003648E00A2ACD2 /* UIView+JM.m in Sources */, 329 | CB6F2FF0200F2138004E46A5 /* JMCountDownViewController.m in Sources */, 330 | CBC4461D2003629B00A2ACD2 /* JMButton.m in Sources */, 331 | CB9CDA58200BA5530029D42F /* JMBadgeValue.m in Sources */, 332 | CB9CDA5E200BADAC0029D42F /* JMBadgeViewController.m in Sources */, 333 | CB6F2FDD200EEEA1004E46A5 /* JMBaseButtonConfig.m in Sources */, 334 | CBA664C0200360DD009F12D3 /* ViewController.m in Sources */, 335 | CB9CDA5B200BA57B0029D42F /* UIColor+JM.m in Sources */, 336 | CB1862D42010ABC3001C4120 /* JMNumberButtonConfig.m in Sources */, 337 | CB42C3C2201C29DE00F41361 /* JMRadioViewController.m in Sources */, 338 | CB6F2FEA200F06E8004E46A5 /* JMBaseButton+CountDown.m in Sources */, 339 | CBA664CB200360DD009F12D3 /* main.m in Sources */, 340 | CB38A2BC2016F885001F6EF0 /* JMWaveViewController.m in Sources */, 341 | CB6F2FF3200F2FA9004E46A5 /* JMCustomViewController.m in Sources */, 342 | CB1862DA2010B38D001C4120 /* JMNumberViewController.m in Sources */, 343 | CBA664BD200360DD009F12D3 /* AppDelegate.m in Sources */, 344 | CB38A2B62016E1C1001F6EF0 /* JMWaveButton.m in Sources */, 345 | CB38A2B92016E20D001F6EF0 /* JMWaveButtonConfig.m in Sources */, 346 | ); 347 | runOnlyForDeploymentPostprocessing = 0; 348 | }; 349 | /* End PBXSourcesBuildPhase section */ 350 | 351 | /* Begin PBXVariantGroup section */ 352 | CBA664C1200360DD009F12D3 /* Main.storyboard */ = { 353 | isa = PBXVariantGroup; 354 | children = ( 355 | CBA664C2200360DD009F12D3 /* Base */, 356 | ); 357 | name = Main.storyboard; 358 | sourceTree = ""; 359 | }; 360 | CBA664C6200360DD009F12D3 /* LaunchScreen.storyboard */ = { 361 | isa = PBXVariantGroup; 362 | children = ( 363 | CBA664C7200360DD009F12D3 /* Base */, 364 | ); 365 | name = LaunchScreen.storyboard; 366 | sourceTree = ""; 367 | }; 368 | /* End PBXVariantGroup section */ 369 | 370 | /* Begin XCBuildConfiguration section */ 371 | CBA664CC200360DD009F12D3 /* Debug */ = { 372 | isa = XCBuildConfiguration; 373 | buildSettings = { 374 | ALWAYS_SEARCH_USER_PATHS = NO; 375 | CLANG_ANALYZER_NONNULL = YES; 376 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 377 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 378 | CLANG_CXX_LIBRARY = "libc++"; 379 | CLANG_ENABLE_MODULES = YES; 380 | CLANG_ENABLE_OBJC_ARC = YES; 381 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 382 | CLANG_WARN_BOOL_CONVERSION = YES; 383 | CLANG_WARN_COMMA = YES; 384 | CLANG_WARN_CONSTANT_CONVERSION = YES; 385 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 386 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 387 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 388 | CLANG_WARN_EMPTY_BODY = YES; 389 | CLANG_WARN_ENUM_CONVERSION = YES; 390 | CLANG_WARN_INFINITE_RECURSION = YES; 391 | CLANG_WARN_INT_CONVERSION = YES; 392 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 393 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 394 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 396 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 397 | CLANG_WARN_STRICT_PROTOTYPES = YES; 398 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 399 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 400 | CLANG_WARN_UNREACHABLE_CODE = YES; 401 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 402 | CODE_SIGN_IDENTITY = "iPhone Developer"; 403 | COPY_PHASE_STRIP = NO; 404 | DEBUG_INFORMATION_FORMAT = dwarf; 405 | ENABLE_STRICT_OBJC_MSGSEND = YES; 406 | ENABLE_TESTABILITY = YES; 407 | GCC_C_LANGUAGE_STANDARD = gnu11; 408 | GCC_DYNAMIC_NO_PIC = NO; 409 | GCC_NO_COMMON_BLOCKS = YES; 410 | GCC_OPTIMIZATION_LEVEL = 0; 411 | GCC_PREPROCESSOR_DEFINITIONS = ( 412 | "DEBUG=1", 413 | "$(inherited)", 414 | ); 415 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 416 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 417 | GCC_WARN_UNDECLARED_SELECTOR = YES; 418 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 419 | GCC_WARN_UNUSED_FUNCTION = YES; 420 | GCC_WARN_UNUSED_VARIABLE = YES; 421 | IPHONEOS_DEPLOYMENT_TARGET = 11.1; 422 | MTL_ENABLE_DEBUG_INFO = YES; 423 | ONLY_ACTIVE_ARCH = YES; 424 | SDKROOT = iphoneos; 425 | }; 426 | name = Debug; 427 | }; 428 | CBA664CD200360DD009F12D3 /* Release */ = { 429 | isa = XCBuildConfiguration; 430 | buildSettings = { 431 | ALWAYS_SEARCH_USER_PATHS = NO; 432 | CLANG_ANALYZER_NONNULL = YES; 433 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 434 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 435 | CLANG_CXX_LIBRARY = "libc++"; 436 | CLANG_ENABLE_MODULES = YES; 437 | CLANG_ENABLE_OBJC_ARC = YES; 438 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 439 | CLANG_WARN_BOOL_CONVERSION = YES; 440 | CLANG_WARN_COMMA = YES; 441 | CLANG_WARN_CONSTANT_CONVERSION = YES; 442 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 443 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 444 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 445 | CLANG_WARN_EMPTY_BODY = YES; 446 | CLANG_WARN_ENUM_CONVERSION = YES; 447 | CLANG_WARN_INFINITE_RECURSION = YES; 448 | CLANG_WARN_INT_CONVERSION = YES; 449 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 450 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 451 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 452 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 453 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 454 | CLANG_WARN_STRICT_PROTOTYPES = YES; 455 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 456 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 457 | CLANG_WARN_UNREACHABLE_CODE = YES; 458 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 459 | CODE_SIGN_IDENTITY = "iPhone Developer"; 460 | COPY_PHASE_STRIP = NO; 461 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 462 | ENABLE_NS_ASSERTIONS = NO; 463 | ENABLE_STRICT_OBJC_MSGSEND = YES; 464 | GCC_C_LANGUAGE_STANDARD = gnu11; 465 | GCC_NO_COMMON_BLOCKS = YES; 466 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 467 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 468 | GCC_WARN_UNDECLARED_SELECTOR = YES; 469 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 470 | GCC_WARN_UNUSED_FUNCTION = YES; 471 | GCC_WARN_UNUSED_VARIABLE = YES; 472 | IPHONEOS_DEPLOYMENT_TARGET = 11.1; 473 | MTL_ENABLE_DEBUG_INFO = NO; 474 | SDKROOT = iphoneos; 475 | VALIDATE_PRODUCT = YES; 476 | }; 477 | name = Release; 478 | }; 479 | CBA664CF200360DD009F12D3 /* Debug */ = { 480 | isa = XCBuildConfiguration; 481 | buildSettings = { 482 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 483 | CLANG_ENABLE_OBJC_WEAK = YES; 484 | CODE_SIGN_STYLE = Automatic; 485 | DEVELOPMENT_TEAM = 9RL8S7JFUQ; 486 | INFOPLIST_FILE = JMButton/Info.plist; 487 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 488 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 489 | PRODUCT_BUNDLE_IDENTIFIER = com.ailaopo.JMButton; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | TARGETED_DEVICE_FAMILY = 1; 492 | }; 493 | name = Debug; 494 | }; 495 | CBA664D0200360DD009F12D3 /* Release */ = { 496 | isa = XCBuildConfiguration; 497 | buildSettings = { 498 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 499 | CLANG_ENABLE_OBJC_WEAK = YES; 500 | CODE_SIGN_STYLE = Automatic; 501 | DEVELOPMENT_TEAM = 9RL8S7JFUQ; 502 | INFOPLIST_FILE = JMButton/Info.plist; 503 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 504 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 505 | PRODUCT_BUNDLE_IDENTIFIER = com.ailaopo.JMButton; 506 | PRODUCT_NAME = "$(TARGET_NAME)"; 507 | TARGETED_DEVICE_FAMILY = 1; 508 | }; 509 | name = Release; 510 | }; 511 | /* End XCBuildConfiguration section */ 512 | 513 | /* Begin XCConfigurationList section */ 514 | CBA664B3200360DD009F12D3 /* Build configuration list for PBXProject "JMButton" */ = { 515 | isa = XCConfigurationList; 516 | buildConfigurations = ( 517 | CBA664CC200360DD009F12D3 /* Debug */, 518 | CBA664CD200360DD009F12D3 /* Release */, 519 | ); 520 | defaultConfigurationIsVisible = 0; 521 | defaultConfigurationName = Release; 522 | }; 523 | CBA664CE200360DD009F12D3 /* Build configuration list for PBXNativeTarget "JMButton" */ = { 524 | isa = XCConfigurationList; 525 | buildConfigurations = ( 526 | CBA664CF200360DD009F12D3 /* Debug */, 527 | CBA664D0200360DD009F12D3 /* Release */, 528 | ); 529 | defaultConfigurationIsVisible = 0; 530 | defaultConfigurationName = Release; 531 | }; 532 | /* End XCConfigurationList section */ 533 | }; 534 | rootObject = CBA664B0200360DD009F12D3 /* Project object */; 535 | } 536 | -------------------------------------------------------------------------------- /JMButton.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JMButton/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/8. 6 | // Copyright © 2018年 JM. 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 | -------------------------------------------------------------------------------- /JMButton/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/8. 6 | // Copyright © 2018年 JM. 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 | -------------------------------------------------------------------------------- /JMButton/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 | } -------------------------------------------------------------------------------- /JMButton/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /JMButton/Assets.xcassets/icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "icon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /JMButton/Assets.xcassets/icon.imageset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JunAILiang/JMButton/e2b1d586658cdb0ed7086e8591f53a4f9d504b82/JMButton/Assets.xcassets/icon.imageset/icon.png -------------------------------------------------------------------------------- /JMButton/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /JMButton/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /JMButton/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 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /JMButton/JMBadgeViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMBadgeViewController.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/14. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | 26 | @interface JMBadgeViewController : UIViewController 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JMButton/JMBadgeViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMBadgeViewController.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/14. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMBadgeViewController.h" 25 | #import "JMButtons.h" 26 | 27 | @interface JMBadgeViewController () 28 | 29 | /** sv */ 30 | @property (nonatomic, strong) UIScrollView *scrollView; 31 | 32 | @end 33 | 34 | @implementation JMBadgeViewController 35 | 36 | 37 | - (void)viewDidLoad { 38 | [super viewDidLoad]; 39 | self.view.backgroundColor = [UIColor whiteColor]; 40 | self.title = @"带角标的样式"; 41 | 42 | self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, kNavigationBarHeight, self.view.width, self.view.height - kNavigationBarHeight)]; 43 | self.automaticallyAdjustsScrollViewInsets = NO; 44 | [self.view addSubview:self.scrollView]; 45 | 46 | CGFloat W = (self.view.width - 80) / 3; 47 | CGFloat H = 66; 48 | NSInteger rank = 3; 49 | CGFloat rankMargin = (self.view.frame.size.width - rank * W) / (rank ); 50 | CGFloat rowMargin = 20; 51 | 52 | CGFloat lastY = 0; 53 | 54 | NSMutableArray *temp = [NSMutableArray array]; 55 | for (int i = 0; i < 15; i++) { 56 | JMBaseButtonConfig *buttonConfig = [JMBaseButtonConfig buttonConfig]; 57 | buttonConfig.backgroundColor = kRandomColor; 58 | buttonConfig.titleFont = [UIFont systemFontOfSize:20.f]; 59 | if (i >= 0 && i <= 11) { 60 | buttonConfig.title = [NSString stringWithFormat:@"样式%d",i]; 61 | } else if (i == 12) { 62 | buttonConfig.titleFont = [UIFont systemFontOfSize:14.f]; 63 | buttonConfig.title = @"自定义样式1"; 64 | } else if (i == 13) { 65 | buttonConfig.titleFont = [UIFont systemFontOfSize:14.f]; 66 | buttonConfig.title = @"自定义样式2"; 67 | } else if (i == 14) { 68 | buttonConfig.titleFont = [UIFont systemFontOfSize:14.f]; 69 | buttonConfig.title = @"自定义样式3"; 70 | } 71 | 72 | CGFloat X = (i % rank) * (W + rankMargin) + 10; 73 | NSUInteger Y = (i / rank) * (H +rowMargin); 74 | 75 | JMButton *btn = [[JMButton alloc] initWithFrame:CGRectMake(X, Y, W, H) ButtonConfig:buttonConfig]; 76 | btn.tag = i; 77 | [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; 78 | [self.scrollView addSubview:btn]; 79 | 80 | lastY = Y + H; 81 | 82 | [temp addObject:btn]; 83 | } 84 | self.scrollView.contentSize = CGSizeMake(0, lastY); 85 | 86 | 87 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 88 | for (int i = 0; i < temp.count; i++) { 89 | JMButton *btn = temp[i]; 90 | if (i == 0) { 91 | [btn showPointBadgeValue]; 92 | } else if (i == 1) { 93 | [btn showNewBadgeValue]; 94 | } else if (i == 2) { 95 | [btn showNumberBadgeValue:@"66"]; 96 | } else if (i == 3) { 97 | btn.badgeAnimationType = JMBadgeValueAnimationTypeShake; 98 | [btn showPointBadgeValue]; 99 | } else if (i == 4) { 100 | btn.badgeAnimationType = JMBadgeValueAnimationTypeShake; 101 | [btn showNewBadgeValue]; 102 | } else if (i == 5) { 103 | btn.badgeAnimationType = JMBadgeValueAnimationTypeShake; 104 | [btn showNumberBadgeValue:@"66"]; 105 | } else if (i == 6) { 106 | btn.badgeAnimationType = JMBadgeValueAnimationTypeScale; 107 | [btn showPointBadgeValue]; 108 | } else if (i == 7) { 109 | btn.badgeAnimationType = JMBadgeValueAnimationTypeScale; 110 | [btn showNewBadgeValue]; 111 | } else if (i == 8) { 112 | btn.badgeAnimationType = JMBadgeValueAnimationTypeScale; 113 | [btn showNumberBadgeValue:@"66"]; 114 | } else if (i == 9) { 115 | btn.badgeAnimationType = JMBadgeValueAnimationTypeOpacity; 116 | [btn showPointBadgeValue]; 117 | } else if (i == 10) { 118 | btn.badgeAnimationType = JMBadgeValueAnimationTypeOpacity; 119 | [btn showNewBadgeValue]; 120 | } else if (i == 11) { 121 | btn.badgeAnimationType = JMBadgeValueAnimationTypeOpacity; 122 | [btn showNumberBadgeValue:@"66"]; 123 | } else if (i == 12) { 124 | btn.badgeTextColor = [UIColor whiteColor]; 125 | btn.badgeBackgroundColor = [UIColor orangeColor]; 126 | btn.badgeAnimationType = JMBadgeValueAnimationTypeOpacity; 127 | [btn showNumberBadgeValue:@"66"]; 128 | } else if (i == 13) { 129 | btn.badgeTextFont = [UIFont systemFontOfSize:16.f]; 130 | btn.badgeSize = CGSizeMake(30, 30); 131 | btn.badgeOffset = CGPointMake(-20, -10); 132 | btn.badgeAnimationType = JMBadgeValueAnimationTypeOpacity; 133 | [btn showNumberBadgeValue:@"77"]; 134 | btn.badgeRadius = 12.f; 135 | } else if (i == 14) { 136 | btn.badgeTextFont = [UIFont systemFontOfSize:16.f]; 137 | btn.badgeSize = CGSizeMake(30, 30); 138 | btn.badgeOffset = CGPointMake(-60, 10); 139 | btn.badgeAnimationType = JMBadgeValueAnimationTypeOpacity; 140 | [btn showNumberBadgeValue:@"88"]; 141 | btn.badgeRadius = 15.f; 142 | } 143 | 144 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 145 | [btn showBadgeAnimation]; 146 | }); 147 | } 148 | }); 149 | 150 | 151 | 152 | } 153 | 154 | - (void)btnClick:(JMButton *)sender { 155 | JMLog(@"点击了第 %zd 个", sender.tag); 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /JMButton/JMBasicViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMBasicViewController.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/10. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | 26 | @interface JMBasicViewController : UIViewController 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JMButton/JMBasicViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMBasicViewController.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/10. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMBasicViewController.h" 25 | #import "JMButtons.h" 26 | 27 | @interface JMBasicViewController () 28 | 29 | /** sv */ 30 | @property (nonatomic, strong) UIScrollView *scrollView; 31 | 32 | @end 33 | 34 | @implementation JMBasicViewController 35 | 36 | - (void)viewDidLoad { 37 | [super viewDidLoad]; 38 | self.view.backgroundColor = [UIColor whiteColor]; 39 | self.title = @"按钮基本样式"; 40 | 41 | self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, kNavigationBarHeight, self.view.width, self.view.height - kNavigationBarHeight)]; 42 | self.automaticallyAdjustsScrollViewInsets = NO; 43 | [self.view addSubview:self.scrollView]; 44 | 45 | 46 | CGFloat W = (self.view.width - 20) / 3; 47 | CGFloat H = 60; 48 | NSInteger rank = 3; 49 | CGFloat rankMargin = (self.view.frame.size.width - rank * W) / (rank - 1); 50 | CGFloat rowMargin = 10; 51 | 52 | CGFloat lastY = 0; 53 | 54 | for (int i = 0; i < 19; i++) { 55 | JMBaseButtonConfig *buttonConfig = [JMBaseButtonConfig buttonConfig]; 56 | buttonConfig.backgroundColor = kRandomColor; 57 | if (i == 0) { 58 | buttonConfig.title = @"样式1"; 59 | } else if (i == 1) { 60 | buttonConfig.title = @"字体大小"; 61 | buttonConfig.titleFont = [UIFont systemFontOfSize:22.f]; 62 | } else if (i == 2) { 63 | buttonConfig.title = @"字体位置"; 64 | buttonConfig.titleOrigin = CGPointMake(5, 20); 65 | } else if (i == 3) { 66 | buttonConfig.image = [UIImage imageNamed:@"icon"]; 67 | } else if (i == 4) { 68 | buttonConfig.image = [UIImage imageNamed:@"icon"]; 69 | buttonConfig.imageOrigin = CGPointMake(10, 10); 70 | } else if (i == 5) { 71 | buttonConfig.image = [UIImage imageNamed:@"icon"]; 72 | buttonConfig.imageSize = CGSizeMake(55, 55); 73 | } else if (i == 6) { 74 | buttonConfig.title = @"系统默认"; 75 | buttonConfig.image = [UIImage imageNamed:@"icon"]; 76 | } else if (i == 7) { 77 | buttonConfig.title = @"间距"; 78 | buttonConfig.image = [UIImage imageNamed:@"icon"]; 79 | buttonConfig.padding = 26; 80 | } else if (i == 8) { 81 | buttonConfig.title = @"图片在左"; 82 | buttonConfig.image = [UIImage imageNamed:@"icon"]; 83 | buttonConfig.styleType = JMButtonStyleTypeLeft; 84 | } else if (i == 9) { 85 | buttonConfig.title = @"图片在右"; 86 | buttonConfig.image = [UIImage imageNamed:@"icon"]; 87 | buttonConfig.styleType = JMButtonStyleTypeRight; 88 | } else if (i == 10) { 89 | buttonConfig.title = @"图片在上"; 90 | buttonConfig.image = [UIImage imageNamed:@"icon"]; 91 | buttonConfig.styleType = JMButtonStyleTypeTop; 92 | } else if (i == 11) { 93 | buttonConfig.title = @"图片在下"; 94 | buttonConfig.image = [UIImage imageNamed:@"icon"]; 95 | buttonConfig.styleType = JMButtonStyleTypeBottom; 96 | } else if (i == 12) { 97 | buttonConfig.title = @"我有圆角"; 98 | buttonConfig.titleFont = [UIFont systemFontOfSize:22]; 99 | buttonConfig.cornerRadius = 20.f; 100 | } else if (i == 13) { 101 | buttonConfig.title = @"左上圆角"; 102 | buttonConfig.titleFont = [UIFont systemFontOfSize:22]; 103 | buttonConfig.cornerRadius = 20.f; 104 | buttonConfig.corners = UIRectCornerTopLeft; 105 | } else if (i == 14) { 106 | buttonConfig.title = @"右上圆角"; 107 | buttonConfig.titleFont = [UIFont systemFontOfSize:22]; 108 | buttonConfig.cornerRadius = 20.f; 109 | buttonConfig.corners = UIRectCornerTopRight; 110 | } else if (i == 15) { 111 | buttonConfig.title = @"左上右下圆角"; 112 | buttonConfig.cornerRadius = 20.f; 113 | buttonConfig.corners = UIRectCornerTopLeft | UIRectCornerBottomRight; 114 | } else if (i == 16) { 115 | buttonConfig.title = @"我有三个圆角"; 116 | buttonConfig.cornerRadius = 20.f; 117 | buttonConfig.corners = UIRectCornerTopLeft | UIRectCornerBottomRight | UIRectCornerBottomLeft; 118 | } else if (i == 17) { 119 | buttonConfig.title = @"我是有边框的"; 120 | buttonConfig.cornerRadius = 20.f; 121 | buttonConfig.corners = UIRectCornerTopLeft | UIRectCornerBottomRight; 122 | buttonConfig.borderColor = [UIColor blueColor]; 123 | buttonConfig.borderWidth = 6.f; 124 | } else if (i == 18) { 125 | buttonConfig.title = @"我是有边框的"; 126 | buttonConfig.borderColor = [UIColor orangeColor]; 127 | buttonConfig.borderWidth = 5.f; 128 | buttonConfig.cornerRadius = 20.f; 129 | buttonConfig.backgroundColor = [UIColor whiteColor]; 130 | buttonConfig.titleColor = [UIColor redColor]; 131 | } 132 | 133 | CGFloat X = (i % rank) * (W + rankMargin); 134 | NSUInteger Y = (i / rank) * (H +rowMargin); 135 | 136 | JMButton *btn = [[JMButton alloc] initWithFrame:CGRectMake(X, Y, W, H) ButtonConfig:buttonConfig]; 137 | btn.tag = i; 138 | [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; 139 | [self.scrollView addSubview:btn]; 140 | 141 | lastY = Y + H; 142 | } 143 | 144 | self.scrollView.contentSize = CGSizeMake(0, lastY); 145 | } 146 | 147 | - (void)btnClick:(JMButton *)sender { 148 | JMLog(@"点击了第 %zd 个", sender.tag); 149 | } 150 | 151 | 152 | 153 | @end 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /JMButton/JMBootstrapViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMBootstrapViewController.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/15. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | 26 | @interface JMBootstrapViewController : UIViewController 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JMButton/JMBootstrapViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMBootstrapViewController.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/15. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMBootstrapViewController.h" 25 | #import "JMButtons.h" 26 | 27 | @interface JMBootstrapViewController () 28 | 29 | /** sv */ 30 | @property (nonatomic, strong) UIScrollView *scrollView; 31 | 32 | @end 33 | 34 | @implementation JMBootstrapViewController 35 | 36 | 37 | - (void)viewDidLoad { 38 | [super viewDidLoad]; 39 | self.view.backgroundColor = [UIColor whiteColor]; 40 | self.title = @"Bootstrap样式"; 41 | 42 | self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, kNavigationBarHeight, self.view.width, self.view.height - kNavigationBarHeight)]; 43 | self.automaticallyAdjustsScrollViewInsets = NO; 44 | [self.view addSubview:self.scrollView]; 45 | 46 | 47 | CGFloat W = (self.view.width - 60) / 3; 48 | CGFloat H = 60; 49 | NSInteger rank = 3; 50 | CGFloat rankMargin = (self.view.frame.size.width - rank * W) / (rank); 51 | CGFloat rowMargin = 10; 52 | 53 | CGFloat lastY = 0; 54 | 55 | for (int i = 0; i < 11; i++) { 56 | JMBootstrapButtonConfig *buttonConfig = [JMBootstrapButtonConfig buttonConfig]; 57 | buttonConfig.titleFont = [UIFont systemFontOfSize:20.f]; 58 | if (i == 0) { 59 | buttonConfig.title = @"Default"; 60 | buttonConfig.bootstrapType = JMBootstrapTypeDefault; 61 | } else if (i == 1) { 62 | buttonConfig.title = @"Primary"; 63 | buttonConfig.bootstrapType = JMBootstrapTypePrimary; 64 | } else if (i == 2) { 65 | buttonConfig.title = @"Success"; 66 | buttonConfig.bootstrapType = JMBootstrapTypeSuccess; 67 | } else if (i == 3) { 68 | buttonConfig.title = @"Info"; 69 | buttonConfig.bootstrapType = JMBootstrapTypeInfo; 70 | } else if (i == 4) { 71 | buttonConfig.title = @"Danger"; 72 | buttonConfig.bootstrapType = JMBootstrapTypeDanger; 73 | } else if (i == 5) { 74 | buttonConfig.title = @"Warning"; 75 | buttonConfig.bootstrapType = JMBootstrapTypeWarning; 76 | } else if (i == 6) { 77 | buttonConfig.title = @"Maroon"; 78 | buttonConfig.bootstrapType = JMBootstrapTypeMaroon; 79 | } else if (i == 7) { 80 | buttonConfig.title = @"Purple"; 81 | buttonConfig.bootstrapType = JMBootstrapTypePurple; 82 | } else if (i == 8) { 83 | buttonConfig.title = @"Navy"; 84 | buttonConfig.bootstrapType = JMBootstrapTypeNavy; 85 | } else if (i == 9) { 86 | buttonConfig.title = @"Orange"; 87 | buttonConfig.bootstrapType = JMBootstrapTypeOrange; 88 | } else if (i == 10) { 89 | buttonConfig.title = @"Olive"; 90 | buttonConfig.bootstrapType = JMBootstrapTypeOlive; 91 | } 92 | 93 | 94 | CGFloat X = (i % rank) * (W + rankMargin) + 10; 95 | NSUInteger Y = (i / rank) * (H +rowMargin); 96 | 97 | JMButton *btn = [[JMButton alloc] initWithFrame:CGRectMake(X, Y + 10, W, H) ButtonConfig:buttonConfig]; 98 | btn.tag = i; 99 | [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; 100 | [self.scrollView addSubview:btn]; 101 | 102 | 103 | lastY = Y + H; 104 | } 105 | 106 | self.scrollView.contentSize = CGSizeMake(0, lastY); 107 | } 108 | 109 | - (void)btnClick:(JMButton *)sender { 110 | JMLog(@"点击了第 %zd 个", sender.tag); 111 | } 112 | 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /JMButton/JMButton/BaseButton/JMBaseButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMBaseButton.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/10. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | #import "JMBaseButtonConfig.h" 26 | 27 | @interface JMBaseButton : UIButton 28 | 29 | + (instancetype)buttonFrame:(CGRect)frame ButtonConfig:(JMBaseButtonConfig *)buttonConfig; 30 | 31 | - (instancetype)initWithFrame:(CGRect)frame ButtonConfig:(JMBaseButtonConfig *)buttonConfig; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /JMButton/JMButton/BaseButton/JMBaseButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMBaseButton.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/10. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMBaseButton.h" 25 | #import "UIView+JM.h" 26 | 27 | @interface JMBaseButton() 28 | 29 | /** buttonConifig */ 30 | @property (nonatomic, strong) JMBaseButtonConfig *buttonConfig; 31 | 32 | @end 33 | 34 | @implementation JMBaseButton 35 | 36 | + (instancetype)buttonFrame:(CGRect)frame ButtonConfig:(JMBaseButtonConfig *)buttonConfig { 37 | return [[self alloc] initWithFrame:frame ButtonConfig:buttonConfig]; 38 | } 39 | 40 | - (instancetype)initWithFrame:(CGRect)frame ButtonConfig:(JMBaseButtonConfig *)buttonConfig { 41 | if (self = [super initWithFrame:frame]) { 42 | self.buttonConfig = buttonConfig; 43 | [self setTitle:buttonConfig.title forState:UIControlStateNormal]; 44 | [self setImage:buttonConfig.image forState:UIControlStateNormal]; 45 | [self setTitleColor:buttonConfig.titleColor forState:UIControlStateNormal]; 46 | [self setBackgroundColor:buttonConfig.backgroundColor]; 47 | [self setBackgroundImage:buttonConfig.backgroundImage forState:UIControlStateNormal]; 48 | self.titleLabel.font = buttonConfig.titleFont; 49 | } 50 | return self; 51 | } 52 | 53 | - (void)layoutSubviews { 54 | [super layoutSubviews]; 55 | 56 | CGFloat centerX = self.width * 0.5; 57 | CGFloat centerY = self.height * 0.5; 58 | CGFloat padding = self.buttonConfig.padding * 0.5; 59 | 60 | //先改Size和中心点, 否则会有位置显示问题 61 | if (self.buttonConfig.imageSize.width !=0 && self.buttonConfig.imageSize.height != 0) { 62 | self.imageView.y = centerY - self.buttonConfig.imageSize.height * 0.5; 63 | self.imageView.size = self.buttonConfig.imageSize; 64 | } 65 | 66 | CGFloat allWidth = self.imageView.width + self.titleLabel.width; 67 | CGFloat allHeight = self.imageView.height + self.titleLabel.height; 68 | 69 | if (self.buttonConfig.styleType == JMButtonStyleTypeLeft) { 70 | self.imageView.x = centerX - allWidth * 0.5 - padding; 71 | self.titleLabel.x = CGRectGetMaxX(self.imageView.frame) + padding * 2; 72 | } else if (self.buttonConfig.styleType == JMButtonStyleTypeRight) { 73 | self.titleLabel.x = centerX - allWidth * 0.5 - padding; 74 | self.imageView.x = CGRectGetMaxX(self.titleLabel.frame) + padding * 2; 75 | } else if (self.buttonConfig.styleType == JMButtonStyleTypeTop) { 76 | self.imageView.x = centerX - self.imageView.width * 0.5; 77 | self.imageView.y = centerY - allHeight * 0.5 - padding; 78 | self.titleLabel.x = centerX - self.titleLabel.width * 0.5; 79 | self.titleLabel.y = CGRectGetMaxY(self.imageView.frame) + padding * 2; 80 | } else if (self.buttonConfig.styleType == JMButtonStyleTypeBottom) { 81 | self.titleLabel.x = centerX - self.titleLabel.width * 0.5; 82 | self.titleLabel.y = centerY - allHeight * 0.5 - padding; 83 | self.imageView.x = centerX - self.imageView.width * 0.5; 84 | self.imageView.y = CGRectGetMaxY(self.titleLabel.frame) + padding * 2; 85 | } 86 | 87 | if (self.buttonConfig.titleOrigin.x != 0 || self.buttonConfig.titleOrigin.y != 0) { 88 | self.titleLabel.x = self.buttonConfig.titleOrigin.x; 89 | self.titleLabel.y = self.buttonConfig.titleOrigin.y; 90 | } 91 | if (self.buttonConfig.imageOrigin.x != 0 || self.buttonConfig.imageOrigin.y != 0) { 92 | self.imageView.x = self.buttonConfig.imageOrigin.x; 93 | self.imageView.y = self.buttonConfig.imageOrigin.y; 94 | } 95 | } 96 | 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /JMButton/JMButton/BaseButton/JMBaseButtonConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMBaseButtonConfig.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/9. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | 25 | #import 26 | #import 27 | 28 | @interface JMBaseButtonConfig : NSObject 29 | 30 | typedef NS_ENUM(NSInteger, JMButtonStyleType) { 31 | JMButtonStyleTypeTop, //图片在上, 文字在下 32 | JMButtonStyleTypeLeft, //图片在左, 文字在右 33 | JMButtonStyleTypeBottom, //图片在下, 文字在上 34 | JMButtonStyleTypeRight, //图片在右, 文字在左 35 | }; 36 | 37 | 38 | /** 初始化 */ 39 | + (instancetype)buttonConfig; 40 | 41 | /** 按钮类型 (默认图片在左, 文字在右) */ 42 | @property (nonatomic, assign) JMButtonStyleType styleType; 43 | /** padding (文字和图片之间的间距, 默认为6.f) */ 44 | @property (nonatomic, assign) CGFloat padding; 45 | 46 | /************************ 文字相关属性设置 ************************/ 47 | /** 文字大小(默认14.f) */ 48 | @property (nonatomic, strong) UIFont *titleFont; 49 | /** 文字 (默认为nil) */ 50 | @property (nonatomic, copy) NSString *title; 51 | /** 文字颜色(默认白色) */ 52 | @property (nonatomic, strong) UIColor *titleColor; 53 | /** 更改文字的origin(无特殊需求,请勿修改此属性, 注意不能设置为0,0) */ 54 | @property (nonatomic, assign) CGPoint titleOrigin; 55 | 56 | 57 | /************************ 图片相关属性设置 ************************/ 58 | /** 图片(默认为nil) */ 59 | @property (nonatomic, strong) UIImage *image; 60 | /** 图片的大小(无特殊需求, 请勿修改此属性) */ 61 | @property (nonatomic, assign) CGSize imageSize; 62 | /** 图片的origin(无特殊需求,请勿修改此属性,注意不能设置为0,0) */ 63 | @property (nonatomic, assign) CGPoint imageOrigin; 64 | 65 | /************************ 圆角相关属性设置 ************************/ 66 | /** 圆角类型 (默认 UIRectCornerAllCorners) */ 67 | @property (nonatomic, assign) UIRectCorner corners; 68 | /** 圆角大小 (默认 0) */ 69 | @property (nonatomic, assign) CGFloat cornerRadius; 70 | 71 | /************************ 背景相关属性设置 ************************/ 72 | /** 背景颜色 (默认 白色) */ 73 | @property (nonatomic, strong) UIColor *backgroundColor; 74 | /** 背景图片 (默认 无) */ 75 | @property (nonatomic, strong) UIImage *backgroundImage; 76 | 77 | /************************ 边框相关属性设置 ************************/ 78 | /** 边框线条颜色 (默认 clearColor) */ 79 | @property (nonatomic, strong) UIColor *borderColor; 80 | /** 边框线条宽度 (默认 0 ) */ 81 | @property (nonatomic, assign) CGFloat borderWidth; 82 | 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /JMButton/JMButton/BaseButton/JMBaseButtonConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMBaseButtonConfig.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/9. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | 25 | #import "JMBaseButtonConfig.h" 26 | 27 | @implementation JMBaseButtonConfig 28 | 29 | + (instancetype)buttonConfig { 30 | return [[self alloc] init]; 31 | } 32 | 33 | - (instancetype)init { 34 | if (self = [super init]) { 35 | _titleFont = [UIFont systemFontOfSize:14.f]; 36 | _title = @""; 37 | _titleColor = [UIColor whiteColor]; 38 | _image = [UIImage new]; 39 | _imageSize = CGSizeZero; 40 | _imageOrigin = CGPointZero; 41 | _titleOrigin = CGPointZero; 42 | _corners = UIRectCornerAllCorners; 43 | _cornerRadius = 0; 44 | _backgroundColor = [UIColor whiteColor]; 45 | _styleType = JMButtonStyleTypeLeft; 46 | _padding = 6.f; 47 | _borderWidth = 0.f; 48 | _borderColor = [UIColor clearColor]; 49 | _backgroundImage = [UIImage new]; 50 | } 51 | return self; 52 | } 53 | 54 | 55 | -(void)setTitleFont:(UIFont *)titleFont { 56 | _titleFont = titleFont; 57 | } 58 | - (void)setTitle:(NSString *)title { 59 | _title = title; 60 | } 61 | - (void)setImage:(UIImage *)image { 62 | _image = image; 63 | } 64 | - (void)setTitleColor:(UIColor *)titleColor { 65 | _titleColor = titleColor; 66 | } 67 | - (void)setImageSize:(CGSize)imageSize { 68 | _imageSize = imageSize; 69 | } 70 | - (void)setTitleOrigin:(CGPoint)titleOrigin { 71 | _titleOrigin = titleOrigin; 72 | } 73 | - (void)setImageOrigin:(CGPoint)imageOrigin { 74 | _imageOrigin = imageOrigin; 75 | } 76 | - (void)setCorners:(UIRectCorner)corners { 77 | _corners = corners; 78 | } 79 | - (void)setCornerRadius:(CGFloat)cornerRadius { 80 | _cornerRadius = cornerRadius; 81 | } 82 | - (void)setBackgroundColor:(UIColor *)backgroundColor { 83 | _backgroundColor = backgroundColor; 84 | } 85 | - (void)setBackgroundImage:(UIImage *)backgroundImage { 86 | _backgroundImage = backgroundImage; 87 | } 88 | - (void)setStyleType:(JMButtonStyleType)styleType { 89 | _styleType = styleType; 90 | } 91 | - (void)setPadding:(CGFloat)padding { 92 | _padding = padding; 93 | } 94 | - (void)setBorderColor:(UIColor *)borderColor { 95 | _borderColor = borderColor; 96 | } 97 | - (void)setBorderWidth:(CGFloat)borderWidth { 98 | _borderWidth = borderWidth; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /JMButton/JMButton/BootstrapButton/JMBootstrapButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMBootstrapButton.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/10. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMBaseButton.h" 25 | 26 | @interface JMBootstrapButton : JMBaseButton 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JMButton/JMButton/BootstrapButton/JMBootstrapButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMBootstrapButton.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/10. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMBootstrapButton.h" 25 | #import "JMBootstrapButtonConfig.h" 26 | #import "UIColor+JM.h" 27 | 28 | @implementation JMBootstrapButton 29 | 30 | + (instancetype)buttonFrame:(CGRect)frame ButtonConfig:(JMBootstrapButtonConfig *)buttonConfig { 31 | return [[self alloc] initWithFrame:frame ButtonConfig:buttonConfig]; 32 | } 33 | 34 | - (instancetype)initWithFrame:(CGRect)frame ButtonConfig:(JMBootstrapButtonConfig *)buttonConfig { 35 | if (self = [super initWithFrame:frame ButtonConfig:buttonConfig]) { 36 | if (buttonConfig.bootstrapType == JMBootstrapTypeDefault) { 37 | [self backgroundColor:[UIColor colorWithHexString:@"#f4f4f4"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#dddddd"] TitleColor:[UIColor colorWithHexString:@"#444444"]]; 38 | } else if (buttonConfig.bootstrapType == JMBootstrapTypePrimary) { 39 | [self backgroundColor:[UIColor colorWithHexString:@"#3c8dbc"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#367fa9"] TitleColor:[UIColor whiteColor]]; 40 | } else if (buttonConfig.bootstrapType == JMBootstrapTypeSuccess) { 41 | [self backgroundColor:[UIColor colorWithHexString:@"#00a65a"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#008d4c"] TitleColor:[UIColor whiteColor]]; 42 | } else if (buttonConfig.bootstrapType == JMBootstrapTypeInfo) { 43 | [self backgroundColor:[UIColor colorWithHexString:@"#00c0ef"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#00acd6"] TitleColor:[UIColor whiteColor]]; 44 | } else if (buttonConfig.bootstrapType == JMBootstrapTypeDanger) { 45 | [self backgroundColor:[UIColor colorWithHexString:@"#dd4b39"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#d73925"] TitleColor:[UIColor whiteColor]]; 46 | } else if (buttonConfig.bootstrapType == JMBootstrapTypeWarning) { 47 | [self backgroundColor:[UIColor colorWithHexString:@"#f39c12"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#e08e0b"] TitleColor:[UIColor whiteColor]]; 48 | } else if (buttonConfig.bootstrapType == JMBootstrapTypeMaroon) { 49 | [self backgroundColor:[UIColor colorWithHexString:@"#f93c81"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#d81b60"] TitleColor:[UIColor whiteColor]]; 50 | } else if (buttonConfig.bootstrapType == JMBootstrapTypePurple) { 51 | [self backgroundColor:[UIColor colorWithHexString:@"#7470bc"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#605ca8"] TitleColor:[UIColor whiteColor]]; 52 | } else if (buttonConfig.bootstrapType == JMBootstrapTypeNavy) { 53 | [self backgroundColor:[UIColor colorWithHexString:@"#163455"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#0C2A4B"] TitleColor:[UIColor whiteColor]]; 54 | } else if (buttonConfig.bootstrapType == JMBootstrapTypeOlive) { 55 | [self backgroundColor:[UIColor colorWithHexString:@"#4ba77e"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#419d74"] TitleColor:[UIColor whiteColor]]; 56 | } else if (buttonConfig.bootstrapType == JMBootstrapTypeOrange) { 57 | [self backgroundColor:[UIColor colorWithHexString:@"#ff9d33"] CornerRadius:3.f BorderWidth:1.f BorderColor:[UIColor colorWithHexString:@"#ff9127"] TitleColor:[UIColor whiteColor]]; 58 | } 59 | } 60 | return self; 61 | } 62 | 63 | - (void)backgroundColor:(UIColor *)backgroudColor CornerRadius:(CGFloat)cornerRadius BorderWidth:(CGFloat)borderWidth BorderColor:(UIColor *)borderColor TitleColor:(UIColor *)titleColor { 64 | self.backgroundColor = backgroudColor; 65 | self.layer.cornerRadius = cornerRadius; 66 | self.layer.masksToBounds = YES; 67 | self.layer.borderWidth = borderWidth; 68 | self.layer.borderColor = borderColor.CGColor; 69 | [self setTitleColor:titleColor forState:UIControlStateNormal]; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /JMButton/JMButton/BootstrapButton/JMBootstrapButtonConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMBootstrapButtonConfig.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/10. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | 25 | #import "JMBaseButtonConfig.h" 26 | 27 | typedef NS_ENUM(NSInteger, JMBootstrapType) { 28 | JMBootstrapTypeNone, //none 29 | JMBootstrapTypeDefault, //Default 30 | JMBootstrapTypePrimary, //Primary 31 | JMBootstrapTypeSuccess, //Success 32 | JMBootstrapTypeInfo, //Info 33 | JMBootstrapTypeDanger, //Danger 34 | JMBootstrapTypeWarning, //Warning 35 | JMBootstrapTypeMaroon, //Maroon 36 | JMBootstrapTypePurple, //Purple 37 | JMBootstrapTypeNavy, //Navy 38 | JMBootstrapTypeOrange, //Orange 39 | JMBootstrapTypeOlive, //Olive 40 | }; 41 | 42 | @interface JMBootstrapButtonConfig : JMBaseButtonConfig 43 | 44 | /** type */ 45 | @property (nonatomic, assign) JMBootstrapType bootstrapType; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /JMButton/JMButton/BootstrapButton/JMBootstrapButtonConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMBootstrapButtonConfig.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/10. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | 25 | #import "JMBootstrapButtonConfig.h" 26 | #import "UIColor+JM.h" 27 | 28 | @implementation JMBootstrapButtonConfig 29 | 30 | - (instancetype)init { 31 | if (self = [super init]) { 32 | self.bootstrapType = JMBootstrapTypeDefault; 33 | } 34 | return self; 35 | } 36 | 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMBadgeValue.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMBadgeValue.h 3 | // JMTabBarController 4 | // 5 | // Created by JM on 2018/1/2. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | 26 | /** badgeValue样式 */ 27 | typedef NS_ENUM(NSInteger, JMBadgeValueType) { 28 | JMBadgeValueTypePoint, //点 29 | JMBadgeValueTypeNew, //new 30 | JMBadgeValueTypeNumber, //number 31 | }; 32 | 33 | /** badgeValue 动画样式 */ 34 | typedef NS_ENUM(NSInteger, JMBadgeValueAnimationType) { 35 | JMBadgeValueAnimationTypeNone, //无动画 36 | JMBadgeValueAnimationTypeShake, //抖动 37 | JMBadgeValueAnimationTypeOpacity, //透明过渡动画 38 | JMBadgeValueAnimationTypeScale, //缩放动画 39 | }; 40 | 41 | @interface JMBadgeValue : UIView 42 | 43 | /** badgeL */ 44 | @property (nonatomic, strong) UILabel *badgeL; 45 | /** type */ 46 | @property (nonatomic, assign) JMBadgeValueType type; 47 | /** animationType */ 48 | @property (nonatomic, assign) JMBadgeValueAnimationType animationType; 49 | /** badgeValue */ 50 | @property (nonatomic, copy) NSString *badgeValue; 51 | @property (nonatomic, assign) CGFloat badgeRadius; 52 | 53 | 54 | - (void)showAnimation; 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMBadgeValue.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMBadgeValue.m 3 | // JMTabBarController 4 | // 5 | // Created by JM on 2018/1/2. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMBadgeValue.h" 25 | #import "UIColor+JM.h" 26 | #import "UIView+JM.h" 27 | 28 | #define angle2Rad(angle) ((angle) / 180.0 * M_PI) 29 | 30 | 31 | @interface JMBadgeValue() 32 | 33 | @end 34 | 35 | @implementation JMBadgeValue 36 | 37 | - (instancetype)initWithFrame:(CGRect)frame { 38 | if (self = [super initWithFrame:frame]) { 39 | 40 | self.badgeL = [[UILabel alloc] initWithFrame:self.bounds]; 41 | self.badgeL.textAlignment = NSTextAlignmentCenter; 42 | self.badgeL.layer.cornerRadius = 8.f; 43 | self.badgeL.layer.masksToBounds = YES; 44 | [self addSubview:self.badgeL]; 45 | } 46 | return self; 47 | } 48 | 49 | - (void)setType:(JMBadgeValueType)type { 50 | _type = type; 51 | if (type == JMBadgeValueTypePoint) { 52 | self.badgeL.size = CGSizeMake(10, 10); 53 | self.badgeL.layer.cornerRadius = 5.f; 54 | self.badgeL.x = 0; 55 | self.badgeL.y = self.height * 0.5 - self.badgeL.size.height * 0.5; 56 | } else if (type == JMBadgeValueTypeNew) { 57 | self.badgeL.text = @"new"; 58 | self.badgeL.size = CGSizeMake(self.width, self.height); 59 | } 60 | } 61 | 62 | - (void)setBadgeValue:(NSString *)badgeValue { 63 | _badgeValue = badgeValue; 64 | self.badgeL.text = badgeValue; 65 | CGSize size = CGSizeZero; 66 | CGFloat radius = 8.f; 67 | if (self.badgeL.text.length <= 1) { 68 | size = CGSizeMake(self.height, self.height); 69 | radius = self.height * 0.5; 70 | } else if (self.badgeL.text.length > 1) { 71 | size = self.bounds.size; 72 | radius = 8.f; 73 | } 74 | self.badgeL.size = size; 75 | self.badgeL.layer.cornerRadius = radius; 76 | } 77 | 78 | - (void)setBadgeRadius:(CGFloat)badgeRadius { 79 | _badgeRadius = badgeRadius; 80 | self.badgeL.layer.cornerRadius = badgeRadius; 81 | } 82 | 83 | - (void)showAnimation { 84 | if (self.animationType == JMBadgeValueAnimationTypeScale) { 85 | CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; 86 | anima.toValue = [NSNumber numberWithFloat:1.2f]; 87 | anima.duration = 0.3f; 88 | anima.repeatCount = 3; 89 | anima.autoreverses = YES; 90 | [self.badgeL.layer addAnimation:anima forKey:@"scale"]; 91 | } else if (self.animationType == JMBadgeValueAnimationTypeShake) { 92 | CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"]; 93 | anima.values = @[@(angle2Rad(-15)),@(angle2Rad(-10)),@(angle2Rad(-7)),@(angle2Rad(-5)),@(angle2Rad(0)),@(angle2Rad(5)),@(angle2Rad(-7)),@(angle2Rad(10)),@(angle2Rad(15))]; 94 | anima.repeatCount = 5.f; 95 | [self.badgeL.layer addAnimation:anima forKey:@"shake"]; 96 | } else if (self.animationType == JMBadgeValueAnimationTypeOpacity) { 97 | CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"opacity"]; 98 | anima.fromValue = [NSNumber numberWithFloat:1.0f]; 99 | anima.toValue = [NSNumber numberWithFloat:0.2f]; 100 | anima.repeatCount = 3; 101 | anima.duration = 0.3; 102 | anima.autoreverses = YES; 103 | [self.badgeL.layer addAnimation:anima forKey:@"opacity"]; 104 | } 105 | } 106 | 107 | - (CGSize)sizeWithAttribute:(NSString *)text { 108 | return [text sizeWithAttributes:@{NSFontAttributeName:self.badgeL.font}]; 109 | } 110 | 111 | @end 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMButton.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/8. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | #import "JMBadgeValue.h" 26 | #import "JMBaseButton+CountDown.h" 27 | #import "JMBaseButton.h" 28 | #import "JMBaseButtonConfig.h" 29 | #import "JMBootstrapButton.h" 30 | #import "JMBootstrapButtonConfig.h" 31 | #import "JMNumberButtonConfig.h" 32 | #import "JMWaveButton.h" 33 | #import "JMWaveButtonConfig.h" 34 | 35 | @interface JMButton : UIView 36 | 37 | 38 | /** 39 | 初始化方法 (此初始化方法能实现按钮的基本样式控制) 40 | @param frame frame 41 | @param buttonConfig 按钮配置文件 42 | */ 43 | - (instancetype)initWithFrame:(CGRect)frame ButtonConfig:(JMBaseButtonConfig *)buttonConfig; 44 | /** 45 | 点击事件 (该点击事件仅支持 initWithFrame: ButtonConfig: 的初始化方式) 如上 46 | @param target 事件目标 47 | @param action 事件方法 48 | @param controlEvents 事件类型 49 | */ 50 | - (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents; 51 | 52 | 53 | /** 54 | 初始化方法 (此初始化方法需要自己设定样式以及事件处理, 可高度自定义, 自定义view不支持角标属性) 55 | @param frame frame 56 | @param customView 自定义的View 57 | */ 58 | - (instancetype)initWithFrame:(CGRect)frame CustomView:(UIView *)customView; 59 | 60 | 61 | 62 | /** 63 | 初始化方法 (此初始化方法用于显示计数器的效果, 类似于 饿了吗 淘宝 京东 等商品的加减) 64 | @param frame frame 65 | @param numberButtonConfig 计数器按钮配置文件 66 | @return JMButton || JMNumberButton 67 | */ 68 | - (instancetype)initWithFrame:(CGRect)frame NumberButtonConfig:(JMNumberButtonConfig *)numberButtonConfig; 69 | 70 | 71 | 72 | 73 | 74 | 75 | /********** 按钮角标配置及显示, 默认不显示角标, 如需要可通过如下方法设置 (frame必需要有值) **********/ 76 | 77 | /***** 请注意, 如果需要自定义角标的样式(如调用时下面五个属性时必需在show方法之前设置调用 *****/ 78 | 79 | /** 角标的文字颜色 (默认 #FFFFFF) */ 80 | @property (nonatomic, strong) UIColor *badgeTextColor; 81 | /** 角标的背景颜色 (默认 #FF4040) */ 82 | @property (nonatomic, strong) UIColor *badgeBackgroundColor; 83 | /** badgeTextFont (如没有特殊需求, 请勿修改此属性, 此属性只有在控制器加载完成后有效)*/ 84 | @property (nonatomic, strong) UIFont *badgeTextFont; 85 | /** badgeSize (如没有特殊需求, 请勿修改此属性, 此属性只有在控制器加载完成后有效)*/ 86 | @property (nonatomic, assign) CGSize badgeSize; 87 | /** badgeOffset (如没有特殊需求, 请勿修改此属性, 此属性只有在控制器加载完成后有效) */ 88 | @property (nonatomic, assign) CGPoint badgeOffset; 89 | /** badge圆角大小 (如没有特殊需求, 请勿修改此属性, 此属性只有在控制器加载完成后有效, 一般配合badgeSize或badgeOffset使用) */ 90 | @property (nonatomic, assign) CGFloat badgeRadius; 91 | 92 | /***** 请注意, 如果需要自定义角标的样式(如调用时上面五个属性时必需在show方法之前设置调用 *****/ 93 | 94 | /** 动画类型 */ 95 | @property (nonatomic, assign) JMBadgeValueAnimationType badgeAnimationType; 96 | /** badgeValue(角标数值, 仅对 数值样式有效) */ 97 | @property (nonatomic, copy) NSString *badgeValue; 98 | 99 | /** 100 | 显示小红点样式 101 | */ 102 | - (void)showPointBadgeValue; 103 | 104 | /** 105 | 显示New样式 106 | */ 107 | - (void)showNewBadgeValue; 108 | 109 | /** 110 | 显示数值样式 111 | @param badgeValue 数值 112 | */ 113 | - (void)showNumberBadgeValue:(NSString *)badgeValue; 114 | 115 | /** 116 | 删除小红点 117 | */ 118 | - (void)removeBadgeValue; 119 | 120 | /** 121 | 展示动画 122 | */ 123 | - (void)showBadgeAnimation; 124 | 125 | 126 | 127 | @end 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMButton.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/8. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMButton.h" 25 | #import "JMRuntime.h" 26 | #import "UIView+JM.h" 27 | #import "UIColor+JM.h" 28 | 29 | @interface JMButton() 30 | 31 | /** baseButton */ 32 | @property (nonatomic, strong) JMBaseButton *baseButton; 33 | /** badgeValue */ 34 | @property (nonatomic, strong) JMBadgeValue *bv; 35 | 36 | @end 37 | 38 | @implementation JMButton 39 | 40 | - (instancetype)initWithFrame:(CGRect)frame NumberButtonConfig:(JMNumberButtonConfig *)numberButtonConfig { 41 | if (self = [super initWithFrame:frame]) { 42 | } 43 | return self; 44 | } 45 | 46 | - (instancetype)initWithFrame:(CGRect)frame CustomView:(UIView *)customView { 47 | if (self = [super initWithFrame:frame]) { 48 | [self addSubview:customView]; 49 | } 50 | return self; 51 | } 52 | 53 | - (instancetype)initWithFrame:(CGRect)frame ButtonConfig:(JMBaseButtonConfig *)buttonConfig { 54 | if (self = [super initWithFrame:frame]) { 55 | if ([buttonConfig isMemberOfClass:[JMBaseButtonConfig class]]) { 56 | self.baseButton = [[JMBaseButton alloc] initWithFrame:self.bounds ButtonConfig:buttonConfig]; 57 | } else if ([buttonConfig isMemberOfClass:[JMBootstrapButtonConfig class]]) { 58 | self.baseButton = [[JMBootstrapButton alloc] initWithFrame:self.bounds ButtonConfig:buttonConfig]; 59 | } else if ([buttonConfig isMemberOfClass:[JMWaveButtonConfig class]]) { 60 | self.baseButton = [[JMWaveButton alloc] initWithFrame:self.bounds ButtonConfig:buttonConfig]; 61 | } 62 | 63 | if (buttonConfig.cornerRadius != 0) { 64 | if (buttonConfig.corners == UIRectCornerAllCorners) { 65 | self.baseButton.layer.cornerRadius = buttonConfig.cornerRadius; 66 | self.baseButton.layer.borderColor = buttonConfig.borderColor.CGColor; 67 | self.baseButton.layer.borderWidth = buttonConfig.borderWidth; 68 | self.baseButton.layer.masksToBounds = YES; 69 | } else { 70 | UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.baseButton.bounds byRoundingCorners:buttonConfig.corners cornerRadii:CGSizeMake(buttonConfig.cornerRadius, buttonConfig.cornerRadius)]; 71 | 72 | CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; 73 | maskLayer.frame = self.bounds; 74 | maskLayer.path = maskPath.CGPath; 75 | 76 | CAShapeLayer *borderMaskLayer = [CAShapeLayer layer]; 77 | borderMaskLayer.path = maskPath.CGPath; 78 | borderMaskLayer.lineWidth = buttonConfig.borderWidth; 79 | borderMaskLayer.strokeColor = buttonConfig.borderColor.CGColor; 80 | borderMaskLayer.fillColor = [UIColor clearColor].CGColor; 81 | 82 | self.baseButton.layer.mask = maskLayer; 83 | [self.baseButton.layer addSublayer:borderMaskLayer]; 84 | } 85 | } 86 | 87 | [self addSubview:self.baseButton]; 88 | } 89 | 90 | return self; 91 | } 92 | 93 | - (void)setTag:(NSInteger)tag { 94 | self.baseButton.tag = tag; 95 | } 96 | 97 | - (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents { 98 | [self.baseButton addTarget:target action:action forControlEvents:controlEvents]; 99 | } 100 | 101 | - (void)showPointBadgeValue { 102 | [self setupBadgeValueType:JMBadgeValueTypePoint]; 103 | [self addSubview:self.bv]; 104 | } 105 | 106 | - (void)showNewBadgeValue { 107 | [self setupBadgeValueType:JMBadgeValueTypeNew]; 108 | [self addSubview:self.bv]; 109 | } 110 | 111 | - (void)showNumberBadgeValue:(NSString *)badgeValue { 112 | [self setupBadgeValueType:JMBadgeValueTypeNumber]; 113 | self.bv.badgeValue = badgeValue; 114 | [self addSubview:self.bv]; 115 | } 116 | 117 | - (void)setupBadgeValueType:(JMBadgeValueType)type { 118 | CGFloat badgeX = self.badgeOffset.x ? CGRectGetMaxX(self.bounds) - 10 + self.badgeOffset.x : CGRectGetMaxX(self.bounds) - 10; 119 | CGFloat badgeY = self.badgeOffset.y ? CGRectGetMinY(self.bounds) + self.badgeOffset.y : CGRectGetMinY(self.bounds); 120 | CGFloat badgeH = self.badgeSize.width ? self.badgeSize.width : 16; 121 | CGFloat badgeW = self.badgeSize.height ? self.badgeSize.height : 24; 122 | self.bv = [[JMBadgeValue alloc] initWithFrame:CGRectMake(badgeX, badgeY, badgeW, badgeH)]; 123 | self.bv.badgeL.font = self.badgeTextFont ? self.badgeTextFont : [UIFont systemFontOfSize:11.f]; 124 | self.bv.badgeL.textColor = self.badgeTextColor ? self.badgeTextColor : [UIColor whiteColor]; 125 | self.bv.badgeL.backgroundColor = self.badgeBackgroundColor ? self.badgeBackgroundColor : [UIColor colorWithHexString:@"#FF4040"]; 126 | self.bv.type = type; 127 | self.bv.animationType = self.badgeAnimationType; 128 | } 129 | 130 | - (void)setBadgeValue:(NSString *)badgeValue { 131 | _badgeValue = badgeValue; 132 | if (self.badgeAnimationType == JMBadgeValueTypeNumber) { 133 | self.bv.badgeValue = badgeValue; 134 | } 135 | } 136 | 137 | - (void)setBadgeRadius:(CGFloat)badgeRadius { 138 | _badgeRadius = badgeRadius; 139 | self.bv.badgeRadius = badgeRadius; 140 | } 141 | 142 | - (void)removeBadgeValue { 143 | [self.bv removeFromSuperview]; 144 | } 145 | 146 | - (void)showBadgeAnimation { 147 | [self.bv showAnimation]; 148 | } 149 | 150 | 151 | @end 152 | 153 | 154 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMButtons.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMButtons.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/19. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #ifndef JMButtons_h 10 | #define JMButtons_h 11 | 12 | #import "JMButton.h" 13 | #import "JMNumberButton.h" 14 | #import "JMRadioButton.h" 15 | #import "UIView+JM.h" 16 | #import "JMDefine.h" 17 | #import "UIColor+JM.h" 18 | #import "JMBaseButton+CountDown.h" 19 | 20 | 21 | #endif /* JMButtons_h */ 22 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMCategroy/JMBaseButton+CountDown.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMBaseButton+CountDown.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/17. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #import "JMBaseButton.h" 10 | 11 | @interface JMBaseButton (CountDown) 12 | /** 13 | 开始倒计时 14 | @param time 倒计时时间 15 | */ 16 | - (void)startCountDown:(int)time; 17 | 18 | /** 19 | 开始倒计时 20 | @param time 倒计时时间 21 | @param detail 文字描述 (默认是 **秒后重新获取) 22 | */ 23 | - (void)startCountDown:(int)time Detail:(NSString *)detail; 24 | 25 | 26 | /** 倒计时中背景颜色(默认 不设置) */ 27 | @property (nonatomic, strong) UIColor *countDownBackground; 28 | /** 倒计时完成后背景颜色 (默认 不设置) */ 29 | @property (nonatomic, strong) UIColor *countDownDoneBackground; 30 | /** 倒计时边框颜色 (默认 不设置) */ 31 | @property (nonatomic, strong) UIColor *countDownBorderColor; 32 | /** 倒计时完成后边框颜色 (默认 不设置) */ 33 | @property (nonatomic, strong) UIColor *countDownDoneBorderColor; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMCategroy/JMBaseButton+CountDown.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMBaseButton+CountDown.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/17. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #import "JMBaseButton+CountDown.h" 10 | #import 11 | 12 | static NSString *yasinTempText; 13 | static NSString *details; 14 | 15 | static const void *cdbKey = @"cdbKey"; 16 | static const void *cddbKey = @"cddbKey"; 17 | static const void *cdbwKey = @"cdbwKey"; 18 | static const void *cddbwKey = @"cddbwKey"; 19 | 20 | @implementation JMBaseButton (CountDown) 21 | 22 | - (UIColor *)countDownBackground { 23 | return objc_getAssociatedObject(self, cdbKey); 24 | } 25 | - (void)setCountDownBackground:(UIColor *)countDownBackground { 26 | objc_setAssociatedObject(self, cdbKey, countDownBackground, OBJC_ASSOCIATION_COPY_NONATOMIC); 27 | } 28 | - (UIColor *)countDownDoneBackground { 29 | return objc_getAssociatedObject(self, cddbKey); 30 | } 31 | - (void)setCountDownDoneBackground:(UIColor *)countDownDoneBackground{ 32 | objc_setAssociatedObject(self, cddbKey, countDownDoneBackground, OBJC_ASSOCIATION_COPY_NONATOMIC); 33 | } 34 | - (UIColor *)countDownBorderColor { 35 | return objc_getAssociatedObject(self, cdbwKey); 36 | } 37 | - (void)setCountDownBorderColor:(UIColor *)countDownBorderColor { 38 | objc_setAssociatedObject(self, cdbwKey, countDownBorderColor, OBJC_ASSOCIATION_COPY_NONATOMIC); 39 | } 40 | - (UIColor *)countDownDoneBorderColor { 41 | return objc_getAssociatedObject(self, cddbwKey); 42 | } 43 | - (void)setCountDownDoneBorderColor:(UIColor *)countDownDoneBorderColor { 44 | objc_setAssociatedObject(self, cddbwKey, countDownDoneBorderColor, OBJC_ASSOCIATION_COPY_NONATOMIC); 45 | } 46 | 47 | 48 | 49 | - (void)startCountDown:(int)time { 50 | [self initButtonData]; 51 | 52 | [self startTime:time]; 53 | } 54 | 55 | - (void)startCountDown:(int)time Detail:(NSString *)detail { 56 | details = detail; 57 | [self startCountDown:time]; 58 | } 59 | 60 | - (void)initButtonData{ 61 | 62 | yasinTempText = [NSString stringWithFormat:@"%@",self.titleLabel.text]; 63 | 64 | } 65 | 66 | - (void)startTime:(int)time{ 67 | 68 | __block int timeout = time; 69 | 70 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 71 | 72 | dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue); 73 | 74 | dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0 * NSEC_PER_SEC, 0); 75 | 76 | dispatch_source_set_event_handler(_timer, ^{ 77 | 78 | //倒计时结束 79 | if(timeout <= 0){ 80 | 81 | dispatch_source_cancel(_timer); 82 | 83 | dispatch_async(dispatch_get_main_queue(), ^{ 84 | 85 | [self setTitle:yasinTempText forState:UIControlStateNormal]; 86 | self.userInteractionEnabled = YES; 87 | 88 | }); 89 | 90 | }else{ 91 | 92 | dispatch_async(dispatch_get_main_queue(), ^{ 93 | if (details) { 94 | [self setTitle:[NSString stringWithFormat:@"%02d%@",timeout, details] forState:UIControlStateNormal]; 95 | } else { 96 | [self setTitle:[NSString stringWithFormat:@"%02d秒重新获取",timeout] forState:UIControlStateNormal]; 97 | } 98 | self.userInteractionEnabled = NO; 99 | 100 | }); 101 | 102 | timeout --; 103 | 104 | } 105 | 106 | }); 107 | 108 | dispatch_resume(_timer); 109 | 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMCategroy/JMDefine.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMDefine.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/8. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #ifndef JMDefine_h 10 | #define JMDefine_h 11 | 12 | //自定义log 13 | #ifdef DEBUG 14 | #define JMLog(...) NSLog(__VA_ARGS__) 15 | #else 16 | #define JMLog(...) 17 | #endif 18 | 19 | //随机颜色+RGB颜色+RBGA颜色+16进制颜色 20 | #define kRandomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0] 21 | 22 | // 判断是否是iPhone X 23 | #define kiPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO) 24 | // 状态栏高度 25 | #define kStatusBarHeight (kiPhoneX ? 44.f : 20.f) 26 | // 导航栏高度 27 | #define kNavigationBarHeight (kiPhoneX ? 88.f : 64.f) 28 | // tabBar高度 29 | #define kTabBarHeight (kiPhoneX ? (49.f+34.f) : 49.f) 30 | 31 | 32 | #endif /* JMDefine_h */ 33 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMCategroy/JMRuntime.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMRuntime.h 3 | // JMTabBarController 4 | // 5 | // Created by JM on 2017/12/26. 6 | // Copyright © 2017年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | #import 26 | #import "JMDefine.h" 27 | 28 | @interface JMRuntime : NSObject 29 | 30 | /** 31 | * 打印成员变量列表 32 | * className 类名称 33 | */ 34 | + (void)JM_runTimeConsoleMemberListWithClassName:(Class)className; 35 | 36 | /** 37 | * 打印属性列表 38 | * className 类名称 39 | */ 40 | + (void)JM_runTimeConsolePropertyListWithClassName:(Class)className; 41 | 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMCategroy/JMRuntime.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMRuntime.m 3 | // JMTabBarController 4 | // 5 | // Created by JM on 2017/12/26. 6 | // Copyright © 2017年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | 25 | #import "JMRuntime.h" 26 | 27 | @implementation JMRuntime 28 | 29 | /** 30 | * 打印成员变量列表 31 | * className 类名称 32 | */ 33 | + (void)JM_runTimeConsoleMemberListWithClassName:(Class)className { 34 | unsigned int outCount = 0; 35 | Ivar *ivars = class_copyIvarList(className, &outCount); 36 | for (unsigned int i = 0; i < outCount; i++) { 37 | Ivar ivar = ivars[i]; 38 | const char *name = ivar_getName(ivar); 39 | const char *type = ivar_getTypeEncoding(ivar); 40 | JMLog(@"类型为 %s 的 %s ",type, name); 41 | } 42 | free(ivars); 43 | } 44 | 45 | /** 46 | * 打印属性列表 47 | * className 类名称 48 | */ 49 | + (void)JM_runTimeConsolePropertyListWithClassName:(Class)className { 50 | unsigned int outCount = 0; 51 | objc_property_t * properties = class_copyPropertyList(className, &outCount); 52 | for (unsigned int i = 0; i < outCount; i ++) { 53 | objc_property_t property = properties[i]; 54 | //属性名 55 | const char * name = property_getName(property); 56 | //属性描述 57 | const char * propertyAttr = property_getAttributes(property); 58 | JMLog(@"属性描述为 %s 的 %s ", propertyAttr, name); 59 | 60 | //属性的特性 61 | unsigned int attrCount = 0; 62 | objc_property_attribute_t * attrs = property_copyAttributeList(property, &attrCount); 63 | for (unsigned int j = 0; j < attrCount; j ++) { 64 | objc_property_attribute_t attr = attrs[j]; 65 | const char * name = attr.name; 66 | const char * value = attr.value; 67 | JMLog(@"属性的描述:%s 值:%s", name, value); 68 | } 69 | free(attrs); 70 | JMLog(@"\n"); 71 | } 72 | free(properties); 73 | } 74 | 75 | @end 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMCategroy/UIColor+JM.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+JM.h 3 | // JMTabBarController 4 | // 5 | // Created by JM on 2017/12/27. 6 | // Copyright © 2017年 JM. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIColor (JM) 12 | 13 | //16进制颜色转换 14 | + (UIColor *)colorWithHexString:(NSString *)color; 15 | 16 | + (UIColor *)colorWithHexString:(NSString *)color Alpha:(CGFloat)alpha; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMCategroy/UIColor+JM.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+JM.m 3 | // JMTabBarController 4 | // 5 | // Created by JM on 2017/12/27. 6 | // Copyright © 2017年 JM. All rights reserved. 7 | // 8 | 9 | #import "UIColor+JM.h" 10 | 11 | @implementation UIColor (JM) 12 | 13 | 14 | + (UIColor *)colorWithHexString:(NSString *)color { 15 | return [self colorWithHexString:color Alpha:1.0f]; 16 | } 17 | 18 | + (UIColor *)colorWithHexString:(NSString *)color Alpha:(CGFloat)alpha { 19 | NSString *cString = [[color stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; 20 | if ([cString length] < 6) { 21 | return [UIColor clearColor]; 22 | } 23 | 24 | //判断前缀 25 | if ([cString hasPrefix:@"0X"]) { 26 | cString = [cString substringFromIndex:2]; 27 | } 28 | if ([cString hasPrefix:@"#"]) { 29 | cString = [cString substringFromIndex:1]; 30 | } 31 | if ([cString length] != 6) { 32 | return [UIColor clearColor]; 33 | } 34 | 35 | //从六位数值中找到RGB对应的位数并转换 36 | NSRange range; 37 | range.location = 0; 38 | range.length = 2; 39 | //R G B 40 | NSString *rString = [cString substringWithRange:range]; 41 | range.location = 2; 42 | NSString *gString = [cString substringWithRange:range]; 43 | range.location = 4; 44 | NSString *bString = [cString substringWithRange:range]; 45 | 46 | unsigned int r, g, b; 47 | [[NSScanner scannerWithString:rString] scanHexInt:&r]; 48 | [[NSScanner scannerWithString:gString] scanHexInt:&g]; 49 | [[NSScanner scannerWithString:bString] scanHexInt:&b]; 50 | 51 | return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:alpha]; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMCategroy/UIView+JM.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+JM.h 3 | // tool 4 | // 5 | // Created by JM on 16/10/25. 6 | // Copyright © 2016年 JM. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (JM) 12 | @property (nonatomic, assign) CGFloat x; 13 | @property (nonatomic, assign) CGFloat y; 14 | @property (nonatomic, assign) CGFloat width; 15 | @property (nonatomic, assign) CGFloat height; 16 | @property (nonatomic, assign) CGFloat centerX; 17 | @property (nonatomic, assign) CGFloat centerY; 18 | @property (nonatomic, assign) CGSize size; 19 | @end 20 | -------------------------------------------------------------------------------- /JMButton/JMButton/JMCategroy/UIView+JM.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+JM.m 3 | // tool 4 | // 5 | // Created by JM on 16/10/25. 6 | // Copyright © 2016年 JM. All rights reserved. 7 | // 8 | 9 | #import "UIView+JM.h" 10 | 11 | @implementation UIView (JM) 12 | - (void)setX:(CGFloat)x 13 | { 14 | CGRect frame = self.frame; 15 | frame.origin.x = x; 16 | self.frame = frame; 17 | } 18 | 19 | - (CGFloat)x 20 | { 21 | return self.frame.origin.x; 22 | } 23 | 24 | - (void)setY:(CGFloat)y 25 | { 26 | CGRect frame = self.frame; 27 | frame.origin.y = y; 28 | self.frame = frame; 29 | } 30 | 31 | - (CGFloat)y 32 | { 33 | return self.frame.origin.y; 34 | } 35 | 36 | - (void)setWidth:(CGFloat)width 37 | { 38 | CGRect frame = self.frame; 39 | frame.size.width = width; 40 | self.frame = frame; 41 | } 42 | 43 | - (CGFloat)width 44 | { 45 | return self.frame.size.width; 46 | } 47 | 48 | - (void)setHeight:(CGFloat)height 49 | { 50 | CGRect frame = self.frame; 51 | frame.size.height = height; 52 | self.frame = frame; 53 | } 54 | 55 | - (CGFloat)height 56 | { 57 | return self.frame.size.height; 58 | } 59 | 60 | - (void)setSize:(CGSize)size 61 | { 62 | CGRect frame = self.frame; 63 | frame.size = size; 64 | self.frame = frame; 65 | } 66 | 67 | - (CGSize)size 68 | { 69 | return self.frame.size; 70 | } 71 | 72 | - (void)setCenterX:(CGFloat)centerX 73 | { 74 | CGPoint center = self.center; 75 | center.x = centerX; 76 | self.center = center; 77 | } 78 | 79 | - (CGFloat)centerX 80 | { 81 | return self.center.x; 82 | } 83 | 84 | - (void)setCenterY:(CGFloat)centerY 85 | { 86 | CGPoint center = self.center; 87 | center.y = centerY; 88 | self.center = center; 89 | } 90 | 91 | - (CGFloat)centerY 92 | { 93 | return self.center.y; 94 | } 95 | @end 96 | -------------------------------------------------------------------------------- /JMButton/JMButton/NumberButton/JMNumberButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMNumberButton.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/18. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMButton.h" 25 | #import "JMBaseButton.h" 26 | @class JMNumberButton; 27 | 28 | @protocol JMNumberButtonDelegate 29 | 30 | /** 31 | JMNumberButtonDelegate 32 | @param numberButton 当前按钮 33 | @param number 当前的数据 34 | */ 35 | - (void)numberButton:(JMNumberButton *)numberButton Number:(NSInteger)number; 36 | 37 | @end 38 | 39 | @interface JMNumberButton : JMButton 40 | 41 | /** 代理 */ 42 | @property (nonatomic, weak) id delegate; 43 | 44 | @end 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /JMButton/JMButton/NumberButton/JMNumberButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMNumberButton.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/18. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMNumberButton.h" 25 | #import "UIColor+JM.h" 26 | #import "UIView+JM.h" 27 | 28 | @interface JMNumberButton() 29 | 30 | @property (nonatomic, strong) UIButton *decreaseBtn; 31 | @property (nonatomic, strong) UIButton *increaseBtn; 32 | @property (nonatomic, strong) UITextField *textField; 33 | /** 线1 */ 34 | @property (nonatomic, strong) UIImageView *line1; 35 | /** 线2 */ 36 | @property (nonatomic, strong) UIImageView *line2; 37 | /** config */ 38 | @property (nonatomic, strong) JMNumberButtonConfig *config; 39 | 40 | @end; 41 | 42 | @implementation JMNumberButton 43 | 44 | - (instancetype)initWithFrame:(CGRect)frame NumberButtonConfig:(JMNumberButtonConfig *)numberButtonConfig { 45 | if (self = [super initWithFrame:frame NumberButtonConfig:numberButtonConfig]) { 46 | self.layer.masksToBounds = YES; 47 | self.layer.cornerRadius = numberButtonConfig.cornerRadius; 48 | 49 | self.config = numberButtonConfig; 50 | [self setupUI]; 51 | 52 | if (self.config.borderLineWidth) { 53 | [self setupLine]; 54 | } 55 | [self setupStyle]; 56 | 57 | } 58 | return self; 59 | } 60 | 61 | #pragma mark - 设置样式 62 | - (void)setupStyle { 63 | if (self.config.numberButtonType == JMNumberButtonTypeNormal) { 64 | 65 | } else if (self.config.numberButtonType == JMNumberButtonTypeTaoBao) { 66 | self.config.borderLineWidth = 3.f; 67 | self.config.borderLineColor = [UIColor whiteColor]; 68 | 69 | [self setupLine]; 70 | 71 | self.decreaseBtn.backgroundColor = [UIColor colorWithHexString:@"#F4F4F4"]; 72 | self.textField.backgroundColor = [UIColor colorWithHexString:@"#F4F4F4"]; 73 | self.increaseBtn.backgroundColor = [UIColor colorWithHexString:@"#F4F4F4"]; 74 | 75 | self.layer.borderWidth = 0.f; 76 | } else if (self.config.numberButtonType == JMNumberButtonTypeJingDong) { 77 | self.config.borderLineWidth = 1.f; 78 | self.config.borderLineColor = [UIColor colorWithHexString:@"#888888"]; 79 | 80 | [self setupLine]; 81 | } else if (self.config.numberButtonType == JMNumberButtonTypeMeiTuan) { 82 | CGFloat cornerRadius = 0.f; 83 | if (self.decreaseBtn.width > self.decreaseBtn.height) { 84 | self.decreaseBtn.width = self.decreaseBtn.height; 85 | self.increaseBtn.width = self.increaseBtn.height; 86 | self.decreaseBtn.y = self.height * 0.5 - self.decreaseBtn.height * 0.5; 87 | self.increaseBtn.y = self.height * 0.5 - self.increaseBtn.height * 0.5; 88 | self.increaseBtn.x = self.width - self.increaseBtn.width; 89 | self.decreaseBtn.x = self.increaseBtn.x; 90 | cornerRadius = self.decreaseBtn.width * 0.5; 91 | } else if (self.decreaseBtn.height > self.decreaseBtn.width) { 92 | self.decreaseBtn.height = self.decreaseBtn.width; 93 | self.increaseBtn.height = self.increaseBtn.width; 94 | self.decreaseBtn.y = self.height * 0.5 - self.decreaseBtn.height * 0.5; 95 | self.increaseBtn.y = self.height * 0.5 - self.increaseBtn.height * 0.5; 96 | self.decreaseBtn.x = self.increaseBtn.x; 97 | cornerRadius = self.decreaseBtn.height * 0.5; 98 | } 99 | 100 | self.decreaseBtn.layer.cornerRadius = cornerRadius; 101 | self.decreaseBtn.layer.masksToBounds = YES; 102 | self.increaseBtn.layer.cornerRadius = cornerRadius; 103 | self.increaseBtn.layer.masksToBounds = YES; 104 | 105 | self.decreaseBtn.backgroundColor = [UIColor whiteColor]; 106 | self.decreaseBtn.layer.borderColor = [UIColor colorWithHexString:@"#3c8dbc"].CGColor; 107 | self.decreaseBtn.layer.borderWidth = 1.f; 108 | [self.decreaseBtn setTitleColor:[UIColor colorWithHexString:@"#3c8dbc"] forState:UIControlStateNormal]; 109 | 110 | self.increaseBtn.backgroundColor = [UIColor colorWithHexString:@"#3c8dbc"]; 111 | [self.increaseBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 112 | 113 | self.textField.backgroundColor = [UIColor clearColor]; 114 | self.textField.alpha = 0.f; 115 | } 116 | } 117 | 118 | #pragma mark - 初始化线条 119 | - (void)setupLine { 120 | [self.line1 removeFromSuperview]; 121 | [self.line2 removeFromSuperview]; 122 | 123 | self.line1 = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.decreaseBtn.frame) - self.config.borderLineWidth * 0.5, 0, self.config.borderLineWidth, self.height)]; 124 | self.line1.backgroundColor = self.config.borderLineColor; 125 | [self addSubview:self.line1]; 126 | 127 | self.line2 = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.textField.frame) - self.config.borderLineWidth, 0, self.config.borderLineWidth, self.height)]; 128 | self.line2.backgroundColor = self.config.borderLineColor; 129 | [self addSubview:self.line2]; 130 | 131 | self.layer.borderColor = self.config.borderLineColor.CGColor; 132 | self.layer.borderWidth = self.config.borderLineWidth; 133 | } 134 | 135 | #pragma mark - 设置UI 136 | - (void)setupUI { 137 | self.decreaseBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 138 | self.decreaseBtn.frame = CGRectMake(0, 0, self.width * 0.3, self.height); 139 | [self.decreaseBtn setTitle:self.config.decreaseTitle forState:UIControlStateNormal]; 140 | [self.decreaseBtn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; 141 | self.decreaseBtn.backgroundColor = self.config.decreaseBackgroundColor; 142 | [self.decreaseBtn setBackgroundImage:self.config.decreaseBackgroundImage forState:UIControlStateNormal]; 143 | self.decreaseBtn.titleLabel.font = self.config.buttonTitleFont; 144 | self.decreaseBtn.contentEdgeInsets = self.config.decreaseContentEdgeInsets; 145 | [self.decreaseBtn addTarget:self action:@selector(decreaseBtnClick) forControlEvents:UIControlEventTouchUpInside]; 146 | [self addSubview:self.decreaseBtn]; 147 | 148 | self.increaseBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 149 | self.increaseBtn.frame = CGRectMake(self.width - self.width * 0.3, 0, self.decreaseBtn.width, self.decreaseBtn.height); 150 | [self.increaseBtn setTitle:self.config.increaseTitle forState:UIControlStateNormal]; 151 | [self.increaseBtn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; 152 | self.increaseBtn.backgroundColor = self.config.increaseBackgroundColor; 153 | [self.increaseBtn setBackgroundImage:self.config.increaseBackgroundImage forState:UIControlStateNormal]; 154 | self.increaseBtn.titleLabel.font = self.config.buttonTitleFont; 155 | self.increaseBtn.contentEdgeInsets = self.config.increaseContentEdgeInsets; 156 | [self.increaseBtn addTarget:self action:@selector(increaseBtnClick) forControlEvents:UIControlEventTouchUpInside]; 157 | [self addSubview:self.increaseBtn]; 158 | 159 | self.textField = [[UITextField alloc] initWithFrame:CGRectMake(self.width * 0.3, 0, self.width * 0.4, self.height)]; 160 | self.textField.keyboardType = UIKeyboardTypeNumberPad; 161 | self.textField.font = self.config.inputFont; 162 | self.textField.text = [NSString stringWithFormat:@"%zd",self.config.currentNumber]; 163 | self.textField.textAlignment = NSTextAlignmentCenter; 164 | self.textField.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; 165 | self.textField.backgroundColor = [UIColor whiteColor]; 166 | [self.textField addTarget:self action:@selector(textFieldValueChange:) forControlEvents:UIControlEventEditingChanged]; 167 | self.textField.enabled = self.config.isInput; 168 | [self addSubview:self.textField]; 169 | } 170 | 171 | #pragma mark - 减号按钮事件 172 | - (void)decreaseBtnClick { 173 | NSInteger curValue = [self.textField.text integerValue]; 174 | curValue--; 175 | if (curValue < self.config.minNumber) { 176 | curValue++; 177 | if (self.config.shakeAnimation) { 178 | [self shakeAnimation]; 179 | } 180 | } 181 | self.textField.text = [NSString stringWithFormat:@"%zd",curValue]; 182 | if ([self.delegate respondsToSelector:@selector(numberButton:Number:)]) { 183 | [self.delegate numberButton:self Number:curValue]; 184 | } 185 | } 186 | 187 | #pragma mark - 加号按钮事件 188 | - (void)increaseBtnClick { 189 | if (self.textField.alpha == 0) { 190 | [self rotationAnimation]; 191 | [UIView animateWithDuration:.3f animations:^{ 192 | self.decreaseBtn.x = 0; 193 | self.textField.alpha = 0.2f; 194 | [UIView animateWithDuration:.3f animations:^{ 195 | self.textField.alpha = 1.f; 196 | }]; 197 | }]; 198 | 199 | return; 200 | } 201 | 202 | NSInteger curValue = [self.textField.text integerValue]; 203 | curValue++; 204 | if (curValue > self.config.maxNumber) { 205 | curValue--; 206 | if (self.config.shakeAnimation) { 207 | [self shakeAnimation]; 208 | } 209 | } 210 | self.textField.text = [NSString stringWithFormat:@"%zd",curValue]; 211 | if ([self.delegate respondsToSelector:@selector(numberButton:Number:)]) { 212 | [self.delegate numberButton:self Number:curValue]; 213 | } 214 | } 215 | 216 | #pragma mark - 输入框的值改变 217 | - (void)textFieldValueChange:(UITextField *)tf { 218 | if ([tf.text isEqualToString:@""]) { 219 | tf.text = [NSString stringWithFormat:@"%zd",self.config.minNumber]; 220 | } 221 | 222 | if ([[tf.text substringToIndex:1] isEqualToString:@"0"] && tf.text.length > 1) { 223 | tf.text = [tf.text substringWithRange:NSMakeRange(1, tf.text.length - 1)]; 224 | } 225 | 226 | if ([tf.text integerValue] > self.config.maxNumber) { 227 | tf.text = [NSString stringWithFormat:@"%zd",self.config.maxNumber]; 228 | } 229 | 230 | if ([self.delegate respondsToSelector:@selector(numberButton:Number:)]) { 231 | [self.delegate numberButton:self Number:[tf.text integerValue]]; 232 | } 233 | } 234 | 235 | #pragma mark - 核心动画 236 | // 抖动动画 237 | - (void)shakeAnimation 238 | { 239 | CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"]; 240 | CGFloat positionX = self.layer.position.x; 241 | animation.values = @[@(positionX-10),@(positionX),@(positionX+10)]; 242 | animation.repeatCount = 3; 243 | animation.duration = 0.07; 244 | animation.autoreverses = YES; 245 | [self.layer addAnimation:animation forKey:nil]; 246 | } 247 | 248 | // 旋转动画 249 | - (void)rotationAnimation 250 | { 251 | CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; 252 | rotationAnimation.toValue = @(M_PI*2); 253 | rotationAnimation.repeatCount = 2; 254 | rotationAnimation.duration = 0.3f; 255 | rotationAnimation.fillMode = kCAFillModeForwards; 256 | rotationAnimation.removedOnCompletion = NO; 257 | [self.decreaseBtn.layer addAnimation:rotationAnimation forKey:nil]; 258 | 259 | 260 | CABasicAnimation *rotationAnimation1 = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; 261 | rotationAnimation1.toValue = @(M_PI*2); 262 | rotationAnimation1.duration = 0.3f; 263 | rotationAnimation1.fillMode = kCAFillModeForwards; 264 | rotationAnimation1.removedOnCompletion = NO; 265 | [self.increaseBtn.layer addAnimation:rotationAnimation1 forKey:nil]; 266 | 267 | CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"opacity"]; 268 | // anima.fromValue = [NSNumber numberWithFloat:0.1f]; 269 | anima.toValue = [NSNumber numberWithFloat:0]; 270 | // anima.repeatCount = 1; 271 | anima.duration = 0.3f; 272 | anima.autoreverses = YES; 273 | anima.fillMode = kCAFillModeForwards; 274 | anima.removedOnCompletion = NO; 275 | [self.textField.layer addAnimation:anima forKey:@"opacity"]; 276 | } 277 | 278 | 279 | @end 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | -------------------------------------------------------------------------------- /JMButton/JMButton/NumberButton/JMNumberButtonConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMNumberButtonConfig.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/18. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | 25 | #import 26 | #import 27 | 28 | typedef NS_ENUM(NSInteger, JMNumberButtonType) { 29 | JMNumberButtonTypeNormal, //默认样式 30 | JMNumberButtonTypeTaoBao, //仿淘宝样式 31 | JMNumberButtonTypeJingDong, //仿京东样式 32 | JMNumberButtonTypeMeiTuan, //仿美团 饿了吗 百度外卖 样式 33 | }; 34 | 35 | @interface JMNumberButtonConfig : NSObject 36 | 37 | /** 初始化 */ 38 | + (instancetype)buttonConfig; 39 | 40 | /********************* 样式配置 *********************/ 41 | /** 样式 */ 42 | @property (nonatomic, assign) JMNumberButtonType numberButtonType; 43 | /** 是否开启抖动动画 (默认 NO) */ 44 | @property (nonatomic, assign) BOOL shakeAnimation; 45 | 46 | 47 | /********************* 输入框配置 *********************/ 48 | /** 输入框中的内容 (默认 1) */ 49 | @property (nonatomic, assign) NSInteger currentNumber; 50 | /** 输入框中字体大小 (默认 20.f )*/ 51 | @property (nonatomic, strong) UIFont *inputFont; 52 | /** 输入框是否可输入 (默认 YES) */ 53 | @property (nonatomic, assign) BOOL isInput; 54 | /** 边框线条宽度 (默认 0 0的话不会展示) */ 55 | @property (nonatomic, assign) CGFloat borderLineWidth; 56 | /** 边框线条颜色 (默认 #eeeeee) */ 57 | @property (nonatomic, strong) UIColor *borderLineColor; 58 | /** 圆角值 ( 默认 3.f 如果设置了numberButtonType, 圆角值将无效 ) */ 59 | @property (nonatomic, assign) CGFloat cornerRadius; 60 | 61 | 62 | /********************* 按钮配置 *********************/ 63 | /** 加减按钮字体大小 (默认 30.f) */ 64 | @property (nonatomic, strong) UIFont *buttonTitleFont; 65 | /** 加按钮背景颜色 (默认 #FFFFFF) */ 66 | @property (nonatomic, strong) UIColor *increaseBackgroundColor; 67 | /** 减按钮背景颜色 (默认 #FFFFFF)*/ 68 | @property (nonatomic, strong) UIColor *decreaseBackgroundColor; 69 | /** 加按钮背景图片 (默认 nil 图片的设置优先级高于背景颜色) */ 70 | @property (nonatomic, strong) UIImage *increaseBackgroundImage; 71 | /** 减按钮背景图片 (默认 nil) */ 72 | @property (nonatomic, strong) UIImage *decreaseBackgroundImage; 73 | /** 加按钮标题 (默认 +) */ 74 | @property (nonatomic, strong) NSString *increaseTitle; 75 | /** 减按钮标题 (默认 -) */ 76 | @property (nonatomic, strong) NSString *decreaseTitle; 77 | /** 加按钮contentEdgeInsets (默认 0, 0, 3, 0) */ 78 | @property (nonatomic, assign) UIEdgeInsets increaseContentEdgeInsets; 79 | /** 减按钮contentEdgeInsets (默认 0, 0, 3, 0) */ 80 | @property (nonatomic, assign) UIEdgeInsets decreaseContentEdgeInsets; 81 | 82 | 83 | /********************* 其他配置 *********************/ 84 | /** 最小值 (默认 1)*/ 85 | @property (nonatomic, assign) NSInteger minNumber; 86 | /** 最大值 (默认 无限制)*/ 87 | @property (nonatomic, assign) NSInteger maxNumber; 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /JMButton/JMButton/NumberButton/JMNumberButtonConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMNumberButtonConfig.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/18. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | 25 | #import "JMNumberButtonConfig.h" 26 | #import "UIColor+JM.h" 27 | 28 | @implementation JMNumberButtonConfig 29 | 30 | - (instancetype)init { 31 | if (self = [super init]) { 32 | _currentNumber = 1; 33 | _minNumber = 1; 34 | _maxNumber = MAXFLOAT; 35 | _inputFont = [UIFont systemFontOfSize:20.f]; 36 | _buttonTitleFont = [UIFont systemFontOfSize:30.f]; 37 | _numberButtonType = JMNumberButtonTypeNormal; 38 | _isInput = YES; 39 | _increaseTitle = @"+"; 40 | _decreaseTitle = @"-"; 41 | _increaseBackgroundColor = [UIColor colorWithHexString:@"#FFFFFF"]; 42 | _decreaseBackgroundColor = [UIColor colorWithHexString:@"#FFFFFF"]; 43 | _increaseBackgroundImage = [UIImage new]; 44 | _decreaseBackgroundImage = [UIImage new]; 45 | _borderLineWidth = 0.f; 46 | _borderLineColor = [UIColor colorWithHexString:@"#eeeeee"]; 47 | _cornerRadius = 3.f; 48 | _shakeAnimation = NO; 49 | _increaseContentEdgeInsets = UIEdgeInsetsMake(0, 0, 3, 0); 50 | _decreaseContentEdgeInsets = UIEdgeInsetsMake(0, 0, 3, 0); 51 | } 52 | return self; 53 | } 54 | 55 | + (instancetype)buttonConfig { 56 | return [[self alloc] init]; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /JMButton/JMButton/RadioButton/JMRadioButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMRadioButton.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/27. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #import "JMButton.h" 10 | 11 | @interface JMRadioButton : JMButton 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /JMButton/JMButton/RadioButton/JMRadioButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMRadioButton.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/27. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #import "JMRadioButton.h" 10 | 11 | @implementation JMRadioButton 12 | 13 | - (instancetype)initWithFrame:(CGRect)frame { 14 | if (self = [super initWithFrame:frame]) { 15 | 16 | } 17 | return self; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /JMButton/JMButton/WaveButton/JMWaveButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMWaveButton.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/23. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMBootstrapButton.h" 25 | #import "JMWaveButtonConfig.h" 26 | 27 | @interface JMWaveButton : JMBootstrapButton 28 | 29 | @end 30 | 31 | 32 | -------------------------------------------------------------------------------- /JMButton/JMButton/WaveButton/JMWaveButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMWaveButton.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/23. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMWaveButton.h" 25 | //#import "JMWaveButtonConfig.m" 26 | 27 | 28 | @interface JMButtonCircleSet : NSObject 29 | 30 | @property CGFloat circleCenterX; 31 | @property CGFloat circleCenterY; 32 | @property CGFloat circleWidth; 33 | @property CGFloat circleRait; 34 | 35 | @end 36 | 37 | @implementation JMButtonCircleSet 38 | 39 | @end 40 | 41 | @interface JMWaveButton() 42 | 43 | @property (nonatomic, assign) int loopCount; 44 | @property (nonatomic, strong) NSMutableDictionary *circles; 45 | @property (nonatomic, assign) int circleFlag; 46 | @property (nonatomic, strong) JMWaveButtonConfig *config; 47 | 48 | @end 49 | 50 | @implementation JMWaveButton 51 | 52 | + (instancetype)buttonFrame:(CGRect)frame ButtonConfig:(JMWaveButtonConfig *)buttonConfig { 53 | return [[self alloc] initWithFrame:frame ButtonConfig:buttonConfig]; 54 | } 55 | 56 | - (instancetype)initWithFrame:(CGRect)frame ButtonConfig:(JMWaveButtonConfig *)buttonConfig { 57 | if (self = [super initWithFrame:frame ButtonConfig:buttonConfig]) { 58 | self.config = buttonConfig; 59 | 60 | self.config.AnimationDuration = 1; 61 | self.loopCount = self.config.AnimationDuration / 0.02; 62 | 63 | self.circles = [NSMutableDictionary dictionary]; 64 | self.circleFlag = 0; 65 | 66 | [self addTarget:self action:@selector(touchedDown:event:) forControlEvents:UIControlEventTouchDown]; 67 | } 68 | return self; 69 | } 70 | 71 | -(void)touchedDown:(UIButton *)btn event:(UIEvent *)event{ 72 | 73 | UITouch *touch = event.allTouches.allObjects.firstObject; 74 | CGPoint touchePoint = [touch locationInView:btn]; 75 | 76 | NSString *key = [NSString stringWithFormat:@"%d",self.circleFlag]; 77 | JMButtonCircleSet *set = [JMButtonCircleSet new]; 78 | set.circleCenterX = touchePoint.x; 79 | set.circleCenterY = touchePoint.y; 80 | set.circleRait = 0; 81 | 82 | CGFloat maxX = touchePoint.x>(self.frame.size.width-touchePoint.x)?touchePoint.x:(self.frame.size.width-touchePoint.x); 83 | CGFloat maxY = touchePoint.y>(self.frame.size.width-touchePoint.y)?touchePoint.y:(self.frame.size.height-touchePoint.y); 84 | set.circleWidth = maxX>maxY?maxX:maxY; 85 | 86 | [self.circles setObject:set forKey:key]; 87 | 88 | NSTimer *timer = [NSTimer timerWithTimeInterval:0.01 89 | target:self 90 | selector:@selector(TimerFunction:) 91 | userInfo:@{@"key":key} 92 | repeats:YES]; 93 | 94 | [NSRunLoop.mainRunLoop addTimer:timer forMode:NSRunLoopCommonModes]; 95 | 96 | self.circleFlag++; 97 | } 98 | 99 | -(void)TimerFunction:(NSTimer *)timer{ 100 | 101 | [self setNeedsDisplay]; 102 | 103 | NSDictionary *userInfo = timer.userInfo; 104 | 105 | NSString *key = userInfo[@"key"]; 106 | 107 | JMButtonCircleSet *set = self.circles[key]; 108 | 109 | if(set.circleRait<=1){ 110 | 111 | set.circleRait += (1.0/self.loopCount); 112 | 113 | }else{ 114 | [self.circles removeObjectForKey:key]; 115 | 116 | [timer invalidate]; 117 | } 118 | } 119 | 120 | -(void)drawRect:(CGRect)rect{ 121 | 122 | CGContextRef context = UIGraphicsGetCurrentContext(); 123 | 124 | CGFloat endAngle = M_PI * 2; 125 | 126 | for (JMButtonCircleSet *circleSet in self.circles.allValues) { 127 | CGContextAddArc(context, 128 | circleSet.circleCenterX, 129 | circleSet.circleCenterY, 130 | circleSet.circleWidth * circleSet.circleRait, 131 | 0, 132 | endAngle, 133 | NO); 134 | 135 | [[self.config.highlightedColor colorWithAlphaComponent:(1-circleSet.circleRait)] setStroke]; 136 | [[self.config.highlightedColor colorWithAlphaComponent:(1-circleSet.circleRait)] setFill]; 137 | 138 | CGContextFillPath(context); 139 | } 140 | } 141 | 142 | 143 | @end 144 | -------------------------------------------------------------------------------- /JMButton/JMButton/WaveButton/JMWaveButtonConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMWaveButtonConfig.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/23. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | 25 | #import "JMBootstrapButtonConfig.h" 26 | 27 | @interface JMWaveButtonConfig : JMBootstrapButtonConfig 28 | 29 | //动画时间,默认为1秒 30 | @property (nonatomic, assign) NSTimeInterval AnimationDuration; 31 | //动画颜色 (默认 橙色) 32 | @property (nonatomic, strong) UIColor *highlightedColor; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /JMButton/JMButton/WaveButton/JMWaveButtonConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMWaveButtonConfig.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/23. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | 25 | #import "JMWaveButtonConfig.h" 26 | 27 | @implementation JMWaveButtonConfig 28 | 29 | - (instancetype)init { 30 | if (self = [super init]) { 31 | _highlightedColor = [UIColor clearColor]; 32 | } 33 | return self; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /JMButton/JMCountDownViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMCountDownViewController.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/17. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | 26 | @interface JMCountDownViewController : UIViewController 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JMButton/JMCountDownViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMCountDownViewController.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/17. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMCountDownViewController.h" 25 | #import "JMButtons.h" 26 | 27 | @interface JMCountDownViewController () 28 | 29 | /** sv */ 30 | @property (nonatomic, strong) UIScrollView *scrollView; 31 | 32 | @end 33 | 34 | @implementation JMCountDownViewController 35 | 36 | 37 | - (void)viewDidLoad { 38 | [super viewDidLoad]; 39 | self.view.backgroundColor = [UIColor whiteColor]; 40 | self.title = @"按钮倒计时功能"; 41 | 42 | self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, kNavigationBarHeight, self.view.width, self.view.height - kNavigationBarHeight)]; 43 | self.automaticallyAdjustsScrollViewInsets = NO; 44 | [self.view addSubview:self.scrollView]; 45 | 46 | 47 | CGFloat W = (self.view.width - 60) / 3; 48 | CGFloat H = 60; 49 | NSInteger rank = 3; 50 | CGFloat rankMargin = (self.view.frame.size.width - rank * W) / (rank); 51 | CGFloat rowMargin = 10; 52 | 53 | CGFloat lastY = 0; 54 | 55 | for (int i = 0; i < 1; i++) { 56 | JMBootstrapButtonConfig *buttonConfig = [JMBootstrapButtonConfig buttonConfig]; 57 | if (i == 0) { 58 | buttonConfig.title = @"Info"; 59 | buttonConfig.bootstrapType = JMBootstrapTypeInfo; 60 | } 61 | 62 | CGFloat X = (i % rank) * (W + rankMargin) + 10; 63 | NSUInteger Y = (i / rank) * (H +rowMargin); 64 | 65 | JMButton *btn = [[JMButton alloc] initWithFrame:CGRectMake(X, Y + 10, W, H) ButtonConfig:buttonConfig]; 66 | btn.tag = i; 67 | [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; 68 | [self.scrollView addSubview:btn]; 69 | 70 | 71 | lastY = Y + H; 72 | } 73 | 74 | self.scrollView.contentSize = CGSizeMake(0, lastY); 75 | } 76 | 77 | - (void)btnClick:(JMButton *)sender { 78 | JMLog(@"点击了第 %zd 个", sender.tag); 79 | 80 | //开始倒计时核心代码 81 | JMBootstrapButton *bsBtn = (JMBootstrapButton*)sender; 82 | [bsBtn startCountDown:6]; 83 | // [bsBtn startCountDown:5 Detail:@"哈哈"]; 84 | // bsBtn.countDownBackground = [UIColor redColor]; 85 | // bsBtn.countDownBorderColor = [UIColor blueColor]; 86 | // bsBtn.countDownDoneBackground = [UIColor orangeColor]; 87 | // bsBtn.countDownDoneBorderColor = [UIColor greenColor]; 88 | } 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /JMButton/JMCustomViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMCustomViewController.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/17. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | 26 | @interface JMCustomViewController : UIViewController 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JMButton/JMCustomViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMCustomViewController.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/17. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMCustomViewController.h" 25 | #import "JMButtons.h" 26 | 27 | @interface JMCustomViewController () 28 | 29 | @end 30 | 31 | @implementation JMCustomViewController 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | 36 | self.view.backgroundColor = [UIColor whiteColor]; 37 | self.title = @"自定义View"; 38 | 39 | 40 | UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 280, 100)]; 41 | customView.backgroundColor = [UIColor redColor]; 42 | 43 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 100, 20)]; 44 | label.text = @"我是的label"; 45 | label.backgroundColor = [UIColor greenColor]; 46 | [customView addSubview:label]; 47 | 48 | UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; 49 | [btn setTitle:@"我是按钮, 点我吧" forState:UIControlStateNormal]; 50 | [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 51 | btn.backgroundColor = [UIColor blackColor]; 52 | btn.frame = CGRectMake(10, 40, 260, 50); 53 | [btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside]; 54 | [customView addSubview:btn]; 55 | 56 | 57 | JMButton *customBtn = [[JMButton alloc] initWithFrame:CGRectMake(50, 100, 300, 120) CustomView:customView]; 58 | customBtn.backgroundColor = [UIColor orangeColor]; 59 | [self.view addSubview:customBtn]; 60 | 61 | 62 | // JMButton *customBtn1 = [JMButton alloc] initWithFrame:CGRectMake(50, 500, 80, 40) CustomView:<#(UIView *)#> 63 | 64 | 65 | 66 | } 67 | 68 | - (void)btnClick { 69 | NSLog(@"我被点击了-.-"); 70 | } 71 | 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /JMButton/JMNumberViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMNumberViewController.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/18. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | 26 | @interface JMNumberViewController : UIViewController 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JMButton/JMNumberViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMNumberViewController.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/18. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMNumberViewController.h" 25 | #import "JMButtons.h" 26 | 27 | @interface JMNumberViewController () 28 | 29 | @end 30 | 31 | @implementation JMNumberViewController 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | // self.view.backgroundColor = [UIColor colorWithHexString:@"#f4f4f4"]; 36 | self.view.backgroundColor = [UIColor orangeColor]; 37 | self.title = @"高度自定制计数器按钮"; 38 | 39 | 40 | //默认样式 41 | JMNumberButtonConfig *buttonConfig = [JMNumberButtonConfig buttonConfig]; 42 | buttonConfig.shakeAnimation = YES; 43 | JMNumberButton *numberBtn = [[JMNumberButton alloc] initWithFrame:CGRectMake(50, 100, 120, 40) NumberButtonConfig:buttonConfig]; 44 | [self.view addSubview:numberBtn]; 45 | 46 | //自定义样式 47 | JMNumberButtonConfig *buttonConfig1 = [JMNumberButtonConfig buttonConfig]; 48 | buttonConfig1.currentNumber = 2; 49 | buttonConfig1.minNumber = 0; 50 | buttonConfig1.maxNumber = 10; 51 | // buttonConfig1.isInput = NO; 52 | buttonConfig1.increaseBackgroundColor = [UIColor redColor]; 53 | buttonConfig1.decreaseBackgroundColor = [UIColor greenColor]; 54 | buttonConfig1.borderLineWidth = 2.f; 55 | buttonConfig1.borderLineColor = [UIColor blueColor]; 56 | JMNumberButton *numberBtn1 = [[JMNumberButton alloc] initWithFrame:CGRectMake(50, 160, 120, 36) NumberButtonConfig:buttonConfig1]; 57 | [self.view addSubview:numberBtn1]; 58 | 59 | //仿淘宝样式 60 | JMNumberButtonConfig *buttonConfig2 = [JMNumberButtonConfig buttonConfig]; 61 | buttonConfig2.numberButtonType = JMNumberButtonTypeTaoBao; 62 | JMNumberButton *numberBtn2 = [[JMNumberButton alloc] initWithFrame:CGRectMake(50, 220, 120, 40) NumberButtonConfig:buttonConfig2]; 63 | [self.view addSubview:numberBtn2]; 64 | 65 | 66 | //仿京东样式 67 | JMNumberButtonConfig *buttonConfig3 = [JMNumberButtonConfig buttonConfig]; 68 | buttonConfig3.numberButtonType = JMNumberButtonTypeJingDong; 69 | JMNumberButton *numberBtn3 = [[JMNumberButton alloc] initWithFrame:CGRectMake(50, 280, 120, 40) NumberButtonConfig:buttonConfig3]; 70 | [self.view addSubview:numberBtn3]; 71 | 72 | 73 | //仿美团 饿了吗 百度外卖样式 74 | JMNumberButtonConfig *buttonConfig4 = [JMNumberButtonConfig buttonConfig]; 75 | buttonConfig4.numberButtonType = JMNumberButtonTypeMeiTuan; 76 | JMNumberButton *numberBtn4 = [[JMNumberButton alloc] initWithFrame:CGRectMake(50, 340, 120, 30) NumberButtonConfig:buttonConfig4]; 77 | [self.view addSubview:numberBtn4]; 78 | 79 | 80 | //遵守代理 81 | numberBtn.delegate = self; 82 | numberBtn1.delegate = self; 83 | numberBtn2.delegate = self; 84 | numberBtn3.delegate = self; 85 | numberBtn4.delegate = self; 86 | } 87 | 88 | #pragma mark - JMNumberButtonDelegate 89 | - (void)numberButton:(JMNumberButton *)numberButton Number:(NSInteger)number { 90 | JMLog(@"%@----%zd",numberButton, number); 91 | } 92 | 93 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 94 | [self.view endEditing:YES]; 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /JMButton/JMRadioViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMRadioViewController.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/27. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JMRadioViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /JMButton/JMRadioViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMRadioViewController.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/27. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #import "JMRadioViewController.h" 10 | #import "JMButtons.h" 11 | 12 | @interface JMRadioViewController () 13 | 14 | @end 15 | 16 | @implementation JMRadioViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | self.view.backgroundColor = [UIColor whiteColor]; 21 | self.title = @"radio按钮效果"; 22 | 23 | JMRadioButton *radiobtn = [[JMRadioButton alloc] initWithFrame:CGRectMake(50, 100, 140, 50)]; 24 | radiobtn.backgroundColor = [UIColor redColor]; 25 | [self.view addSubview:radiobtn]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JMButton/JMWaveViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JMWaveViewController.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/23. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import 25 | 26 | @interface JMWaveViewController : UIViewController 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JMButton/JMWaveViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JMWaveViewController.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/23. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | /* 9 | .----------------. .----------------. 10 | | .--------------. | .--------------. | 11 | | | _____ | | | ____ ____ | | 12 | | | |_ _| | | ||_ \ / _|| | 13 | | | | | | | | | \/ | | | 14 | | | _ | | | | | | |\ /| | | | 15 | | | | |_' | | | | _| |_\/_| |_ | | 16 | | | `.___.' | | ||_____||_____|| | 17 | | | | | | | | 18 | | '--------------' | '--------------' | 19 | '----------------' '----------------' 20 | github: https://github.com/JunAILiang 21 | blog: https://www.ljmvip.cn 22 | */ 23 | 24 | #import "JMWaveViewController.h" 25 | #import "JMButtons.h" 26 | 27 | @interface JMWaveViewController () 28 | 29 | @end 30 | 31 | @implementation JMWaveViewController 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | self.view.backgroundColor = [UIColor whiteColor]; 36 | self.title = @"按钮水波点击效果"; 37 | 38 | 39 | JMWaveButtonConfig *buttonConfig = [JMWaveButtonConfig buttonConfig]; 40 | buttonConfig.highlightedColor = [UIColor redColor]; 41 | buttonConfig.bootstrapType = JMBootstrapTypePurple; 42 | buttonConfig.title = @"我是按钮1"; 43 | JMButton *waveBtn = [[JMButton alloc] initWithFrame:CGRectMake(50, 100, 160, 60) ButtonConfig:buttonConfig]; 44 | [self.view addSubview:waveBtn]; 45 | 46 | JMWaveButtonConfig *buttonConfig1 = [JMWaveButtonConfig buttonConfig]; 47 | buttonConfig1.bootstrapType = JMBootstrapTypeNone; //水波纹效果一定要把bootstrapType设为None 48 | buttonConfig1.highlightedColor = [UIColor orangeColor]; 49 | buttonConfig1.backgroundColor = [UIColor colorWithHexString:@"#f93c81"]; 50 | buttonConfig1.title = @"我是按钮2"; 51 | buttonConfig1.cornerRadius = 20.f; 52 | buttonConfig1.corners = UIRectCornerTopLeft | UIRectCornerBottomRight; 53 | buttonConfig1.borderColor = [UIColor blueColor]; 54 | buttonConfig1.borderWidth = 6.f; 55 | JMButton *waveBtn1 = [[JMButton alloc] initWithFrame:CGRectMake(50, 200, 160, 60) ButtonConfig:buttonConfig1]; 56 | [self.view addSubview:waveBtn1]; 57 | 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /JMButton/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/8. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /JMButton/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/8. 6 | // Copyright © 2018年 JM. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "JMButton.h" 11 | #import "JMDefine.h" 12 | #import "JMBasicViewController.h" 13 | #import "JMBadgeViewController.h" 14 | #import "JMBootstrapViewController.h" 15 | #import "JMCountDownViewController.h" 16 | #import "JMCustomViewController.h" 17 | #import "JMNumberViewController.h" 18 | #import "JMWaveViewController.h" 19 | #import "JMRadioViewController.h" 20 | 21 | @interface ViewController () 22 | 23 | /** tableView */ 24 | @property (nonatomic, strong) UITableView *tableView; 25 | /** dataArr */ 26 | @property (nonatomic, strong) NSMutableArray *dataArr; 27 | 28 | @end 29 | 30 | @implementation ViewController 31 | 32 | - (void)viewDidLoad { 33 | [super viewDidLoad]; 34 | 35 | self.view.backgroundColor = [UIColor whiteColor]; 36 | 37 | self.dataArr = [NSMutableArray arrayWithObjects:@"系统默认样式",@"带角标的样式",@"Bootstrap样式",@"倒计时按钮功能",@"自定义View",@"高度自定制计数器按钮",@"按钮水波点击效果",@"Radio按钮", nil]; 38 | 39 | [self.view addSubview:self.tableView]; 40 | 41 | } 42 | 43 | - (UITableView *)tableView { 44 | if (!_tableView) { 45 | _tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain]; 46 | _tableView.delegate = self; 47 | _tableView.dataSource = self; 48 | _tableView.tableFooterView = [UIView new]; 49 | } 50 | return _tableView; 51 | } 52 | 53 | - (NSMutableArray *)dataArr { 54 | if (!_dataArr) { 55 | _dataArr = [NSMutableArray array]; 56 | } 57 | return _dataArr; 58 | } 59 | 60 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 61 | return self.dataArr.count; 62 | } 63 | 64 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 65 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellId"]; 66 | if (!cell) { 67 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellId"]; 68 | } 69 | cell.textLabel.text = self.dataArr[indexPath.row]; 70 | return cell; 71 | } 72 | 73 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 74 | if (indexPath.row == 0) { 75 | JMBasicViewController *basicVC = [[JMBasicViewController alloc] init]; 76 | [self.navigationController pushViewController:basicVC animated:YES]; 77 | } else if (indexPath.row == 1) { 78 | JMBadgeViewController *badgeVC = [[JMBadgeViewController alloc] init]; 79 | [self.navigationController pushViewController:badgeVC animated:YES]; 80 | } else if (indexPath.row == 2) { 81 | JMBootstrapViewController *bootstrapVC = [[JMBootstrapViewController alloc] init]; 82 | [self.navigationController pushViewController:bootstrapVC animated:YES]; 83 | } else if (indexPath.row == 3) { 84 | JMCountDownViewController *countDownVC = [[JMCountDownViewController alloc] init]; 85 | [self.navigationController pushViewController:countDownVC animated:YES]; 86 | } else if (indexPath.row == 4) { 87 | JMCustomViewController *customVC = [[JMCustomViewController alloc] init]; 88 | [self.navigationController pushViewController:customVC animated:YES]; 89 | } else if (indexPath.row == 5) { 90 | JMNumberViewController *numberVC = [[JMNumberViewController alloc] init]; 91 | [self.navigationController pushViewController:numberVC animated:YES]; 92 | } else if (indexPath.row == 6) { 93 | JMWaveViewController *waveVC = [[JMWaveViewController alloc] init]; 94 | [self.navigationController pushViewController:waveVC animated:YES]; 95 | } else if (indexPath.row == 7) { 96 | JMRadioViewController *radioVC = [[JMRadioViewController alloc] init]; 97 | [self.navigationController pushViewController:radioVC animated:YES]; 98 | } 99 | } 100 | 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /JMButton/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // JMButton 4 | // 5 | // Created by JM on 2018/1/8. 6 | // Copyright © 2018年 JM. 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 JunAILiang 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 | # JMButton 2 | 超强UIButton封装 3 | * 新增水波纹按钮点击效果 4 | * 新增倒计时功能 5 | * 新增高度自定义计数器功能 6 | * 自定义图片上下左右位置 7 | * 自定义文字和图片间距 8 | * 自定义角标动画 9 | * 支持CocoaPods 10 | 11 | # 一张图让你看懂JMButton结构 12 | ![](https://github.com/JunAILiang/JMAllGif/raw/master/JMButton/JMButtonAll.png) 13 | 14 | # 版本 15 | * 2018-01-29 修复按钮倒计时功能 16 | * 2018-01-26 新增水波纹点击效果 17 | * 2018-01-22 新增计数器功能 (仿淘宝, 京东, 美团, 饿了吗, 百度外卖 计数功能) 18 | * 2018-01-17 新增自定义View, 新增倒计时功能 19 | * 2018-01-16 初始版本 20 | 21 | # 演示 22 | ![](https://github.com/JunAILiang/JMAllGif/raw/master/JMButton/JMButton.gif) ![](https://github.com/JunAILiang/JMAllGif/raw/master/JMButton/JMButton1.gif) ![](https://github.com/JunAILiang/JMAllGif/raw/master/JMButton/JMButton2.gif) 23 | 24 | # 基本按钮如何使用, 以Bootstrap样式为例 25 | * 通过CocoaPods导入 `pod 'JMButton', '~> 0.5'` 26 | * 手动导入 直接下载工程把 `JMButton` 文件夹导入到自己工程中 27 | 1. 导入JMButtons`#import "JMButtons.h"`, 28 | 2. 初始化JMBootstrapButtonConfig并配置属性 29 | ``` 30 | JMBootstrapButtonConfig *buttonConfig = [JMBootstrapButtonConfig buttonConfig]; 31 | buttonConfig.bootstrapType = JMBootstrapTypeDefault; 32 | ``` 33 | 3. 初始化JMButton并添加到视图 34 | ``` 35 | JMButton *btn = [[JMButton alloc] initWithFrame:CGRectMake(100, 100, 100, 50) ButtonConfig:buttonConfig]; 36 | [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; 37 | [self.view addSubView:btn]; 38 | ``` 39 | 40 | # 一行代码实现倒计时按钮 41 | ``` 42 | //一行代码实现倒计时 43 | [bsBtn startCountDown:6]; 44 | ``` 45 | 46 | ### 倒计时其他属性 47 | ``` 48 | /** 倒计时中背景颜色(默认 不设置) */ 49 | @property (nonatomic, strong) UIColor *countDownBackground; 50 | /** 倒计时完成后背景颜色 (默认 不设置) */ 51 | @property (nonatomic, strong) UIColor *countDownDoneBackground; 52 | /** 倒计时边框颜色 (默认 不设置) */ 53 | @property (nonatomic, strong) UIColor *countDownBorderColor; 54 | /** 倒计时完成后边框颜色 (默认 不设置) */ 55 | @property (nonatomic, strong) UIColor *countDownDoneBorderColor; 56 | ``` 57 | 58 | # 计数器按钮如何使用 59 | 1. 导入JMButtons`#import "JMButtons.h"` 60 | ``` 61 | JMNumberButtonConfig *buttonConfig = [JMNumberButtonConfig buttonConfig]; 62 | buttonConfig.shakeAnimation = YES; //开启抖动动画 63 | JMNumberButton *numberBtn = [[JMNumberButton alloc] initWithFrame:CGRectMake(50, 100, 120, 40) NumberButtonConfig:buttonConfig]; 64 | [self.view addSubview:numberBtn]; 65 | ``` 66 | 67 | ### 计数器按钮高自定义 68 | ``` 69 | typedef NS_ENUM(NSInteger, JMNumberButtonType) { 70 | JMNumberButtonTypeNormal, //默认样式 71 | JMNumberButtonTypeTaoBao, //仿淘宝样式 72 | JMNumberButtonTypeJingDong, //仿京东样式 73 | JMNumberButtonTypeMeiTuan, //仿美团 饿了吗 百度外卖 样式 74 | }; 75 | 76 | @interface JMNumberButtonConfig : NSObject 77 | 78 | /** 初始化 */ 79 | + (instancetype)buttonConfig; 80 | 81 | /********************* 样式配置 *********************/ 82 | /** 样式 */ 83 | @property (nonatomic, assign) JMNumberButtonType numberButtonType; 84 | /** 是否开启抖动动画 (默认 NO) */ 85 | @property (nonatomic, assign) BOOL shakeAnimation; 86 | 87 | 88 | /********************* 输入框配置 *********************/ 89 | /** 输入框中的内容 (默认 1) */ 90 | @property (nonatomic, assign) NSInteger currentNumber; 91 | /** 输入框中字体大小 (默认 20.f )*/ 92 | @property (nonatomic, strong) UIFont *inputFont; 93 | /** 输入框是否可输入 (默认 YES) */ 94 | @property (nonatomic, assign) BOOL isInput; 95 | /** 边框线条宽度 (默认 0 0的话不会展示) */ 96 | @property (nonatomic, assign) CGFloat borderLineWidth; 97 | /** 边框线条颜色 (默认 #eeeeee) */ 98 | @property (nonatomic, strong) UIColor *borderLineColor; 99 | /** 圆角值 ( 默认 3.f 如果设置了numberButtonType, 圆角值将无效 ) */ 100 | @property (nonatomic, assign) CGFloat cornerRadius; 101 | 102 | 103 | /********************* 按钮配置 *********************/ 104 | /** 加减按钮字体大小 (默认 30.f) */ 105 | @property (nonatomic, strong) UIFont *buttonTitleFont; 106 | /** 加按钮背景颜色 (默认 #FFFFFF) */ 107 | @property (nonatomic, strong) UIColor *increaseBackgroundColor; 108 | /** 减按钮背景颜色 (默认 #FFFFFF)*/ 109 | @property (nonatomic, strong) UIColor *decreaseBackgroundColor; 110 | /** 加按钮背景图片 (默认 nil 图片的设置优先级高于背景颜色) */ 111 | @property (nonatomic, strong) UIImage *increaseBackgroundImage; 112 | /** 减按钮背景图片 (默认 nil) */ 113 | @property (nonatomic, strong) UIImage *decreaseBackgroundImage; 114 | /** 加按钮标题 (默认 +) */ 115 | @property (nonatomic, strong) NSString *increaseTitle; 116 | /** 减按钮标题 (默认 -) */ 117 | @property (nonatomic, strong) NSString *decreaseTitle; 118 | /** 加按钮contentEdgeInsets (默认 0, 0, 3, 0) */ 119 | @property (nonatomic, assign) UIEdgeInsets increaseContentEdgeInsets; 120 | /** 减按钮contentEdgeInsets (默认 0, 0, 3, 0) */ 121 | @property (nonatomic, assign) UIEdgeInsets decreaseContentEdgeInsets; 122 | 123 | 124 | /********************* 其他配置 *********************/ 125 | /** 最小值 (默认 1)*/ 126 | @property (nonatomic, assign) NSInteger minNumber; 127 | /** 最大值 (默认 无限制)*/ 128 | @property (nonatomic, assign) NSInteger maxNumber; 129 | ``` 130 | 131 | # 水波纹按钮如何使用 132 | 1. 导入JMButtons`#import "JMButtons.h"` 133 | ``` 134 | JMWaveButtonConfig *buttonConfig = [JMWaveButtonConfig buttonConfig]; 135 | buttonConfig.highlightedColor = [UIColor redColor]; //水波纹按钮颜色 136 | buttonConfig.title = @"我是按钮1"; 137 | JMButton *waveBtn = [[JMButton alloc] initWithFrame:CGRectMake(50, 100, 160, 60) ButtonConfig:buttonConfig]; 138 | [self.view addSubview:waveBtn]; 139 | ``` 140 | 141 | 142 | ### 联系我: 143 | * qq: 1245424073 144 | * [简书地址](https://www.jianshu.com/p/ba8e986cdd0c) 145 | * [我的博客](https://ljmvip.cn) 146 | --------------------------------------------------------------------------------