├── .DS_Store ├── .gitignore ├── .travis.yml ├── 3006981-889f087b55f3e57f.gif ├── Example ├── .DS_Store ├── SPPageMenu.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata │ │ │ ├── devlop1.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ │ ├── libo.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ │ └── stephen.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── SPPageMenu.xcscheme │ └── xcuserdata │ │ ├── devlop1.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ │ ├── libo.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ ├── SPPageMenu.xcscheme │ │ │ └── xcschememanagement.plist │ │ └── stephen.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── SPPageMenu │ ├── .DS_Store │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Expression_1.imageset │ │ │ ├── Contents.json │ │ │ └── Expression_1@2x.png │ │ ├── Expression_2.imageset │ │ │ ├── Contents.json │ │ │ └── Expression_3@2x.png │ │ ├── Expression_3.imageset │ │ │ ├── Contents.json │ │ │ └── Expression_5@2x.png │ │ ├── asc.imageset │ │ │ ├── 1@2x.png │ │ │ └── Contents.json │ │ └── dog.imageset │ │ │ ├── Contents.json │ │ │ └── dog.jpg │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── ChildViewControllers │ │ ├── BaseViewController.h │ │ ├── BaseViewController.m │ │ ├── EightViewController.h │ │ ├── EightViewController.m │ │ ├── FirstViewController.h │ │ ├── FirstViewController.m │ │ ├── FiveViewController.h │ │ ├── FiveViewController.m │ │ ├── FourViewController.h │ │ ├── FourViewController.m │ │ ├── SecondViewController.h │ │ ├── SecondViewController.m │ │ ├── SevenViewController.h │ │ ├── SevenViewController.m │ │ ├── SixViewController.h │ │ ├── SixViewController.m │ │ ├── ThidViewController.h │ │ └── ThidViewController.m │ ├── Images │ │ └── mateor.jpg │ ├── Info.plist │ ├── JSBadgeView │ │ ├── JSBadgeView.h │ │ └── JSBadgeView.m │ ├── ParentViewController.h │ ├── ParentViewController.m │ ├── SPPageMenu │ │ ├── .DS_Store │ │ ├── SPPageMenu.h │ │ └── SPPageMenu.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── SPPageMenuTests │ ├── Info.plist │ └── SPPageMenuTests.m └── SPPageMenuUITests │ ├── Info.plist │ └── SPPageMenuUITests.m ├── README.md ├── SPPageMenu.podspec └── SPPageMenu ├── .DS_Store ├── SPPageMenu.h └── SPPageMenu.m /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 3 | 4 | ## Build generated 5 | build/ 6 | DerivedData/ 7 | 8 | ## Various settings 9 | *.xcuserstate 10 | *.DS_Store 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | 33 | # CocoaPods 34 | # 35 | # We recommend against adding the Pods directory to your .gitignore. However 36 | # you should judge for yourself, the pros and cons are mentioned at: 37 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 38 | # 39 | # Pods/ 40 | 41 | # Carthage 42 | # 43 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 44 | # Carthage/Checkouts 45 | 46 | Carthage/Build 47 | 48 | # fastlane 49 | # 50 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 51 | # screenshots whenever they are needed. 52 | # For more information about the recommended setup visit: 53 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 54 | 55 | fastlane/report.xml 56 | fastlane/Preview.html 57 | fastlane/screenshots 58 | fastlane/test_output 59 | 60 | # Code Injection 61 | # 62 | # After new code Injection tools there's a generated folder /iOSInjectionProject 63 | # https://github.com/johnno1962/injectionforxcode 64 | 65 | iOSInjectionProject/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | script: true -------------------------------------------------------------------------------- /3006981-889f087b55f3e57f.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/3006981-889f087b55f3e57f.gif -------------------------------------------------------------------------------- /Example/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/.DS_Store -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 091229F91FA5F13000AEE295 /* ParentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 091229F81FA5F13000AEE295 /* ParentViewController.m */; }; 11 | 091A68771FA1CAC100DAA561 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 091A68761FA1CAC100DAA561 /* main.m */; }; 12 | 091A687A1FA1CAC100DAA561 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 091A68791FA1CAC100DAA561 /* AppDelegate.m */; }; 13 | 091A687D1FA1CAC100DAA561 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 091A687C1FA1CAC100DAA561 /* ViewController.m */; }; 14 | 091A68801FA1CAC100DAA561 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 091A687E1FA1CAC100DAA561 /* Main.storyboard */; }; 15 | 091A68821FA1CAC100DAA561 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 091A68811FA1CAC100DAA561 /* Assets.xcassets */; }; 16 | 091A68851FA1CAC100DAA561 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 091A68831FA1CAC100DAA561 /* LaunchScreen.storyboard */; }; 17 | 091A68901FA1CAC200DAA561 /* SPPageMenuTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 091A688F1FA1CAC200DAA561 /* SPPageMenuTests.m */; }; 18 | 091A689B1FA1CAC200DAA561 /* SPPageMenuUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 091A689A1FA1CAC200DAA561 /* SPPageMenuUITests.m */; }; 19 | 095E9C181FA6F8CC0097A889 /* BaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C041FA6F8CC0097A889 /* BaseViewController.m */; }; 20 | 095E9C191FA6F8CC0097A889 /* EightViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C061FA6F8CC0097A889 /* EightViewController.m */; }; 21 | 095E9C1A1FA6F8CC0097A889 /* FirstViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C081FA6F8CC0097A889 /* FirstViewController.m */; }; 22 | 095E9C1B1FA6F8CC0097A889 /* FiveViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C0A1FA6F8CC0097A889 /* FiveViewController.m */; }; 23 | 095E9C1C1FA6F8CC0097A889 /* FourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C0C1FA6F8CC0097A889 /* FourViewController.m */; }; 24 | 095E9C1D1FA6F8CC0097A889 /* SecondViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C0E1FA6F8CC0097A889 /* SecondViewController.m */; }; 25 | 095E9C1E1FA6F8CC0097A889 /* SevenViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C101FA6F8CC0097A889 /* SevenViewController.m */; }; 26 | 095E9C1F1FA6F8CC0097A889 /* SixViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C121FA6F8CC0097A889 /* SixViewController.m */; }; 27 | 095E9C211FA6F8CC0097A889 /* ThidViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C171FA6F8CC0097A889 /* ThidViewController.m */; }; 28 | 095E9C291FA6F92D0097A889 /* SPPageMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 095E9C281FA6F92D0097A889 /* SPPageMenu.m */; }; 29 | 6A8808C1213D361D00C3553F /* mateor.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 6A8808BF213D361C00C3553F /* mateor.jpg */; }; 30 | 6A9270122179BCF400831045 /* JSBadgeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A9270102179BCF400831045 /* JSBadgeView.m */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | 091A688C1FA1CAC200DAA561 /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 091A686A1FA1CAC100DAA561 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 091A68711FA1CAC100DAA561; 39 | remoteInfo = SPPageMenu; 40 | }; 41 | 091A68971FA1CAC200DAA561 /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = 091A686A1FA1CAC100DAA561 /* Project object */; 44 | proxyType = 1; 45 | remoteGlobalIDString = 091A68711FA1CAC100DAA561; 46 | remoteInfo = SPPageMenu; 47 | }; 48 | /* End PBXContainerItemProxy section */ 49 | 50 | /* Begin PBXFileReference section */ 51 | 091229F71FA5F13000AEE295 /* ParentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParentViewController.h; sourceTree = ""; }; 52 | 091229F81FA5F13000AEE295 /* ParentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ParentViewController.m; sourceTree = ""; }; 53 | 091A68721FA1CAC100DAA561 /* SPPageMenu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SPPageMenu.app; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 091A68761FA1CAC100DAA561 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 55 | 091A68781FA1CAC100DAA561 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 56 | 091A68791FA1CAC100DAA561 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 57 | 091A687B1FA1CAC100DAA561 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 58 | 091A687C1FA1CAC100DAA561 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 59 | 091A687F1FA1CAC100DAA561 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 60 | 091A68811FA1CAC100DAA561 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 61 | 091A68841FA1CAC100DAA561 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 62 | 091A68861FA1CAC100DAA561 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | 091A688B1FA1CAC200DAA561 /* SPPageMenuTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SPPageMenuTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | 091A688F1FA1CAC200DAA561 /* SPPageMenuTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SPPageMenuTests.m; sourceTree = ""; }; 65 | 091A68911FA1CAC200DAA561 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | 091A68961FA1CAC200DAA561 /* SPPageMenuUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SPPageMenuUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | 091A689A1FA1CAC200DAA561 /* SPPageMenuUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SPPageMenuUITests.m; sourceTree = ""; }; 68 | 091A689C1FA1CAC200DAA561 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | 095E9C031FA6F8CC0097A889 /* BaseViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseViewController.h; sourceTree = ""; }; 70 | 095E9C041FA6F8CC0097A889 /* BaseViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BaseViewController.m; sourceTree = ""; }; 71 | 095E9C051FA6F8CC0097A889 /* EightViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EightViewController.h; sourceTree = ""; }; 72 | 095E9C061FA6F8CC0097A889 /* EightViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EightViewController.m; sourceTree = ""; }; 73 | 095E9C071FA6F8CC0097A889 /* FirstViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FirstViewController.h; sourceTree = ""; }; 74 | 095E9C081FA6F8CC0097A889 /* FirstViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirstViewController.m; sourceTree = ""; }; 75 | 095E9C091FA6F8CC0097A889 /* FiveViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FiveViewController.h; sourceTree = ""; }; 76 | 095E9C0A1FA6F8CC0097A889 /* FiveViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FiveViewController.m; sourceTree = ""; }; 77 | 095E9C0B1FA6F8CC0097A889 /* FourViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FourViewController.h; sourceTree = ""; }; 78 | 095E9C0C1FA6F8CC0097A889 /* FourViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FourViewController.m; sourceTree = ""; }; 79 | 095E9C0D1FA6F8CC0097A889 /* SecondViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecondViewController.h; sourceTree = ""; }; 80 | 095E9C0E1FA6F8CC0097A889 /* SecondViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecondViewController.m; sourceTree = ""; }; 81 | 095E9C0F1FA6F8CC0097A889 /* SevenViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SevenViewController.h; sourceTree = ""; }; 82 | 095E9C101FA6F8CC0097A889 /* SevenViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SevenViewController.m; sourceTree = ""; }; 83 | 095E9C111FA6F8CC0097A889 /* SixViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SixViewController.h; sourceTree = ""; }; 84 | 095E9C121FA6F8CC0097A889 /* SixViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SixViewController.m; sourceTree = ""; }; 85 | 095E9C161FA6F8CC0097A889 /* ThidViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThidViewController.h; sourceTree = ""; }; 86 | 095E9C171FA6F8CC0097A889 /* ThidViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThidViewController.m; sourceTree = ""; }; 87 | 095E9C271FA6F92D0097A889 /* SPPageMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPPageMenu.h; sourceTree = ""; }; 88 | 095E9C281FA6F92D0097A889 /* SPPageMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPPageMenu.m; sourceTree = ""; }; 89 | 6A8808BF213D361C00C3553F /* mateor.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = mateor.jpg; sourceTree = ""; }; 90 | 6A9270102179BCF400831045 /* JSBadgeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSBadgeView.m; sourceTree = ""; }; 91 | 6A9270112179BCF400831045 /* JSBadgeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBadgeView.h; sourceTree = ""; }; 92 | /* End PBXFileReference section */ 93 | 94 | /* Begin PBXFrameworksBuildPhase section */ 95 | 091A686F1FA1CAC100DAA561 /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | 091A68881FA1CAC200DAA561 /* Frameworks */ = { 103 | isa = PBXFrameworksBuildPhase; 104 | buildActionMask = 2147483647; 105 | files = ( 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | 091A68931FA1CAC200DAA561 /* Frameworks */ = { 110 | isa = PBXFrameworksBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | ); 114 | runOnlyForDeploymentPostprocessing = 0; 115 | }; 116 | /* End PBXFrameworksBuildPhase section */ 117 | 118 | /* Begin PBXGroup section */ 119 | 091A68691FA1CAC100DAA561 = { 120 | isa = PBXGroup; 121 | children = ( 122 | 091A68741FA1CAC100DAA561 /* SPPageMenu */, 123 | 091A688E1FA1CAC200DAA561 /* SPPageMenuTests */, 124 | 091A68991FA1CAC200DAA561 /* SPPageMenuUITests */, 125 | 091A68731FA1CAC100DAA561 /* Products */, 126 | ); 127 | sourceTree = ""; 128 | }; 129 | 091A68731FA1CAC100DAA561 /* Products */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 091A68721FA1CAC100DAA561 /* SPPageMenu.app */, 133 | 091A688B1FA1CAC200DAA561 /* SPPageMenuTests.xctest */, 134 | 091A68961FA1CAC200DAA561 /* SPPageMenuUITests.xctest */, 135 | ); 136 | name = Products; 137 | sourceTree = ""; 138 | }; 139 | 091A68741FA1CAC100DAA561 /* SPPageMenu */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 095E9C261FA6F92D0097A889 /* SPPageMenu */, 143 | 091A687B1FA1CAC100DAA561 /* ViewController.h */, 144 | 091A687C1FA1CAC100DAA561 /* ViewController.m */, 145 | 091229F71FA5F13000AEE295 /* ParentViewController.h */, 146 | 091229F81FA5F13000AEE295 /* ParentViewController.m */, 147 | 095E9C021FA6F8CC0097A889 /* ChildViewControllers */, 148 | DC317C5E213C0BB9000F4159 /* Images */, 149 | 6A92700F2179BCF400831045 /* JSBadgeView */, 150 | 091A687E1FA1CAC100DAA561 /* Main.storyboard */, 151 | 091A68811FA1CAC100DAA561 /* Assets.xcassets */, 152 | 091A68831FA1CAC100DAA561 /* LaunchScreen.storyboard */, 153 | 091A68861FA1CAC100DAA561 /* Info.plist */, 154 | 091A68781FA1CAC100DAA561 /* AppDelegate.h */, 155 | 091A68791FA1CAC100DAA561 /* AppDelegate.m */, 156 | 091A68751FA1CAC100DAA561 /* Supporting Files */, 157 | ); 158 | path = SPPageMenu; 159 | sourceTree = ""; 160 | }; 161 | 091A68751FA1CAC100DAA561 /* Supporting Files */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 091A68761FA1CAC100DAA561 /* main.m */, 165 | ); 166 | name = "Supporting Files"; 167 | sourceTree = ""; 168 | }; 169 | 091A688E1FA1CAC200DAA561 /* SPPageMenuTests */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | 091A688F1FA1CAC200DAA561 /* SPPageMenuTests.m */, 173 | 091A68911FA1CAC200DAA561 /* Info.plist */, 174 | ); 175 | path = SPPageMenuTests; 176 | sourceTree = ""; 177 | }; 178 | 091A68991FA1CAC200DAA561 /* SPPageMenuUITests */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | 091A689A1FA1CAC200DAA561 /* SPPageMenuUITests.m */, 182 | 091A689C1FA1CAC200DAA561 /* Info.plist */, 183 | ); 184 | path = SPPageMenuUITests; 185 | sourceTree = ""; 186 | }; 187 | 095E9C021FA6F8CC0097A889 /* ChildViewControllers */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 095E9C031FA6F8CC0097A889 /* BaseViewController.h */, 191 | 095E9C041FA6F8CC0097A889 /* BaseViewController.m */, 192 | 095E9C071FA6F8CC0097A889 /* FirstViewController.h */, 193 | 095E9C081FA6F8CC0097A889 /* FirstViewController.m */, 194 | 095E9C0D1FA6F8CC0097A889 /* SecondViewController.h */, 195 | 095E9C0E1FA6F8CC0097A889 /* SecondViewController.m */, 196 | 095E9C161FA6F8CC0097A889 /* ThidViewController.h */, 197 | 095E9C171FA6F8CC0097A889 /* ThidViewController.m */, 198 | 095E9C0B1FA6F8CC0097A889 /* FourViewController.h */, 199 | 095E9C0C1FA6F8CC0097A889 /* FourViewController.m */, 200 | 095E9C091FA6F8CC0097A889 /* FiveViewController.h */, 201 | 095E9C0A1FA6F8CC0097A889 /* FiveViewController.m */, 202 | 095E9C111FA6F8CC0097A889 /* SixViewController.h */, 203 | 095E9C121FA6F8CC0097A889 /* SixViewController.m */, 204 | 095E9C0F1FA6F8CC0097A889 /* SevenViewController.h */, 205 | 095E9C101FA6F8CC0097A889 /* SevenViewController.m */, 206 | 095E9C051FA6F8CC0097A889 /* EightViewController.h */, 207 | 095E9C061FA6F8CC0097A889 /* EightViewController.m */, 208 | ); 209 | path = ChildViewControllers; 210 | sourceTree = ""; 211 | }; 212 | 095E9C261FA6F92D0097A889 /* SPPageMenu */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | 095E9C271FA6F92D0097A889 /* SPPageMenu.h */, 216 | 095E9C281FA6F92D0097A889 /* SPPageMenu.m */, 217 | ); 218 | path = SPPageMenu; 219 | sourceTree = ""; 220 | }; 221 | 6A92700F2179BCF400831045 /* JSBadgeView */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | 6A9270112179BCF400831045 /* JSBadgeView.h */, 225 | 6A9270102179BCF400831045 /* JSBadgeView.m */, 226 | ); 227 | path = JSBadgeView; 228 | sourceTree = ""; 229 | }; 230 | DC317C5E213C0BB9000F4159 /* Images */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | 6A8808BF213D361C00C3553F /* mateor.jpg */, 234 | ); 235 | name = Images; 236 | path = SPPageMenu/Images; 237 | sourceTree = SOURCE_ROOT; 238 | }; 239 | /* End PBXGroup section */ 240 | 241 | /* Begin PBXNativeTarget section */ 242 | 091A68711FA1CAC100DAA561 /* SPPageMenu */ = { 243 | isa = PBXNativeTarget; 244 | buildConfigurationList = 091A689F1FA1CAC200DAA561 /* Build configuration list for PBXNativeTarget "SPPageMenu" */; 245 | buildPhases = ( 246 | 091A686E1FA1CAC100DAA561 /* Sources */, 247 | 091A686F1FA1CAC100DAA561 /* Frameworks */, 248 | 091A68701FA1CAC100DAA561 /* Resources */, 249 | ); 250 | buildRules = ( 251 | ); 252 | dependencies = ( 253 | ); 254 | name = SPPageMenu; 255 | productName = SPPageMenu; 256 | productReference = 091A68721FA1CAC100DAA561 /* SPPageMenu.app */; 257 | productType = "com.apple.product-type.application"; 258 | }; 259 | 091A688A1FA1CAC200DAA561 /* SPPageMenuTests */ = { 260 | isa = PBXNativeTarget; 261 | buildConfigurationList = 091A68A21FA1CAC200DAA561 /* Build configuration list for PBXNativeTarget "SPPageMenuTests" */; 262 | buildPhases = ( 263 | 091A68871FA1CAC200DAA561 /* Sources */, 264 | 091A68881FA1CAC200DAA561 /* Frameworks */, 265 | 091A68891FA1CAC200DAA561 /* Resources */, 266 | ); 267 | buildRules = ( 268 | ); 269 | dependencies = ( 270 | 091A688D1FA1CAC200DAA561 /* PBXTargetDependency */, 271 | ); 272 | name = SPPageMenuTests; 273 | productName = SPPageMenuTests; 274 | productReference = 091A688B1FA1CAC200DAA561 /* SPPageMenuTests.xctest */; 275 | productType = "com.apple.product-type.bundle.unit-test"; 276 | }; 277 | 091A68951FA1CAC200DAA561 /* SPPageMenuUITests */ = { 278 | isa = PBXNativeTarget; 279 | buildConfigurationList = 091A68A51FA1CAC200DAA561 /* Build configuration list for PBXNativeTarget "SPPageMenuUITests" */; 280 | buildPhases = ( 281 | 091A68921FA1CAC200DAA561 /* Sources */, 282 | 091A68931FA1CAC200DAA561 /* Frameworks */, 283 | 091A68941FA1CAC200DAA561 /* Resources */, 284 | ); 285 | buildRules = ( 286 | ); 287 | dependencies = ( 288 | 091A68981FA1CAC200DAA561 /* PBXTargetDependency */, 289 | ); 290 | name = SPPageMenuUITests; 291 | productName = SPPageMenuUITests; 292 | productReference = 091A68961FA1CAC200DAA561 /* SPPageMenuUITests.xctest */; 293 | productType = "com.apple.product-type.bundle.ui-testing"; 294 | }; 295 | /* End PBXNativeTarget section */ 296 | 297 | /* Begin PBXProject section */ 298 | 091A686A1FA1CAC100DAA561 /* Project object */ = { 299 | isa = PBXProject; 300 | attributes = { 301 | LastUpgradeCheck = 0920; 302 | ORGANIZATIONNAME = iDress; 303 | TargetAttributes = { 304 | 091A68711FA1CAC100DAA561 = { 305 | CreatedOnToolsVersion = 8.2.1; 306 | DevelopmentTeam = N7GTHGMGVY; 307 | ProvisioningStyle = Automatic; 308 | }; 309 | 091A688A1FA1CAC200DAA561 = { 310 | CreatedOnToolsVersion = 8.2.1; 311 | DevelopmentTeam = SXULSRC6Y5; 312 | ProvisioningStyle = Automatic; 313 | TestTargetID = 091A68711FA1CAC100DAA561; 314 | }; 315 | 091A68951FA1CAC200DAA561 = { 316 | CreatedOnToolsVersion = 8.2.1; 317 | DevelopmentTeam = SXULSRC6Y5; 318 | ProvisioningStyle = Automatic; 319 | TestTargetID = 091A68711FA1CAC100DAA561; 320 | }; 321 | }; 322 | }; 323 | buildConfigurationList = 091A686D1FA1CAC100DAA561 /* Build configuration list for PBXProject "SPPageMenu" */; 324 | compatibilityVersion = "Xcode 3.2"; 325 | developmentRegion = English; 326 | hasScannedForEncodings = 0; 327 | knownRegions = ( 328 | en, 329 | Base, 330 | ); 331 | mainGroup = 091A68691FA1CAC100DAA561; 332 | productRefGroup = 091A68731FA1CAC100DAA561 /* Products */; 333 | projectDirPath = ""; 334 | projectRoot = ""; 335 | targets = ( 336 | 091A68711FA1CAC100DAA561 /* SPPageMenu */, 337 | 091A688A1FA1CAC200DAA561 /* SPPageMenuTests */, 338 | 091A68951FA1CAC200DAA561 /* SPPageMenuUITests */, 339 | ); 340 | }; 341 | /* End PBXProject section */ 342 | 343 | /* Begin PBXResourcesBuildPhase section */ 344 | 091A68701FA1CAC100DAA561 /* Resources */ = { 345 | isa = PBXResourcesBuildPhase; 346 | buildActionMask = 2147483647; 347 | files = ( 348 | 091A68851FA1CAC100DAA561 /* LaunchScreen.storyboard in Resources */, 349 | 091A68821FA1CAC100DAA561 /* Assets.xcassets in Resources */, 350 | 6A8808C1213D361D00C3553F /* mateor.jpg in Resources */, 351 | 091A68801FA1CAC100DAA561 /* Main.storyboard in Resources */, 352 | ); 353 | runOnlyForDeploymentPostprocessing = 0; 354 | }; 355 | 091A68891FA1CAC200DAA561 /* Resources */ = { 356 | isa = PBXResourcesBuildPhase; 357 | buildActionMask = 2147483647; 358 | files = ( 359 | ); 360 | runOnlyForDeploymentPostprocessing = 0; 361 | }; 362 | 091A68941FA1CAC200DAA561 /* Resources */ = { 363 | isa = PBXResourcesBuildPhase; 364 | buildActionMask = 2147483647; 365 | files = ( 366 | ); 367 | runOnlyForDeploymentPostprocessing = 0; 368 | }; 369 | /* End PBXResourcesBuildPhase section */ 370 | 371 | /* Begin PBXSourcesBuildPhase section */ 372 | 091A686E1FA1CAC100DAA561 /* Sources */ = { 373 | isa = PBXSourcesBuildPhase; 374 | buildActionMask = 2147483647; 375 | files = ( 376 | 095E9C1D1FA6F8CC0097A889 /* SecondViewController.m in Sources */, 377 | 095E9C1B1FA6F8CC0097A889 /* FiveViewController.m in Sources */, 378 | 095E9C191FA6F8CC0097A889 /* EightViewController.m in Sources */, 379 | 6A9270122179BCF400831045 /* JSBadgeView.m in Sources */, 380 | 095E9C181FA6F8CC0097A889 /* BaseViewController.m in Sources */, 381 | 095E9C291FA6F92D0097A889 /* SPPageMenu.m in Sources */, 382 | 091229F91FA5F13000AEE295 /* ParentViewController.m in Sources */, 383 | 095E9C1E1FA6F8CC0097A889 /* SevenViewController.m in Sources */, 384 | 091A687D1FA1CAC100DAA561 /* ViewController.m in Sources */, 385 | 095E9C1A1FA6F8CC0097A889 /* FirstViewController.m in Sources */, 386 | 091A687A1FA1CAC100DAA561 /* AppDelegate.m in Sources */, 387 | 095E9C1C1FA6F8CC0097A889 /* FourViewController.m in Sources */, 388 | 095E9C1F1FA6F8CC0097A889 /* SixViewController.m in Sources */, 389 | 091A68771FA1CAC100DAA561 /* main.m in Sources */, 390 | 095E9C211FA6F8CC0097A889 /* ThidViewController.m in Sources */, 391 | ); 392 | runOnlyForDeploymentPostprocessing = 0; 393 | }; 394 | 091A68871FA1CAC200DAA561 /* Sources */ = { 395 | isa = PBXSourcesBuildPhase; 396 | buildActionMask = 2147483647; 397 | files = ( 398 | 091A68901FA1CAC200DAA561 /* SPPageMenuTests.m in Sources */, 399 | ); 400 | runOnlyForDeploymentPostprocessing = 0; 401 | }; 402 | 091A68921FA1CAC200DAA561 /* Sources */ = { 403 | isa = PBXSourcesBuildPhase; 404 | buildActionMask = 2147483647; 405 | files = ( 406 | 091A689B1FA1CAC200DAA561 /* SPPageMenuUITests.m in Sources */, 407 | ); 408 | runOnlyForDeploymentPostprocessing = 0; 409 | }; 410 | /* End PBXSourcesBuildPhase section */ 411 | 412 | /* Begin PBXTargetDependency section */ 413 | 091A688D1FA1CAC200DAA561 /* PBXTargetDependency */ = { 414 | isa = PBXTargetDependency; 415 | target = 091A68711FA1CAC100DAA561 /* SPPageMenu */; 416 | targetProxy = 091A688C1FA1CAC200DAA561 /* PBXContainerItemProxy */; 417 | }; 418 | 091A68981FA1CAC200DAA561 /* PBXTargetDependency */ = { 419 | isa = PBXTargetDependency; 420 | target = 091A68711FA1CAC100DAA561 /* SPPageMenu */; 421 | targetProxy = 091A68971FA1CAC200DAA561 /* PBXContainerItemProxy */; 422 | }; 423 | /* End PBXTargetDependency section */ 424 | 425 | /* Begin PBXVariantGroup section */ 426 | 091A687E1FA1CAC100DAA561 /* Main.storyboard */ = { 427 | isa = PBXVariantGroup; 428 | children = ( 429 | 091A687F1FA1CAC100DAA561 /* Base */, 430 | ); 431 | name = Main.storyboard; 432 | sourceTree = ""; 433 | }; 434 | 091A68831FA1CAC100DAA561 /* LaunchScreen.storyboard */ = { 435 | isa = PBXVariantGroup; 436 | children = ( 437 | 091A68841FA1CAC100DAA561 /* Base */, 438 | ); 439 | name = LaunchScreen.storyboard; 440 | sourceTree = ""; 441 | }; 442 | /* End PBXVariantGroup section */ 443 | 444 | /* Begin XCBuildConfiguration section */ 445 | 091A689D1FA1CAC200DAA561 /* Debug */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | ALWAYS_SEARCH_USER_PATHS = NO; 449 | CLANG_ANALYZER_NONNULL = YES; 450 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 451 | CLANG_CXX_LIBRARY = "libc++"; 452 | CLANG_ENABLE_MODULES = YES; 453 | CLANG_ENABLE_OBJC_ARC = YES; 454 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 455 | CLANG_WARN_BOOL_CONVERSION = YES; 456 | CLANG_WARN_COMMA = YES; 457 | CLANG_WARN_CONSTANT_CONVERSION = YES; 458 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 459 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 460 | CLANG_WARN_EMPTY_BODY = YES; 461 | CLANG_WARN_ENUM_CONVERSION = YES; 462 | CLANG_WARN_INFINITE_RECURSION = YES; 463 | CLANG_WARN_INT_CONVERSION = YES; 464 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 465 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 467 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 468 | CLANG_WARN_STRICT_PROTOTYPES = YES; 469 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 470 | CLANG_WARN_UNREACHABLE_CODE = YES; 471 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 472 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 473 | COPY_PHASE_STRIP = NO; 474 | DEBUG_INFORMATION_FORMAT = dwarf; 475 | ENABLE_STRICT_OBJC_MSGSEND = YES; 476 | ENABLE_TESTABILITY = YES; 477 | GCC_C_LANGUAGE_STANDARD = gnu99; 478 | GCC_DYNAMIC_NO_PIC = NO; 479 | GCC_NO_COMMON_BLOCKS = YES; 480 | GCC_OPTIMIZATION_LEVEL = 0; 481 | GCC_PREPROCESSOR_DEFINITIONS = ( 482 | "DEBUG=1", 483 | "$(inherited)", 484 | ); 485 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 486 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 487 | GCC_WARN_UNDECLARED_SELECTOR = YES; 488 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 489 | GCC_WARN_UNUSED_FUNCTION = YES; 490 | GCC_WARN_UNUSED_VARIABLE = YES; 491 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 492 | MTL_ENABLE_DEBUG_INFO = YES; 493 | ONLY_ACTIVE_ARCH = YES; 494 | SDKROOT = iphoneos; 495 | }; 496 | name = Debug; 497 | }; 498 | 091A689E1FA1CAC200DAA561 /* Release */ = { 499 | isa = XCBuildConfiguration; 500 | buildSettings = { 501 | ALWAYS_SEARCH_USER_PATHS = NO; 502 | CLANG_ANALYZER_NONNULL = YES; 503 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 504 | CLANG_CXX_LIBRARY = "libc++"; 505 | CLANG_ENABLE_MODULES = YES; 506 | CLANG_ENABLE_OBJC_ARC = YES; 507 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 508 | CLANG_WARN_BOOL_CONVERSION = YES; 509 | CLANG_WARN_COMMA = YES; 510 | CLANG_WARN_CONSTANT_CONVERSION = YES; 511 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 512 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 513 | CLANG_WARN_EMPTY_BODY = YES; 514 | CLANG_WARN_ENUM_CONVERSION = YES; 515 | CLANG_WARN_INFINITE_RECURSION = YES; 516 | CLANG_WARN_INT_CONVERSION = YES; 517 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 518 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 519 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 520 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 521 | CLANG_WARN_STRICT_PROTOTYPES = YES; 522 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 523 | CLANG_WARN_UNREACHABLE_CODE = YES; 524 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 525 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 526 | COPY_PHASE_STRIP = NO; 527 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 528 | ENABLE_NS_ASSERTIONS = NO; 529 | ENABLE_STRICT_OBJC_MSGSEND = YES; 530 | GCC_C_LANGUAGE_STANDARD = gnu99; 531 | GCC_NO_COMMON_BLOCKS = YES; 532 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 533 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 534 | GCC_WARN_UNDECLARED_SELECTOR = YES; 535 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 536 | GCC_WARN_UNUSED_FUNCTION = YES; 537 | GCC_WARN_UNUSED_VARIABLE = YES; 538 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 539 | MTL_ENABLE_DEBUG_INFO = NO; 540 | SDKROOT = iphoneos; 541 | VALIDATE_PRODUCT = YES; 542 | }; 543 | name = Release; 544 | }; 545 | 091A68A01FA1CAC200DAA561 /* Debug */ = { 546 | isa = XCBuildConfiguration; 547 | buildSettings = { 548 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 549 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO; 550 | CODE_SIGN_IDENTITY = "iPhone Developer"; 551 | CODE_SIGN_STYLE = Automatic; 552 | DEVELOPMENT_TEAM = N7GTHGMGVY; 553 | INFOPLIST_FILE = SPPageMenu/Info.plist; 554 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 555 | PRODUCT_BUNDLE_IDENTIFIER = com.idresschina.SPPageMenu; 556 | PRODUCT_NAME = "$(TARGET_NAME)"; 557 | PROVISIONING_PROFILE_SPECIFIER = ""; 558 | }; 559 | name = Debug; 560 | }; 561 | 091A68A11FA1CAC200DAA561 /* Release */ = { 562 | isa = XCBuildConfiguration; 563 | buildSettings = { 564 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 565 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO; 566 | CODE_SIGN_IDENTITY = "iPhone Developer"; 567 | CODE_SIGN_STYLE = Automatic; 568 | DEVELOPMENT_TEAM = N7GTHGMGVY; 569 | INFOPLIST_FILE = SPPageMenu/Info.plist; 570 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 571 | PRODUCT_BUNDLE_IDENTIFIER = com.idresschina.SPPageMenu; 572 | PRODUCT_NAME = "$(TARGET_NAME)"; 573 | PROVISIONING_PROFILE_SPECIFIER = ""; 574 | }; 575 | name = Release; 576 | }; 577 | 091A68A31FA1CAC200DAA561 /* Debug */ = { 578 | isa = XCBuildConfiguration; 579 | buildSettings = { 580 | BUNDLE_LOADER = "$(TEST_HOST)"; 581 | DEVELOPMENT_TEAM = SXULSRC6Y5; 582 | INFOPLIST_FILE = SPPageMenuTests/Info.plist; 583 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 584 | PRODUCT_BUNDLE_IDENTIFIER = com.idresschina.SPPageMenuTests; 585 | PRODUCT_NAME = "$(TARGET_NAME)"; 586 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SPPageMenu.app/SPPageMenu"; 587 | }; 588 | name = Debug; 589 | }; 590 | 091A68A41FA1CAC200DAA561 /* Release */ = { 591 | isa = XCBuildConfiguration; 592 | buildSettings = { 593 | BUNDLE_LOADER = "$(TEST_HOST)"; 594 | DEVELOPMENT_TEAM = SXULSRC6Y5; 595 | INFOPLIST_FILE = SPPageMenuTests/Info.plist; 596 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 597 | PRODUCT_BUNDLE_IDENTIFIER = com.idresschina.SPPageMenuTests; 598 | PRODUCT_NAME = "$(TARGET_NAME)"; 599 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SPPageMenu.app/SPPageMenu"; 600 | }; 601 | name = Release; 602 | }; 603 | 091A68A61FA1CAC200DAA561 /* Debug */ = { 604 | isa = XCBuildConfiguration; 605 | buildSettings = { 606 | DEVELOPMENT_TEAM = SXULSRC6Y5; 607 | INFOPLIST_FILE = SPPageMenuUITests/Info.plist; 608 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 609 | PRODUCT_BUNDLE_IDENTIFIER = com.idresschina.SPPageMenuUITests; 610 | PRODUCT_NAME = "$(TARGET_NAME)"; 611 | TEST_TARGET_NAME = SPPageMenu; 612 | }; 613 | name = Debug; 614 | }; 615 | 091A68A71FA1CAC200DAA561 /* Release */ = { 616 | isa = XCBuildConfiguration; 617 | buildSettings = { 618 | DEVELOPMENT_TEAM = SXULSRC6Y5; 619 | INFOPLIST_FILE = SPPageMenuUITests/Info.plist; 620 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 621 | PRODUCT_BUNDLE_IDENTIFIER = com.idresschina.SPPageMenuUITests; 622 | PRODUCT_NAME = "$(TARGET_NAME)"; 623 | TEST_TARGET_NAME = SPPageMenu; 624 | }; 625 | name = Release; 626 | }; 627 | /* End XCBuildConfiguration section */ 628 | 629 | /* Begin XCConfigurationList section */ 630 | 091A686D1FA1CAC100DAA561 /* Build configuration list for PBXProject "SPPageMenu" */ = { 631 | isa = XCConfigurationList; 632 | buildConfigurations = ( 633 | 091A689D1FA1CAC200DAA561 /* Debug */, 634 | 091A689E1FA1CAC200DAA561 /* Release */, 635 | ); 636 | defaultConfigurationIsVisible = 0; 637 | defaultConfigurationName = Release; 638 | }; 639 | 091A689F1FA1CAC200DAA561 /* Build configuration list for PBXNativeTarget "SPPageMenu" */ = { 640 | isa = XCConfigurationList; 641 | buildConfigurations = ( 642 | 091A68A01FA1CAC200DAA561 /* Debug */, 643 | 091A68A11FA1CAC200DAA561 /* Release */, 644 | ); 645 | defaultConfigurationIsVisible = 0; 646 | defaultConfigurationName = Release; 647 | }; 648 | 091A68A21FA1CAC200DAA561 /* Build configuration list for PBXNativeTarget "SPPageMenuTests" */ = { 649 | isa = XCConfigurationList; 650 | buildConfigurations = ( 651 | 091A68A31FA1CAC200DAA561 /* Debug */, 652 | 091A68A41FA1CAC200DAA561 /* Release */, 653 | ); 654 | defaultConfigurationIsVisible = 0; 655 | defaultConfigurationName = Release; 656 | }; 657 | 091A68A51FA1CAC200DAA561 /* Build configuration list for PBXNativeTarget "SPPageMenuUITests" */ = { 658 | isa = XCConfigurationList; 659 | buildConfigurations = ( 660 | 091A68A61FA1CAC200DAA561 /* Debug */, 661 | 091A68A71FA1CAC200DAA561 /* Release */, 662 | ); 663 | defaultConfigurationIsVisible = 0; 664 | defaultConfigurationName = Release; 665 | }; 666 | /* End XCConfigurationList section */ 667 | }; 668 | rootObject = 091A686A1FA1CAC100DAA561 /* Project object */; 669 | } 670 | -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/project.xcworkspace/xcuserdata/devlop1.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu.xcodeproj/project.xcworkspace/xcuserdata/devlop1.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/project.xcworkspace/xcuserdata/libo.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu.xcodeproj/project.xcworkspace/xcuserdata/libo.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/project.xcworkspace/xcuserdata/stephen.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu.xcodeproj/project.xcworkspace/xcuserdata/stephen.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/xcshareddata/xcschemes/SPPageMenu.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/xcuserdata/devlop1.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/xcuserdata/devlop1.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SuppressBuildableAutocreation 8 | 9 | 091A68711FA1CAC100DAA561 10 | 11 | primary 12 | 13 | 14 | 091A688A1FA1CAC200DAA561 15 | 16 | primary 17 | 18 | 19 | 091A68951FA1CAC200DAA561 20 | 21 | primary 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/xcuserdata/libo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/xcuserdata/libo.xcuserdatad/xcschemes/SPPageMenu.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 44 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 62 | 63 | 64 | 65 | 76 | 78 | 84 | 85 | 86 | 87 | 88 | 89 | 95 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/xcuserdata/libo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SPPageMenu.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 091A68711FA1CAC100DAA561 16 | 17 | primary 18 | 19 | 20 | 091A688A1FA1CAC200DAA561 21 | 22 | primary 23 | 24 | 25 | 091A68951FA1CAC200DAA561 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Example/SPPageMenu.xcodeproj/xcuserdata/stephen.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SPPageMenu.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 091A68711FA1CAC100DAA561 16 | 17 | primary 18 | 19 | 20 | 091A688A1FA1CAC200DAA561 21 | 22 | primary 23 | 24 | 25 | 091A68951FA1CAC200DAA561 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Example/SPPageMenu/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu/.DS_Store -------------------------------------------------------------------------------- /Example/SPPageMenu/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. 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 | -------------------------------------------------------------------------------- /Example/SPPageMenu/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. 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 | -------------------------------------------------------------------------------- /Example/SPPageMenu/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" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/Expression_1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Expression_1@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/Expression_1.imageset/Expression_1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu/Assets.xcassets/Expression_1.imageset/Expression_1@2x.png -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/Expression_2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Expression_3@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/Expression_2.imageset/Expression_3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu/Assets.xcassets/Expression_2.imageset/Expression_3@2x.png -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/Expression_3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Expression_5@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/Expression_3.imageset/Expression_5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu/Assets.xcassets/Expression_3.imageset/Expression_5@2x.png -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/asc.imageset/1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu/Assets.xcassets/asc.imageset/1@2x.png -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/asc.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "1@2x.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/dog.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "dog.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/SPPageMenu/Assets.xcassets/dog.imageset/dog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu/Assets.xcassets/dog.imageset/dog.jpg -------------------------------------------------------------------------------- /Example/SPPageMenu/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 | -------------------------------------------------------------------------------- /Example/SPPageMenu/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 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/BaseViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BaseViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BaseViewController : UIViewController 12 | 13 | @property (nonatomic, copy) NSString *text; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/BaseViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BaseViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface BaseViewController () 12 | @property (nonatomic, strong) UITableView *tableView; 13 | @end 14 | 15 | @implementation BaseViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 21 | tableView.dataSource = self; 22 | tableView.delegate = self; 23 | [self.view addSubview:tableView]; 24 | _tableView = tableView; 25 | } 26 | 27 | - (void)viewWillLayoutSubviews { 28 | [super viewWillLayoutSubviews]; 29 | self.tableView.frame = self.view.bounds; 30 | } 31 | 32 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 33 | return 20; 34 | } 35 | 36 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 37 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[NSStringFromClass([self class]) stringByAppendingString:@"cell"]]; 38 | if (cell == nil) { 39 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:[NSStringFromClass([self class]) stringByAppendingString:@"cell"]]; 40 | } 41 | cell.textLabel.text = [NSString stringWithFormat:@"%@------第%zd行",_text,indexPath.row]; 42 | if ([_text isEqualToString:@"图片"]) { 43 | cell.detailTextLabel.text = @"注:这是图片不是emoji哦"; 44 | cell.detailTextLabel.font = [UIFont systemFontOfSize:10]; 45 | } else { 46 | cell.detailTextLabel.text = nil; 47 | } 48 | cell.textLabel.alpha = 0.7; 49 | cell.textLabel.font = [UIFont systemFontOfSize:15]; 50 | return cell; 51 | } 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/EightViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // EightViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/30. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface EightViewController : BaseViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/EightViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // EightViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/30. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "EightViewController.h" 10 | 11 | @interface EightViewController () 12 | 13 | @end 14 | 15 | @implementation EightViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // 请进入 "BaseViewController" 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/FirstViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FirstViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface FirstViewController : BaseViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/FirstViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FirstViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "FirstViewController.h" 10 | 11 | @interface FirstViewController () 12 | 13 | @end 14 | 15 | @implementation FirstViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // 请进入 "BaseViewController" 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/FiveViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FiveViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface FiveViewController : BaseViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/FiveViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FiveViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "FiveViewController.h" 10 | 11 | @interface FiveViewController () 12 | 13 | @end 14 | 15 | @implementation FiveViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // 请进入 "BaseViewController" 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/FourViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FourViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface FourViewController : BaseViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/FourViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FourViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "FourViewController.h" 10 | 11 | @interface FourViewController () 12 | 13 | @end 14 | 15 | @implementation FourViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // 请进入 "BaseViewController" 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface SecondViewController : BaseViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "SecondViewController.h" 10 | 11 | @interface SecondViewController () 12 | 13 | @end 14 | 15 | @implementation SecondViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // 请进入 "BaseViewController" 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/SevenViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SevenViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/30. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface SevenViewController : BaseViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/SevenViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SevenViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/30. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "SevenViewController.h" 10 | 11 | @interface SevenViewController () 12 | 13 | @end 14 | 15 | @implementation SevenViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // 请进入 "BaseViewController" 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/SixViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SixViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface SixViewController : BaseViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/SixViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SixViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "SixViewController.h" 10 | 11 | @interface SixViewController () 12 | 13 | @end 14 | 15 | @implementation SixViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // 请进入 "BaseViewController" 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/ThidViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ThidViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface ThidViewController : BaseViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ChildViewControllers/ThidViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ThidViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "ThidViewController.h" 10 | 11 | @interface ThidViewController () 12 | 13 | @end 14 | 15 | @implementation ThidViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // 请进入 "BaseViewController" 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Example/SPPageMenu/Images/mateor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu/Images/mateor.jpg -------------------------------------------------------------------------------- /Example/SPPageMenu/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 3.5.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 | 36 | 37 | -------------------------------------------------------------------------------- /Example/SPPageMenu/JSBadgeView/JSBadgeView.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Javier Soto. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #import 24 | 25 | typedef NS_ENUM(NSUInteger, JSBadgeViewAlignment) 26 | { 27 | JSBadgeViewAlignmentTopLeft = 1, 28 | JSBadgeViewAlignmentTopRight, 29 | JSBadgeViewAlignmentTopCenter, 30 | JSBadgeViewAlignmentCenterLeft, 31 | JSBadgeViewAlignmentCenterRight, 32 | JSBadgeViewAlignmentBottomLeft, 33 | JSBadgeViewAlignmentBottomRight, 34 | JSBadgeViewAlignmentBottomCenter, 35 | JSBadgeViewAlignmentCenter 36 | }; 37 | 38 | @interface JSBadgeView : UIView 39 | 40 | @property (nonatomic, copy) NSString *badgeText; 41 | 42 | #pragma mark - Customization 43 | 44 | @property (nonatomic, assign) JSBadgeViewAlignment badgeAlignment UI_APPEARANCE_SELECTOR; 45 | 46 | @property (nonatomic, strong) UIColor *badgeTextColor UI_APPEARANCE_SELECTOR; 47 | @property (nonatomic, assign) CGSize badgeTextShadowOffset UI_APPEARANCE_SELECTOR; 48 | @property (nonatomic, strong) UIColor *badgeTextShadowColor UI_APPEARANCE_SELECTOR; 49 | 50 | @property (nonatomic, strong) UIFont *badgeTextFont UI_APPEARANCE_SELECTOR; 51 | 52 | @property (nonatomic, strong) UIColor *badgeBackgroundColor UI_APPEARANCE_SELECTOR; 53 | 54 | /** 55 | * Color of the overlay circle at the top. Default is semi-transparent white. 56 | */ 57 | @property (nonatomic, strong) UIColor *badgeOverlayColor UI_APPEARANCE_SELECTOR; 58 | 59 | /** 60 | * Color of the badge shadow. Default is semi-transparent black. 61 | */ 62 | @property (nonatomic, strong) UIColor *badgeShadowColor UI_APPEARANCE_SELECTOR; 63 | 64 | /** 65 | * Offset of the badge shadow. Default is 3.0 points down. 66 | */ 67 | @property (nonatomic, assign) CGSize badgeShadowSize UI_APPEARANCE_SELECTOR; 68 | 69 | /** 70 | * Width of the circle around the badge. Default is 2.0 points. 71 | */ 72 | @property (nonatomic, assign) CGFloat badgeStrokeWidth UI_APPEARANCE_SELECTOR; 73 | 74 | /** 75 | * Color of the circle around the badge. Default is white. 76 | */ 77 | @property (nonatomic, strong) UIColor *badgeStrokeColor UI_APPEARANCE_SELECTOR; 78 | 79 | /** 80 | * Allows to shift the badge by x and y points. 81 | */ 82 | @property (nonatomic, assign) CGPoint badgePositionAdjustment UI_APPEARANCE_SELECTOR; 83 | 84 | /** 85 | * You can use this to position the view if you're drawing it using drawRect instead of `-addSubview:` 86 | * (optional) If not provided, the superview frame is used. 87 | */ 88 | @property (nonatomic, assign) CGRect frameToPositionInRelationWith UI_APPEARANCE_SELECTOR; 89 | 90 | /** 91 | * The minimum width of a badge circle. We need this to avoid elipse shapes when using small fonts. 92 | */ 93 | @property (nonatomic, assign) CGFloat badgeMinWidth UI_APPEARANCE_SELECTOR; 94 | 95 | /** 96 | * Optionally init using this method to have the badge automatically added to another view. 97 | */ 98 | - (id)initWithParentView:(UIView *)parentView alignment:(JSBadgeViewAlignment)alignment; 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /Example/SPPageMenu/JSBadgeView/JSBadgeView.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Javier Soto. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #import "JSBadgeView.h" 24 | 25 | #import 26 | #include 27 | 28 | #if !__has_feature(objc_arc) 29 | #error JSBadgeView must be compiled with ARC. 30 | #endif 31 | 32 | // Silencing some deprecation warnings if your deployment target is iOS7 that can only be fixed by using methods that 33 | // Are only available on iOS7. 34 | // Soon JSBadgeView will require iOS 7 and we'll be able to use the new methods. 35 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 36 | #define JSBadgeViewSilenceDeprecatedMethodStart() _Pragma("clang diagnostic push") \ 37 | _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") 38 | #define JSBadgeViewSilenceDeprecatedMethodEnd() _Pragma("clang diagnostic pop") 39 | #else 40 | #define JSBadgeViewSilenceDeprecatedMethodStart() 41 | #define JSBadgeViewSilenceDeprecatedMethodEnd() 42 | #endif 43 | 44 | static const CGFloat JSBadgeViewShadowRadius = 1.0f; 45 | static const CGFloat JSBadgeViewHeight = 16.0f; 46 | static const CGFloat JSBadgeViewTextSideMargin = 8.0f; 47 | static const CGFloat JSBadgeViewCornerRadius = 10.0f; 48 | 49 | // Thanks to Peter Steinberger: https://gist.github.com/steipete/6526860 50 | static BOOL JSBadgeViewIsUIKitFlatMode(void) 51 | { 52 | static BOOL isUIKitFlatMode = NO; 53 | static dispatch_once_t onceToken; 54 | dispatch_once(&onceToken, ^{ 55 | #ifndef kCFCoreFoundationVersionNumber_iOS_7_0 56 | #define kCFCoreFoundationVersionNumber_iOS_7_0 847.2 57 | #endif 58 | #ifndef UIKitVersionNumber_iOS_7_0 59 | #define UIKitVersionNumber_iOS_7_0 0xB57 60 | #endif 61 | // We get the modern UIKit if system is running >= iOS 7 and we were linked with >= SDK 7. 62 | if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0) { 63 | isUIKitFlatMode = (NSVersionOfLinkTimeLibrary("UIKit") >> 16) >= UIKitVersionNumber_iOS_7_0; 64 | } 65 | }); 66 | 67 | return isUIKitFlatMode; 68 | } 69 | 70 | @implementation JSBadgeView 71 | 72 | + (void)applyCommonStyle 73 | { 74 | JSBadgeView *badgeViewAppearanceProxy = JSBadgeView.appearance; 75 | 76 | badgeViewAppearanceProxy.backgroundColor = UIColor.clearColor; 77 | badgeViewAppearanceProxy.badgeAlignment = JSBadgeViewAlignmentTopRight; 78 | badgeViewAppearanceProxy.badgeBackgroundColor = UIColor.redColor; 79 | badgeViewAppearanceProxy.badgeTextFont = [UIFont boldSystemFontOfSize:UIFont.systemFontSize]; 80 | badgeViewAppearanceProxy.badgeTextColor = UIColor.whiteColor; 81 | } 82 | 83 | + (void)applyLegacyStyle 84 | { 85 | JSBadgeView *badgeViewAppearanceProxy = JSBadgeView.appearance; 86 | 87 | badgeViewAppearanceProxy.badgeOverlayColor = [UIColor colorWithWhite:1.0f alpha:0.3]; 88 | badgeViewAppearanceProxy.badgeTextShadowColor = UIColor.clearColor; 89 | badgeViewAppearanceProxy.badgeShadowColor = [UIColor colorWithWhite:0.0f alpha:0.4f]; 90 | badgeViewAppearanceProxy.badgeShadowSize = CGSizeMake(0.0f, 3.0f); 91 | badgeViewAppearanceProxy.badgeStrokeWidth = 2.0f; 92 | badgeViewAppearanceProxy.badgeStrokeColor = UIColor.whiteColor; 93 | } 94 | 95 | + (void)applyIOS7Style 96 | { 97 | JSBadgeView *badgeViewAppearanceProxy = JSBadgeView.appearance; 98 | 99 | badgeViewAppearanceProxy.badgeOverlayColor = UIColor.clearColor; 100 | badgeViewAppearanceProxy.badgeTextShadowColor = UIColor.clearColor; 101 | badgeViewAppearanceProxy.badgeShadowColor = UIColor.clearColor; 102 | badgeViewAppearanceProxy.badgeStrokeWidth = 0.0f; 103 | badgeViewAppearanceProxy.badgeStrokeColor = badgeViewAppearanceProxy.badgeBackgroundColor; 104 | } 105 | 106 | + (void)initialize 107 | { 108 | if (self == JSBadgeView.class) 109 | { 110 | [self applyCommonStyle]; 111 | 112 | if (JSBadgeViewIsUIKitFlatMode()) 113 | { 114 | [self applyIOS7Style]; 115 | } 116 | else 117 | { 118 | [self applyLegacyStyle]; 119 | } 120 | } 121 | } 122 | 123 | - (id)initWithParentView:(UIView *)parentView alignment:(JSBadgeViewAlignment)alignment 124 | { 125 | if ((self = [self initWithFrame:CGRectZero])) 126 | { 127 | self.badgeAlignment = alignment; 128 | [parentView addSubview:self]; 129 | } 130 | 131 | return self; 132 | } 133 | 134 | #pragma mark - Layout 135 | 136 | - (CGFloat)marginToDrawInside 137 | { 138 | return self.badgeStrokeWidth * 2.0f; 139 | } 140 | 141 | - (void)layoutSubviews 142 | { 143 | [super layoutSubviews]; 144 | 145 | CGRect newFrame = self.frame; 146 | const CGRect superviewBounds = CGRectIsEmpty(_frameToPositionInRelationWith) ? self.superview.bounds : _frameToPositionInRelationWith; 147 | 148 | const CGFloat textWidth = [self sizeOfTextForCurrentSettings].width; 149 | 150 | const CGFloat marginToDrawInside = [self marginToDrawInside]; 151 | const CGFloat viewWidth = MAX(_badgeMinWidth, textWidth + JSBadgeViewTextSideMargin + (marginToDrawInside * 2)); 152 | const CGFloat viewHeight = JSBadgeViewHeight + (marginToDrawInside * 2); 153 | 154 | const CGFloat superviewWidth = superviewBounds.size.width; 155 | const CGFloat superviewHeight = superviewBounds.size.height; 156 | 157 | newFrame.size.width = MAX(viewWidth, viewHeight); 158 | newFrame.size.height = viewHeight; 159 | 160 | switch (self.badgeAlignment) { 161 | case JSBadgeViewAlignmentTopLeft: 162 | newFrame.origin.x = -viewWidth / 2.0f; 163 | newFrame.origin.y = -viewHeight / 2.0f; 164 | break; 165 | case JSBadgeViewAlignmentTopRight: 166 | newFrame.origin.x = superviewWidth - (viewWidth / 2.0f); 167 | newFrame.origin.y = -viewHeight / 2.0f; 168 | break; 169 | case JSBadgeViewAlignmentTopCenter: 170 | newFrame.origin.x = (superviewWidth - viewWidth) / 2.0f; 171 | newFrame.origin.y = -viewHeight / 2.0f; 172 | break; 173 | case JSBadgeViewAlignmentCenterLeft: 174 | newFrame.origin.x = -viewWidth / 2.0f; 175 | newFrame.origin.y = (superviewHeight - viewHeight) / 2.0f; 176 | break; 177 | case JSBadgeViewAlignmentCenterRight: 178 | newFrame.origin.x = superviewWidth - (viewWidth / 2.0f); 179 | newFrame.origin.y = (superviewHeight - viewHeight) / 2.0f; 180 | break; 181 | case JSBadgeViewAlignmentBottomLeft: 182 | newFrame.origin.x = -viewWidth / 2.0f; 183 | newFrame.origin.y = superviewHeight - (viewHeight / 2.0f); 184 | break; 185 | case JSBadgeViewAlignmentBottomRight: 186 | newFrame.origin.x = superviewWidth - (viewWidth / 2.0f); 187 | newFrame.origin.y = superviewHeight - (viewHeight / 2.0f); 188 | break; 189 | case JSBadgeViewAlignmentBottomCenter: 190 | newFrame.origin.x = (superviewWidth - viewWidth) / 2.0f; 191 | newFrame.origin.y = superviewHeight - (viewHeight / 2.0f); 192 | break; 193 | case JSBadgeViewAlignmentCenter: 194 | newFrame.origin.x = (superviewWidth - viewWidth) / 2.0f; 195 | newFrame.origin.y = (superviewHeight - viewHeight) / 2.0f; 196 | break; 197 | default: 198 | NSAssert(NO, @"Unimplemented JSBadgeAligment type %lul", (unsigned long)self.badgeAlignment); 199 | } 200 | 201 | newFrame.origin.x += _badgePositionAdjustment.x; 202 | newFrame.origin.y += _badgePositionAdjustment.y; 203 | 204 | // Do not set frame directly so we do not interfere with any potential transform set on the view. 205 | self.bounds = CGRectIntegral(CGRectMake(0, 0, CGRectGetWidth(newFrame), CGRectGetHeight(newFrame))); 206 | self.center = CGPointMake(ceilf(CGRectGetMidX(newFrame)), ceilf(CGRectGetMidY(newFrame))); 207 | 208 | [self setNeedsDisplay]; 209 | } 210 | 211 | #pragma mark - Private 212 | 213 | - (CGSize)sizeOfTextForCurrentSettings 214 | { 215 | JSBadgeViewSilenceDeprecatedMethodStart(); 216 | return [self.badgeText sizeWithFont:self.badgeTextFont]; 217 | JSBadgeViewSilenceDeprecatedMethodEnd(); 218 | } 219 | 220 | #pragma mark - Setters 221 | 222 | - (void)setBadgeAlignment:(JSBadgeViewAlignment)badgeAlignment 223 | { 224 | if (badgeAlignment != _badgeAlignment) 225 | { 226 | _badgeAlignment = badgeAlignment; 227 | 228 | [self setNeedsLayout]; 229 | } 230 | } 231 | 232 | - (void)setBadgePositionAdjustment:(CGPoint)badgePositionAdjustment 233 | { 234 | _badgePositionAdjustment = badgePositionAdjustment; 235 | 236 | [self setNeedsLayout]; 237 | } 238 | 239 | - (void)setBadgeText:(NSString *)badgeText 240 | { 241 | if (badgeText != _badgeText) 242 | { 243 | _badgeText = [badgeText copy]; 244 | 245 | [self setNeedsLayout]; 246 | } 247 | } 248 | 249 | - (void)setBadgeTextColor:(UIColor *)badgeTextColor 250 | { 251 | if (badgeTextColor != _badgeTextColor) 252 | { 253 | _badgeTextColor = badgeTextColor; 254 | 255 | [self setNeedsDisplay]; 256 | } 257 | } 258 | 259 | - (void)setBadgeTextShadowColor:(UIColor *)badgeTextShadowColor 260 | { 261 | if (badgeTextShadowColor != _badgeTextShadowColor) 262 | { 263 | _badgeTextShadowColor = badgeTextShadowColor; 264 | 265 | [self setNeedsDisplay]; 266 | } 267 | } 268 | 269 | - (void)setBadgeTextShadowOffset:(CGSize)badgeTextShadowOffset 270 | { 271 | _badgeTextShadowOffset = badgeTextShadowOffset; 272 | 273 | [self setNeedsDisplay]; 274 | } 275 | 276 | - (void)setBadgeTextFont:(UIFont *)badgeTextFont 277 | { 278 | if (badgeTextFont != _badgeTextFont) 279 | { 280 | _badgeTextFont = badgeTextFont; 281 | 282 | [self setNeedsLayout]; 283 | [self setNeedsDisplay]; 284 | } 285 | } 286 | 287 | - (void)setBadgeBackgroundColor:(UIColor *)badgeBackgroundColor 288 | { 289 | if (badgeBackgroundColor != _badgeBackgroundColor) 290 | { 291 | _badgeBackgroundColor = badgeBackgroundColor; 292 | 293 | [self setNeedsDisplay]; 294 | } 295 | } 296 | 297 | - (void)setBadgeStrokeWidth:(CGFloat)badgeStrokeWidth 298 | { 299 | if (badgeStrokeWidth != _badgeStrokeWidth) 300 | { 301 | _badgeStrokeWidth = badgeStrokeWidth; 302 | 303 | [self setNeedsLayout]; 304 | [self setNeedsDisplay]; 305 | } 306 | } 307 | 308 | - (void)setBadgeStrokeColor:(UIColor *)badgeStrokeColor 309 | { 310 | if (badgeStrokeColor != _badgeStrokeColor) 311 | { 312 | _badgeStrokeColor = badgeStrokeColor; 313 | 314 | [self setNeedsDisplay]; 315 | } 316 | } 317 | 318 | - (void)setBadgeShadowColor:(UIColor *)badgeShadowColor 319 | { 320 | if (badgeShadowColor != _badgeShadowColor) 321 | { 322 | _badgeShadowColor = badgeShadowColor; 323 | 324 | [self setNeedsDisplay]; 325 | } 326 | } 327 | 328 | - (void)setBadgeShadowSize:(CGSize)badgeShadowSize 329 | { 330 | if (!CGSizeEqualToSize(badgeShadowSize, _badgeShadowSize)) 331 | { 332 | _badgeShadowSize = badgeShadowSize; 333 | 334 | [self setNeedsDisplay]; 335 | } 336 | } 337 | 338 | #pragma mark - Drawing 339 | 340 | - (void)drawRect:(CGRect)rect 341 | { 342 | const BOOL anyTextToDraw = (self.badgeText.length > 0); 343 | 344 | if (anyTextToDraw) 345 | { 346 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 347 | 348 | const CGFloat marginToDrawInside = [self marginToDrawInside]; 349 | const CGRect rectToDraw = CGRectInset(rect, marginToDrawInside, marginToDrawInside); 350 | 351 | UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:rectToDraw byRoundingCorners:(UIRectCorner)UIRectCornerAllCorners cornerRadii:CGSizeMake(JSBadgeViewCornerRadius, JSBadgeViewCornerRadius)]; 352 | 353 | /* Background and shadow */ 354 | CGContextSaveGState(ctx); 355 | { 356 | CGContextAddPath(ctx, borderPath.CGPath); 357 | 358 | CGContextSetFillColorWithColor(ctx, self.badgeBackgroundColor.CGColor); 359 | CGContextSetShadowWithColor(ctx, self.badgeShadowSize, JSBadgeViewShadowRadius, self.badgeShadowColor.CGColor); 360 | 361 | CGContextDrawPath(ctx, kCGPathFill); 362 | } 363 | CGContextRestoreGState(ctx); 364 | 365 | const BOOL colorForOverlayPresent = self.badgeOverlayColor && ![self.badgeOverlayColor isEqual:[UIColor clearColor]]; 366 | 367 | if (colorForOverlayPresent) 368 | { 369 | /* Gradient overlay */ 370 | CGContextSaveGState(ctx); 371 | { 372 | CGContextAddPath(ctx, borderPath.CGPath); 373 | CGContextClip(ctx); 374 | 375 | const CGFloat height = rectToDraw.size.height; 376 | const CGFloat width = rectToDraw.size.width; 377 | 378 | const CGRect rectForOverlayCircle = CGRectMake(rectToDraw.origin.x, 379 | rectToDraw.origin.y - ceilf(height * 0.5), 380 | width, 381 | height); 382 | 383 | CGContextAddEllipseInRect(ctx, rectForOverlayCircle); 384 | CGContextSetFillColorWithColor(ctx, self.badgeOverlayColor.CGColor); 385 | 386 | CGContextDrawPath(ctx, kCGPathFill); 387 | } 388 | CGContextRestoreGState(ctx); 389 | } 390 | 391 | /* Stroke */ 392 | CGContextSaveGState(ctx); 393 | { 394 | CGContextAddPath(ctx, borderPath.CGPath); 395 | 396 | CGContextSetLineWidth(ctx, self.badgeStrokeWidth); 397 | CGContextSetStrokeColorWithColor(ctx, self.badgeStrokeColor.CGColor); 398 | 399 | CGContextDrawPath(ctx, kCGPathStroke); 400 | } 401 | CGContextRestoreGState(ctx); 402 | 403 | /* Text */ 404 | 405 | CGContextSaveGState(ctx); 406 | { 407 | CGContextSetFillColorWithColor(ctx, self.badgeTextColor.CGColor); 408 | CGContextSetShadowWithColor(ctx, self.badgeTextShadowOffset, 1.0, self.badgeTextShadowColor.CGColor); 409 | 410 | CGRect textFrame = rectToDraw; 411 | const CGSize textSize = [self sizeOfTextForCurrentSettings]; 412 | 413 | textFrame.size.height = textSize.height; 414 | textFrame.origin.y = rectToDraw.origin.y + floorf((rectToDraw.size.height - textFrame.size.height) / 2.0f); 415 | 416 | JSBadgeViewSilenceDeprecatedMethodStart(); 417 | [self.badgeText drawInRect:textFrame 418 | withFont:self.badgeTextFont 419 | lineBreakMode:NSLineBreakByClipping 420 | alignment:NSTextAlignmentCenter]; 421 | JSBadgeViewSilenceDeprecatedMethodEnd(); 422 | } 423 | CGContextRestoreGState(ctx); 424 | } 425 | } 426 | 427 | @end -------------------------------------------------------------------------------- /Example/SPPageMenu/ParentViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ParentViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/29. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ParentViewController : UIViewController 12 | 13 | @property (nonatomic, assign) NSInteger testNumber; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ParentViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "ParentViewController.h" 10 | #import "SPPageMenu.h" 11 | #import "BaseViewController.h" 12 | #import "FirstViewController.h" 13 | #import "SecondViewController.h" 14 | #import "ThidViewController.h" 15 | #import "FourViewController.h" 16 | #import "FiveViewController.h" 17 | #import "SixViewController.h" 18 | #import "SevenViewController.h" 19 | #import "EightViewController.h" 20 | 21 | #import "JSBadgeView.h" 22 | 23 | #define screenW [UIScreen mainScreen].bounds.size.width 24 | #define screenH [UIScreen mainScreen].bounds.size.height 25 | #define pageMenuH 40 26 | #define NaviH (screenH >= 812 ? 88 : 64) // 812是iPhoneX的高度 27 | #define scrollViewHeight (screenH-NaviH-pageMenuH) 28 | 29 | @interface ParentViewController () 30 | @property (nonatomic, strong) NSArray *dataArr; 31 | @property (nonatomic, weak) SPPageMenu *pageMenu; 32 | @property (nonatomic, strong) UIScrollView *scrollView; 33 | @property (nonatomic, strong) NSMutableArray *myChildViewControllers; 34 | @end 35 | 36 | @implementation ParentViewController 37 | 38 | // 示例1:SPPageMenuTrackerStyleLine,下划线样式 39 | - (void)test1 { 40 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"搞笑",@"综艺"]; 41 | 42 | // trackerStyle:跟踪器的样式 43 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLine]; 44 | // 传递数组,默认选中第2个 45 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 46 | // 设置代理 47 | pageMenu.delegate = self; 48 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 49 | pageMenu.bridgeScrollView = self.scrollView; 50 | [self.view addSubview:pageMenu]; 51 | _pageMenu = pageMenu; 52 | } 53 | 54 | // 示例2:SPPageMenuTrackerStyleLineLongerThanItem,下划线比item略长,长度等于tem宽+间距 55 | // 这个例子采用自动布局 56 | - (void)test2 { 57 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"搞笑",@"综艺"]; 58 | 59 | // trackerStyle:跟踪器的样式 60 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectZero trackerStyle:SPPageMenuTrackerStyleLineLongerThanItem]; 61 | pageMenu.translatesAutoresizingMaskIntoConstraints = NO; 62 | // 传递数组,默认选中第1个 63 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 64 | // 设置代理 65 | pageMenu.delegate = self; 66 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 67 | pageMenu.bridgeScrollView = self.scrollView; 68 | [self.view addSubview:pageMenu]; 69 | 70 | NSMutableArray *contraints = [NSMutableArray array]; 71 | [contraints addObject:[NSLayoutConstraint constraintWithItem:pageMenu attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:NaviH]]; 72 | [contraints addObject:[NSLayoutConstraint constraintWithItem:pageMenu attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:pageMenuH]]; 73 | [contraints addObject:[NSLayoutConstraint constraintWithItem:pageMenu attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0]]; 74 | [contraints addObject:[NSLayoutConstraint constraintWithItem:pageMenu attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0]]; 75 | [self.view addConstraints:contraints]; 76 | 77 | _pageMenu = pageMenu; 78 | } 79 | 80 | // 示例3:SPPageMenuTrackerStyleLineAttachment,下划线依恋样式,当滑动底下装载控制器的scrollView时,该下划线会有阻尼效果 81 | - (void)test3 { 82 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"搞笑",@"综艺"]; 83 | 84 | // trackerStyle:跟踪器的样式 85 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLineAttachment]; 86 | // 传递数组,默认选中第2个 87 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 88 | // 设置代理 89 | pageMenu.delegate = self; 90 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 91 | pageMenu.bridgeScrollView = self.scrollView; 92 | [self.view addSubview:pageMenu]; 93 | _pageMenu = pageMenu; 94 | } 95 | 96 | // 示例4:SPPageMenuTrackerStyleTextZoom、SPPageMenuTrackerStyleNothing,缩放 97 | - (void)test4 { 98 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"搞笑",@"综艺"]; 99 | 100 | // trackerStyle:跟踪器的样式 101 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleNothing]; 102 | // 传递数组,默认选中第1个 103 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 104 | // 设置缩放 105 | pageMenu.selectedItemZoomScale = 1.3; 106 | // 设置代理 107 | pageMenu.delegate = self; 108 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 109 | pageMenu.bridgeScrollView = self.scrollView; 110 | 111 | [self.view addSubview:pageMenu]; 112 | _pageMenu = pageMenu; 113 | } 114 | 115 | // 示例5:SPPageMenuTrackerStyleRoundedRect,圆角矩形 116 | - (void)test5 { 117 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"搞笑",@"综艺"]; 118 | 119 | // trackerStyle:跟踪器的样式 120 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleRoundedRect]; 121 | // 传递数组,默认选中第1个 122 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 123 | pageMenu.tracker.backgroundColor = [UIColor redColor]; 124 | // 设置代理 125 | pageMenu.delegate = self; 126 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 127 | pageMenu.bridgeScrollView = self.scrollView; 128 | [self.view addSubview:pageMenu]; 129 | _pageMenu = pageMenu; 130 | } 131 | 132 | // 示例6:SPPageMenuTrackerStyleRoundedRect,圆角矩形(与pageMenu同时圆角) 133 | - (void)test6 { 134 | self.dataArr = @[@"生活",@"影视中心",@"交通"]; 135 | 136 | // trackerStyle:跟踪器的样式 137 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(15, NaviH, screenW-30, pageMenuH) trackerStyle:SPPageMenuTrackerStyleRoundedRect]; 138 | // 设置pageMenu边框 139 | pageMenu.layer.borderWidth = 1; 140 | pageMenu.layer.borderColor = [UIColor redColor].CGColor; 141 | pageMenu.layer.cornerRadius = pageMenuH * 0.5; 142 | // 传递数组,默认选中第1个 143 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 144 | pageMenu.unSelectedItemTitleColor = [UIColor redColor]; 145 | // 设置跟踪器的颜色 146 | pageMenu.tracker.backgroundColor = [UIColor redColor]; 147 | // 设置跟踪器的高度,与pageMenu同高,这样半径就可以跟pageMenu的圆角半径一致,实际上这里设置的半径是无效的,圆角矩形内部会根据高度自动设置圆角 148 | [pageMenu setTrackerHeight:pageMenuH cornerRadius:pageMenuH*0.5]; 149 | // 排列方式 150 | pageMenu.permutationWay = SPPageMenuPermutationWayNotScrollAdaptContent; 151 | pageMenu.dividingLine.hidden = YES; 152 | 153 | // 设置代理 154 | pageMenu.delegate = self; 155 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 156 | pageMenu.bridgeScrollView = self.scrollView; 157 | [self.view addSubview:pageMenu]; 158 | _pageMenu = pageMenu; 159 | } 160 | 161 | // 示例7:SPPageMenuTrackerStyleRect,矩形 162 | 163 | - (void)test7{ 164 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"搞笑",@"综艺"]; 165 | 166 | // trackerStyle:跟踪器的样式 167 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleRect]; 168 | // 传递数组,默认选中第2个 169 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 170 | // 设置代理 171 | pageMenu.delegate = self; 172 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 173 | pageMenu.bridgeScrollView = self.scrollView; 174 | [self.view addSubview:pageMenu]; 175 | _pageMenu = pageMenu; 176 | } 177 | 178 | // 示例8:无样式 179 | - (void)test8 { 180 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"搞笑",@"综艺"]; 181 | 182 | // trackerStyle:跟踪器的样式 183 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleNothing]; 184 | // 传递数组,默认选中第2个 185 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 186 | // 设置代理 187 | pageMenu.delegate = self; 188 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 189 | pageMenu.bridgeScrollView = self.scrollView; 190 | [self.view addSubview:pageMenu]; 191 | _pageMenu = pageMenu; 192 | } 193 | 194 | // 示例9:可滑动的自适应内容排列,关键代码:pageMenu.permutationWay = SPPageMenuPermutationWayScrollAdaptContent; 195 | - (void)test9 { 196 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"搞笑",@"综艺"]; 197 | 198 | // trackerStyle:跟踪器的样式 199 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLine]; 200 | // 传递数组,默认选中第2个 201 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 202 | // 可滑动的自适应内容排列 203 | pageMenu.permutationWay = SPPageMenuPermutationWayScrollAdaptContent; 204 | // 设置代理 205 | pageMenu.delegate = self; 206 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 207 | pageMenu.bridgeScrollView = self.scrollView; 208 | [self.view addSubview:pageMenu]; 209 | _pageMenu = pageMenu; 210 | } 211 | 212 | // 示例10:不可滑动的等宽排列,关键代码:pageMenu.permutationWay = SPPageMenuPermutationWayNotScrollEqualWidths; 213 | - (void)test10 { 214 | self.dataArr = @[@"生活",@"影视中心",@"交通规则"]; 215 | 216 | // trackerStyle:跟踪器的样式 217 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLine]; 218 | // 传递数组,默认选中第2个 219 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 220 | // 不可滑动的等宽排列 221 | pageMenu.permutationWay = SPPageMenuPermutationWayNotScrollEqualWidths; 222 | pageMenu.trackerWidth = 20; 223 | // 设置代理 224 | pageMenu.delegate = self; 225 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 226 | pageMenu.bridgeScrollView = self.scrollView; 227 | [self.view addSubview:pageMenu]; 228 | _pageMenu = pageMenu; 229 | } 230 | 231 | // 示例11:不可滑动的自适应内容排列,关键代码:pageMenu.permutationWay = SPPageMenuPermutationWayNotScrollAdaptContent; 232 | // 这种排列方式下,itemPadding属性无效,因为内部自动计算间距 233 | - (void)test11 { 234 | self.dataArr = @[@"生活",@"音乐榜中榜",@"交通规则"]; 235 | 236 | // trackerStyle:跟踪器的样式 237 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLine]; 238 | // 传递数组,默认选中第2个 239 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 240 | // 不可滑动的自适应内容排列 241 | pageMenu.permutationWay = SPPageMenuPermutationWayNotScrollAdaptContent; 242 | // 设置代理 243 | pageMenu.delegate = self; 244 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 245 | pageMenu.bridgeScrollView = self.scrollView; 246 | [self.view addSubview:pageMenu]; 247 | _pageMenu = pageMenu; 248 | } 249 | 250 | // 示例12:跟踪器时刻跟随外界scrollView移动 251 | - (void)test12 { 252 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"军事",@"综艺"]; 253 | 254 | // trackerStyle:跟踪器的样式 255 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLine]; 256 | // 传递数组,默认选中第2个 257 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 258 | pageMenu.trackerFollowingMode = SPPageMenuTrackerFollowingModeAlways; 259 | // 设置代理 260 | pageMenu.delegate = self; 261 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 262 | pageMenu.bridgeScrollView = self.scrollView; 263 | [self.view addSubview:pageMenu]; 264 | _pageMenu = pageMenu; 265 | } 266 | 267 | // 示例13:外界scrollVie拖动结束后,跟踪器才开始移动 268 | - (void)test13 { 269 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"军事",@"综艺"]; 270 | 271 | // trackerStyle:跟踪器的样式 272 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLine]; 273 | // 传递数组,默认选中第2个 274 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 275 | pageMenu.trackerFollowingMode = SPPageMenuTrackerFollowingModeEnd; 276 | // 设置代理 277 | pageMenu.delegate = self; 278 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 279 | pageMenu.bridgeScrollView = self.scrollView; 280 | [self.view addSubview:pageMenu]; 281 | _pageMenu = pageMenu; 282 | } 283 | 284 | // 示例14:外界scrollView拖动距离超过屏幕一半时,跟踪器开始移动 285 | - (void)test14 { 286 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"军事",@"综艺"]; 287 | 288 | // trackerStyle:跟踪器的样式 289 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLine]; 290 | // 传递数组,默认选中第2个 291 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 292 | pageMenu.trackerFollowingMode = SPPageMenuTrackerFollowingModeHalf; 293 | // 设置代理 294 | pageMenu.delegate = self; 295 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 296 | pageMenu.bridgeScrollView = self.scrollView; 297 | [self.view addSubview:pageMenu]; 298 | _pageMenu = pageMenu; 299 | } 300 | 301 | // 示例15:显示功能按钮 302 | - (void)test15 { 303 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"军事",@"综艺"]; 304 | 305 | // trackerStyle:跟踪器的样式 306 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLine]; 307 | // 传递数组,默认选中第2个 308 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 309 | pageMenu.showFuntionButton = YES; 310 | // 设置代理 311 | pageMenu.delegate = self; 312 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 313 | pageMenu.bridgeScrollView = self.scrollView; 314 | [self.view addSubview:pageMenu]; 315 | _pageMenu = pageMenu; 316 | } 317 | 318 | // 示例16:给功能按钮设置图片和文字 319 | - (void)test16 { 320 | self.dataArr = @[@"生活",@"娱乐",@"交通"]; 321 | 322 | // trackerStyle:跟踪器的样式 323 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLine]; 324 | // 传递数组,默认选中第2个 325 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 326 | // 同时设置图片和文字,如果只想要文字,image传nil,如果只想要图片,title传nil,imagePosition和ratio传0即可 327 | [pageMenu setFunctionButtonContent:[SPPageMenuButtonItem itemWithTitle:@"更多" image:[UIImage imageNamed:@"Expression_1"] imagePosition:SPItemImagePositionTop] forState:UIControlStateNormal]; 328 | [pageMenu setFunctionButtonTitleTextAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} forState:UIControlStateNormal]; 329 | pageMenu.showFuntionButton = YES; 330 | // 设置代理 331 | pageMenu.delegate = self; 332 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 333 | pageMenu.bridgeScrollView = self.scrollView; 334 | [self.view addSubview:pageMenu]; 335 | _pageMenu = pageMenu; 336 | } 337 | 338 | // 示例17:含有图片的按钮 339 | - (void)test17 { 340 | self.dataArr = @[@"生活",[UIImage imageNamed:@"Expression_1"],@"交通",[UIImage imageNamed:@"Expression_2"],@"搞笑",@"综艺"]; 341 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLineLongerThanItem]; 342 | // 传递数组,默认选中第2个 343 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 344 | pageMenu.delegate = self; 345 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 346 | pageMenu.bridgeScrollView = self.scrollView; 347 | [self.view addSubview:pageMenu]; 348 | 349 | _pageMenu = pageMenu; 350 | } 351 | 352 | // 示例18:指定按钮携带图片,或同时携带图片和文字,可以设置图片的位置和图文间距 353 | - (void)test18 { 354 | self.dataArr = @[@"生活",@"影视中心",@"交通",@"电视剧",@"搞笑",@"综艺"]; 355 | 356 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleRect]; 357 | // 传递数组,默认选中第1个 358 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 359 | // 指定第1个item为图片 360 | [pageMenu setImage:[UIImage imageNamed:@"Expression_1"] forItemAtIndex:0]; 361 | // 指定第2个item同时含有图片和文字,图片在上 362 | SPPageMenuButtonItem *item1 = [SPPageMenuButtonItem itemWithTitle:@"害羞" image:[UIImage imageNamed:@"Expression_2"]]; 363 | item1.imagePosition = SPItemImagePositionTop; 364 | [pageMenu setItem:item1 forItemAtIndex:1]; 365 | // 指定第4个item同时含有图片和文字,图片在右 366 | // [pageMenu setTitle:@"可爱的小狗" image:[UIImage imageNamed:@"dog"] imagePosition:SPItemImagePositionDefault imageRatio:0.4 imageTitleSpace:0 forItemIndex:3]; 367 | SPPageMenuButtonItem *item2 = [SPPageMenuButtonItem itemWithTitle:@"歌曲" image:[UIImage imageNamed:@"asc"] imagePosition:SPItemImagePositionRight]; 368 | [pageMenu setItem:item2 forItemAtIndex:3]; 369 | pageMenu.delegate = self; 370 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 371 | pageMenu.bridgeScrollView = self.scrollView; 372 | [self.view addSubview:pageMenu]; 373 | _pageMenu = pageMenu; 374 | } 375 | 376 | // 示例19:设置背景图片 377 | - (void)test19 { 378 | self.dataArr = @[@"生活",@"校园",@"交通",@"军事",@"搞笑",@"综艺"]; 379 | 380 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleNothing]; 381 | // 传递数组,默认选中第2个 382 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 383 | pageMenu.selectedItemTitleColor = [UIColor whiteColor]; 384 | pageMenu.unSelectedItemTitleColor = [UIColor whiteColor]; 385 | pageMenu.selectedItemZoomScale = 1.5; 386 | pageMenu.delegate = self; 387 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 388 | pageMenu.bridgeScrollView = self.scrollView; 389 | 390 | UIImage *image = [UIImage imageNamed:@"mateor.jpg"]; 391 | [pageMenu setBackgroundImage:image barMetrics:0]; 392 | 393 | [self.view addSubview:pageMenu]; 394 | 395 | _pageMenu = pageMenu; 396 | } 397 | 398 | // 示例20:某个按钮上添加一个副标题 399 | - (void)test20 { 400 | self.dataArr = @[@"点菜",@"评论",@"商家",@"已购"]; 401 | 402 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleLineAttachment]; 403 | // 传递数组,默认选中第2个 404 | [pageMenu setItems:self.dataArr selectedItemIndex:0]; 405 | pageMenu.itemTitleFont = [UIFont boldSystemFontOfSize:17]; 406 | pageMenu.selectedItemTitleColor = [UIColor blackColor]; 407 | pageMenu.unSelectedItemTitleColor = [UIColor grayColor]; 408 | pageMenu.trackerWidth = 20; 409 | // 设置第一个按钮后面的自定义间距为60,增大第一个和第二个按钮之间的间距,腾出空间方便在第一个按钮的后面放置一个副标题 410 | [pageMenu setCustomSpacing:60 afterItemAtIndex:1]; 411 | pageMenu.delegate = self; 412 | pageMenu.permutationWay = SPPageMenuPermutationWayNotScrollEqualWidths; 413 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 414 | pageMenu.bridgeScrollView = self.scrollView; 415 | [self.view addSubview:pageMenu]; 416 | _pageMenu = pageMenu; 417 | 418 | // 获取第1个item上文字相对pageMenu的位置大小 419 | CGRect titleRect = [pageMenu titleRectRelativeToPageMenuForItemAtIndex:1]; 420 | 421 | UILabel *detailLabel = [[UILabel alloc] init]; 422 | detailLabel.text = @"8384"; 423 | detailLabel.font = [UIFont systemFontOfSize:11]; 424 | detailLabel.textColor = [UIColor lightGrayColor]; 425 | detailLabel.frame = CGRectMake(CGRectGetMaxX(titleRect),CGRectGetMaxY(titleRect)-16, 50, 16); 426 | [pageMenu addComponentViewInScrollView:detailLabel]; 427 | } 428 | 429 | // 示例21:给指定按钮加角标 430 | - (void)test21 { 431 | self.dataArr = @[@"生活",@"军事",@"水木年华",@"综艺"]; 432 | 433 | SPPageMenu *pageMenu = [SPPageMenu pageMenuWithFrame:CGRectMake(0, NaviH, screenW, pageMenuH) trackerStyle:SPPageMenuTrackerStyleNothing]; 434 | // 传递数组,默认选中第2个 435 | [pageMenu setItems:self.dataArr selectedItemIndex:1]; 436 | pageMenu.delegate = self; 437 | pageMenu.permutationWay = SPPageMenuPermutationWayNotScrollAdaptContent; 438 | // 给pageMenu传递外界的大scrollView,内部监听self.scrollView的滚动,从而实现让跟踪器跟随self.scrollView移动的效果 439 | pageMenu.bridgeScrollView = self.scrollView; 440 | 441 | // 这里通过KVC的形式取出按钮数组,再通过下标获取指定的按钮。本框架没有特别提供返回指定按钮的方法,因为按钮是不能返回的,一旦返回,该按钮的属性就可以被外界轻松地任意修改,这是一个框架该考虑的安全问题。如果专门提供一个设置角标的方法,那么角标的样式又可以自定义,角标并非本框架的核心功能,所以没必要因为它将框架搞得过于臃肿。 442 | NSArray *buttons = [pageMenu valueForKey:@"_buttons"]; 443 | UIButton *button0 = [buttons objectAtIndex:0]; 444 | JSBadgeView *badgeView0 = [[JSBadgeView alloc] initWithParentView:button0.titleLabel alignment:JSBadgeViewAlignmentTopRight]; 445 | badgeView0.badgePositionAdjustment = CGPointMake(10, 0); 446 | badgeView0.badgeBackgroundColor = [UIColor redColor]; 447 | badgeView0.badgeOverlayColor = [UIColor clearColor]; 448 | badgeView0.badgeStrokeColor = [UIColor redColor]; 449 | badgeView0.badgeText = @"3"; 450 | 451 | UIButton *button1 = [buttons objectAtIndex:2]; 452 | JSBadgeView *badgeView2 = [[JSBadgeView alloc] initWithParentView:button1.titleLabel alignment:JSBadgeViewAlignmentTopRight]; 453 | badgeView2.badgePositionAdjustment = CGPointMake(10, 0); 454 | badgeView2.badgeBackgroundColor = [UIColor whiteColor]; 455 | badgeView2.badgeOverlayColor = [UIColor clearColor]; 456 | badgeView2.badgeStrokeColor = [UIColor redColor]; 457 | badgeView2.badgeTextColor = [UIColor redColor]; 458 | badgeView2.badgeMinWidth = 1.0 / [UIScreen mainScreen].scale; 459 | badgeView2.badgeText = @"99"; 460 | 461 | [self.view addSubview:pageMenu]; 462 | 463 | _pageMenu = pageMenu; 464 | } 465 | 466 | // ------------------------------------------------------------------------------------------------ 467 | - (void)viewDidLoad { 468 | [super viewDidLoad]; 469 | 470 | self.view.backgroundColor = [UIColor whiteColor]; 471 | 472 | switch (_testNumber) { 473 | case 0: 474 | [self test1]; 475 | break; 476 | case 1: 477 | [self test2]; 478 | break; 479 | case 2: 480 | [self test3]; 481 | break; 482 | case 3: 483 | [self test4]; 484 | break; 485 | case 4: 486 | [self test5]; 487 | break; 488 | case 5: 489 | [self test6]; 490 | break; 491 | case 6: 492 | [self test7]; 493 | break; 494 | case 7: 495 | [self test8]; 496 | break; 497 | case 8: 498 | [self test9]; 499 | break; 500 | case 9: 501 | [self test10]; 502 | break; 503 | case 10: 504 | [self test11]; 505 | break; 506 | case 11: 507 | [self test12]; 508 | break; 509 | case 12: 510 | [self test13]; 511 | break; 512 | case 13: 513 | [self test14]; 514 | break; 515 | case 14: 516 | [self test15]; 517 | break; 518 | case 15: 519 | [self test16]; 520 | break; 521 | case 16: 522 | [self test17]; 523 | break; 524 | case 17: 525 | [self test18]; 526 | break; 527 | case 18: 528 | [self test19]; 529 | break; 530 | case 19: 531 | [self test20]; 532 | break; 533 | case 20: 534 | [self test21]; 535 | break; 536 | } 537 | 538 | [self.view addSubview:self.scrollView]; 539 | 540 | NSArray *controllerClassNames = [NSArray arrayWithObjects:@"FirstViewController",@"SecondViewController",@"ThidViewController",@"FourViewController",@"FiveViewController",@"SixViewController",@"SevenViewController",@"EightViewController", nil]; 541 | for (int i = 0; i < self.dataArr.count; i++) { 542 | if (controllerClassNames.count > i) { 543 | BaseViewController *baseVc = [[NSClassFromString(controllerClassNames[i]) alloc] init]; 544 | id object = [self.pageMenu contentForItemAtIndex:i]; 545 | if ([object isKindOfClass:[NSString class]]) { 546 | baseVc.text = object; 547 | } else if ([object isKindOfClass:[UIImage class]]) { 548 | baseVc.text = @"图片"; 549 | } else { 550 | SPPageMenuButtonItem *item = (SPPageMenuButtonItem *)object; 551 | baseVc.text = item.title; 552 | } 553 | [self addChildViewController:baseVc]; 554 | // 控制器本来自带childViewControllers,但是遗憾的是该数组的元素顺序永远无法改变,只要是addChildViewController,都是添加到最后一个,而控制器不像数组那样,可以插入或删除任意位置,所以这里自己定义可变数组,以便插入(删除)(如果没有插入(删除)功能,直接用自带的childViewControllers即可) 555 | [self.myChildViewControllers addObject:baseVc]; 556 | } 557 | } 558 | 559 | // pageMenu.selectedItemIndex就是选中的item下标 560 | if (self.pageMenu.selectedItemIndex < self.myChildViewControllers.count) { 561 | BaseViewController *baseVc = self.myChildViewControllers[self.pageMenu.selectedItemIndex]; 562 | [self.scrollView addSubview:baseVc.view]; 563 | baseVc.view.frame = CGRectMake(screenW*self.pageMenu.selectedItemIndex, 0, screenW, scrollViewHeight); 564 | self.scrollView .contentOffset = CGPointMake(screenW*self.pageMenu.selectedItemIndex, 0); 565 | self.scrollView .contentSize = CGSizeMake(self.dataArr.count*screenW, 0); 566 | } 567 | } 568 | 569 | #pragma mark - SPPageMenu的代理方法 570 | 571 | - (void)pageMenu:(SPPageMenu *)pageMenu itemSelectedAtIndex:(NSInteger)index { 572 | NSLog(@"%zd",index); 573 | } 574 | 575 | - (void)pageMenu:(SPPageMenu *)pageMenu itemSelectedFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex { 576 | NSLog(@"%zd------->%zd",fromIndex,toIndex); 577 | 578 | // 如果该代理方法是由拖拽self.scrollView而触发,说明self.scrollView已经在用户手指的拖拽下而发生偏移,此时不需要再用代码去设置偏移量,否则在跟踪模式为SPPageMenuTrackerFollowingModeHalf的情况下,滑到屏幕一半时会有闪跳现象。闪跳是因为外界设置的scrollView偏移和用户拖拽产生冲突 579 | if (!self.scrollView.isDragging) { // 判断用户是否在拖拽scrollView 580 | // 如果fromIndex与toIndex之差大于等于2,说明跨界面移动了,此时不动画. 581 | if (labs(toIndex - fromIndex) >= 2) { 582 | [self.scrollView setContentOffset:CGPointMake(screenW * toIndex, 0) animated:NO]; 583 | } else { 584 | [self.scrollView setContentOffset:CGPointMake(screenW * toIndex, 0) animated:YES]; 585 | } 586 | } 587 | 588 | if (self.myChildViewControllers.count <= toIndex) {return;} 589 | 590 | UIViewController *targetViewController = self.myChildViewControllers[toIndex]; 591 | // 如果已经加载过,就不再加载 592 | if ([targetViewController isViewLoaded]) return; 593 | 594 | targetViewController.view.frame = CGRectMake(screenW * toIndex, 0, screenW, scrollViewHeight); 595 | [_scrollView addSubview:targetViewController.view]; 596 | 597 | } 598 | 599 | - (void)pageMenu:(SPPageMenu *)pageMenu functionButtonClicked:(UIButton *)functionButton { 600 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; 601 | UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"插入一个带标题的item" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 602 | [self insertItemWithObject:@"十九大" toIndex:0]; 603 | }]; 604 | UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"插入一个带图片的item" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 605 | [self insertItemWithObject:[UIImage imageNamed:@"Expression_1"] toIndex:0]; 606 | }]; 607 | UIAlertAction *action3 = [UIAlertAction actionWithTitle:@"删除一个item" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { 608 | [self removeItemAtIndex:0]; 609 | }]; 610 | UIAlertAction *action4 = [UIAlertAction actionWithTitle:@"删除所有item" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { 611 | [self removeAllItems]; 612 | }]; 613 | UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 614 | 615 | }]; 616 | [alertController addAction:action1]; 617 | [alertController addAction:action2]; 618 | [alertController addAction:action3]; 619 | [alertController addAction:action4]; 620 | [alertController addAction:cancelAction]; 621 | [self presentViewController:alertController animated:YES completion:nil]; 622 | } 623 | 624 | #pragma mark - insert or remove 625 | 626 | // object是插入的对象(NSString、UIImage或SPPageMenuButtonItem),insertNumber是插入到第几个 627 | - (void)insertItemWithObject:(id)object toIndex:(NSInteger)insertNumber { 628 | if (insertNumber > self.myChildViewControllers.count) return; 629 | // 插入之前,先将新控制器之后的控制器view往后偏移 630 | for (int i = 0; i < self.myChildViewControllers.count; i++) { 631 | if (i >= insertNumber) { 632 | UIViewController *childController = self.myChildViewControllers[i]; 633 | childController.view.frame = CGRectMake(screenW * (i+1), 0, screenW, scrollViewHeight); 634 | [self.scrollView addSubview:childController.view]; 635 | } 636 | } 637 | if (insertNumber <= self.pageMenu.selectedItemIndex && self.myChildViewControllers.count) { // 如果新插入的item在当前选中的item之前 638 | // scrollView往后偏移 639 | self.scrollView.contentOffset = CGPointMake(screenW*(self.pageMenu.selectedItemIndex+1), 0); 640 | } else { 641 | self.scrollView.contentOffset = CGPointMake(0, 0); 642 | } 643 | 644 | SixViewController *sixVc = [[SixViewController alloc] init]; 645 | sixVc.text = @"我是新插入的"; 646 | [self addChildViewController:sixVc]; 647 | [self.myChildViewControllers insertObject:sixVc atIndex:insertNumber]; 648 | 649 | // 要先添加控制器,再添加item,如果先添加item,会立即调代理方法,此时myChildViewControllers的个数还是0,在代理方法中retun了 650 | if ([object isKindOfClass:[NSString class]]) { 651 | [self.pageMenu insertItemWithTitle:object atIndex:insertNumber animated:YES]; 652 | } else if([object isKindOfClass:[UIImage class]]) { 653 | [self.pageMenu insertItemWithImage:object atIndex:insertNumber animated:YES]; 654 | } else { 655 | [self.pageMenu insertItem:object atIndex:insertNumber animated:YES]; 656 | } 657 | 658 | // 重新设置scrollView容量 659 | self.scrollView.contentSize = CGSizeMake(screenW*self.myChildViewControllers.count, 0); 660 | } 661 | 662 | - (void)removeItemAtIndex:(NSInteger)index { 663 | // 示例中index给的是1,所以当只剩下一个子控制器时,会走该if语句,无法继续删除 664 | if (index >= self.myChildViewControllers.count) { 665 | return; 666 | } 667 | 668 | [self.pageMenu removeItemAtIndex:index animated:YES]; 669 | 670 | // 删除之前,先将新控制器之后的控制器view往前偏移 671 | for (int i = 0; i < self.myChildViewControllers.count; i++) { 672 | if (i >= index) { 673 | UIViewController *childController = self.myChildViewControllers[i]; 674 | childController.view.frame = CGRectMake(screenW * (i>0?(i-1):i), 0, screenW, scrollViewHeight); 675 | [self.scrollView addSubview:childController.view]; 676 | } 677 | } 678 | if (index <= self.pageMenu.selectedItemIndex) { // 移除的item在当前选中的item之前 679 | // scrollView往前偏移 680 | NSInteger offsetIndex = self.pageMenu.selectedItemIndex-1; 681 | if (offsetIndex < 0) { 682 | offsetIndex = 0; 683 | } 684 | self.scrollView.contentOffset = CGPointMake(screenW*offsetIndex, 0); 685 | } 686 | 687 | UIViewController *vc = [self.myChildViewControllers objectAtIndex:index]; 688 | [self.myChildViewControllers removeObjectAtIndex:index]; 689 | [vc removeFromParentViewController]; 690 | [vc.view removeFromSuperview]; 691 | 692 | // 重新设置scrollView容量 693 | self.scrollView.contentSize = CGSizeMake(screenW*self.myChildViewControllers.count, 0); 694 | } 695 | 696 | - (void)removeAllItems { 697 | [self.pageMenu removeAllItems]; 698 | for (UIViewController *vc in self.myChildViewControllers) { 699 | [vc removeFromParentViewController]; 700 | [vc.view removeFromSuperview]; 701 | } 702 | [self.myChildViewControllers removeAllObjects]; 703 | 704 | self.scrollView.contentOffset = CGPointMake(0, 0); 705 | self.scrollView.contentSize = CGSizeMake(0, 0); 706 | 707 | } 708 | 709 | #pragma mark - scrollViewDelegate 710 | 711 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 712 | 713 | // 这一步是实现跟踪器时刻跟随scrollView滑动的效果,如果对self.pageMenu.scrollView赋了值,这一步可省 714 | // [self.pageMenu moveTrackerFollowScrollView:scrollView]; 715 | } 716 | 717 | 718 | #pragma mark - getter 719 | 720 | - (UIScrollView *)scrollView { 721 | if (!_scrollView) { 722 | _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, NaviH+pageMenuH, screenW, scrollViewHeight)]; 723 | _scrollView.delegate = self; 724 | _scrollView.pagingEnabled = YES; 725 | _scrollView.showsHorizontalScrollIndicator = NO; 726 | _scrollView.showsVerticalScrollIndicator = NO; 727 | } 728 | return _scrollView; 729 | } 730 | 731 | - (NSMutableArray *)myChildViewControllers { 732 | 733 | if (!_myChildViewControllers) { 734 | _myChildViewControllers = [NSMutableArray array]; 735 | 736 | } 737 | return _myChildViewControllers; 738 | } 739 | 740 | - (void)dealloc { 741 | NSLog(@"父控制器被销毁了"); 742 | } 743 | 744 | - (void)didReceiveMemoryWarning { 745 | [super didReceiveMemoryWarning]; 746 | // Dispose of any resources that can be recreated. 747 | } 748 | 749 | 750 | @end 751 | -------------------------------------------------------------------------------- /Example/SPPageMenu/SPPageMenu/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/Example/SPPageMenu/SPPageMenu/.DS_Store -------------------------------------------------------------------------------- /Example/SPPageMenu/SPPageMenu/SPPageMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // SPPageMenu.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. https://github.com/SPStore/SPPageMenu 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSInteger, SPPageMenuTrackerStyle) { 14 | SPPageMenuTrackerStyleLine = 0, // 下划线,默认与item等宽 15 | SPPageMenuTrackerStyleLineLongerThanItem, // 下划线,比item要长(长度为item的宽+间距) 16 | SPPageMenuTrackerStyleLineAttachment, // 下划线“依恋”样式,此样式下默认宽度为字体的pointSize,你可以通过trackerWidth自定义宽度 17 | SPPageMenuTrackerStyleRoundedRect, // 圆角矩形 18 | SPPageMenuTrackerStyleRect, // 矩形 19 | SPPageMenuTrackerStyleTextZoom NS_ENUM_DEPRECATED_IOS(6_0, 6_0, "该枚举值已经被废弃,请用“selectedItemZoomScale”属性代替"), // 缩放(该枚举已经被废弃,用属性代替的目的是让其余样式可与缩放样式配套使用。如果你同时设置了该枚举和selectedItemZoomScale属性,selectedItemZoomScale优先级高于SPPageMenuTrackerStyleTextZoom 20 | SPPageMenuTrackerStyleNothing // 什么样式都没有 21 | }; 22 | 23 | typedef NS_ENUM(NSInteger, SPPageMenuPermutationWay) { 24 | SPPageMenuPermutationWayScrollAdaptContent = 0, // 自适应内容,可以左右滑动 25 | SPPageMenuPermutationWayNotScrollEqualWidths, // 等宽排列,不可以滑动,整个内容被控制在pageMenu的范围之内,等宽是根据pageMenu的总宽度对每个按钮均分 26 | SPPageMenuPermutationWayNotScrollAdaptContent // 自适应内容,不可以滑动,整个内容被控制在pageMenu的范围之内,这种排列方式下,自动计算item之间的间距,itemPadding属性无效 27 | }; 28 | 29 | typedef NS_ENUM(NSInteger, SPPageMenuTrackerFollowingMode) { 30 | SPPageMenuTrackerFollowingModeAlways = 0, // 外界scrollView拖动时,跟踪器时刻跟随外界scrollView移动 31 | SPPageMenuTrackerFollowingModeEnd, // 外界scrollVie拖动结束后,跟踪器才开始移动 32 | SPPageMenuTrackerFollowingModeHalf // 外界scrollView拖动到一半时,跟踪器开始移动 33 | }; 34 | 35 | typedef NS_ENUM(NSInteger, SPItemImagePosition) { 36 | SPItemImagePositionDefault, // 默认图片在左侧 37 | SPItemImagePositionLeft, // 图片在文字左侧 38 | SPItemImagePositionRight, // 图片在文字右侧 39 | SPItemImagePositionTop, // 图片在文字上侧 40 | SPItemImagePositionBottom // 图片在文字下侧 41 | }; 42 | 43 | @class SPPageMenu,SPPageMenuButtonItem; 44 | 45 | @protocol SPPageMenuDelegate 46 | 47 | @optional 48 | // 若以下2个代理方法同时实现了,只会走第2个代理方法(第2个代理方法包含了第1个代理方法的功能) 49 | - (void)pageMenu:(SPPageMenu *)pageMenu itemSelectedAtIndex:(NSInteger)index; 50 | - (void)pageMenu:(SPPageMenu *)pageMenu itemSelectedFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex; 51 | 52 | // 右侧的功能按钮被点击的代理方法 53 | - (void)pageMenu:(SPPageMenu *)pageMenu functionButtonClicked:(UIButton *)functionButton; 54 | @end 55 | 56 | @interface SPPageMenu : UIView 57 | 58 | // 创建pagMenu 59 | + (instancetype)pageMenuWithFrame:(CGRect)frame trackerStyle:(SPPageMenuTrackerStyle)trackerStyle; 60 | - (instancetype)initWithFrame:(CGRect)frame trackerStyle:(SPPageMenuTrackerStyle)trackerStyle; 61 | 62 | /** 63 | * 传递数据 64 | * 65 | * @param items 数组 (数组元素可以是NSString、UIImage类型、SPPageMenuButtonItem类型,其中SPPageMenuButtonItem相当于一个模型,可以同时设置图片和文字) 66 | * @param selectedItemIndex 默认选中item的下标 67 | */ 68 | - (void)setItems:(nullable NSArray *)items selectedItemIndex:(NSInteger)selectedItemIndex; 69 | 70 | @property (nonatomic) NSInteger selectedItemIndex; // 选中的item下标,改变其值可以用于切换选中的item 71 | @property(nonatomic,readonly) NSUInteger numberOfItems; // items的总个数 72 | 73 | #if TARGET_INTERFACE_BUILDER 74 | @property (nonatomic, readonly) IBInspectable NSInteger trackerStyle; // 该枚举属性支持storyBoard/xib,方便在storyBoard/xib中创建时直接设置 75 | #else 76 | @property (nonatomic, readonly) SPPageMenuTrackerStyle trackerStyle; 77 | #endif 78 | 79 | @property (nonatomic, assign) SPPageMenuPermutationWay permutationWay; // 排列方式 80 | 81 | @property (nonatomic, assign) CGFloat spacing; // item之间的间距 82 | 83 | @property (nonatomic, strong) UIColor *selectedItemTitleColor; // 选中的item标题颜色 84 | @property (nonatomic, strong) UIColor *unSelectedItemTitleColor; // 未选中的item标题颜色 85 | 86 | @property (nonatomic, strong) UIFont *itemTitleFont; // 设置所有item标题字体,不区分选中的item和未选中的item 87 | @property (nonnull, nonatomic, strong) UIFont *selectedItemTitleFont; // 选中的item字体 88 | @property (nonnull, nonatomic, strong) UIFont *unSelectedItemTitleFont; // 未选中的item字体 89 | 90 | // 外界添加控制器view的srollView,pageMenu会监听该scrollView的滚动状况,让跟踪器时刻跟随此scrollView滑动;所谓的滚动状况,是指手指拖拽滚动,非手指拖拽不算 91 | @property (nonatomic, strong) UIScrollView *bridgeScrollView; 92 | 93 | // 跟踪器 94 | @property (nonatomic, readonly) UIImageView *tracker; // 跟踪器,它是一个UIImageView类型,你可以拿到该对象去设置一些自己想要的属性,例如颜色,图片等 95 | @property (nonatomic, assign) CGFloat trackerWidth; // 跟踪器的宽度 96 | - (void)setTrackerHeight:(CGFloat)trackerHeight cornerRadius:(CGFloat)cornerRadius; // 设置跟踪器的高度和圆角半径,矩形和圆角矩形样式下半径参数无效。其余样式下:默认的高度为3,圆角半径为高度的一半。 97 | @property (nonatomic, assign) SPPageMenuTrackerFollowingMode trackerFollowingMode; // 跟踪器的跟踪模式 98 | 99 | // 分割线 100 | @property (nonatomic, readonly) UIImageView *dividingLine; // 分割线,你可以拿到该对象设置一些自己想要的属性,如颜色、图片等,如果想要隐藏分割线,拿到该对象直接设置hidden为YES或设置alpha<0.01即可(eg:pageMenu.dividingLine.hidden = YES) 101 | @property (nonatomic) CGFloat dividingLineHeight; // 分割线的高度 102 | 103 | @property (nonatomic, assign) UIEdgeInsets contentInset; // 内容的四周内边距(内容不包括分割线),默认UIEdgeInsetsZero 104 | 105 | // 选中的item缩放系数,默认为1,为1代表不缩放,[0,1)之间缩小,(1,+∞)之间放大,(-1,0)之间"倒立"缩小,(-∞,-1)之间"倒立"放大,为-1"倒立不缩放",如果依然使用了废弃的SPPageMenuTrackerStyleTextZoom样式,则缩放系数默认为1.3 106 | @property (nonatomic) CGFloat selectedItemZoomScale; 107 | @property (nonatomic, assign) BOOL needTextColorGradients; // 是否需要文字渐变,默认为YES 108 | 109 | @property (nonatomic, assign) BOOL showFuntionButton; // 是否显示功能按钮(功能按钮显示在最右侧),默认为NO 110 | @property (nonatomic, assign) CGFloat funtionButtonshadowOpacity; // 功能按钮左侧的阴影透明度,如果设置小于等于0,则没有阴影 111 | 112 | @property(nonatomic) BOOL bounces; // 边界反弹效果,默认YES 113 | @property(nonatomic) BOOL alwaysBounceHorizontal; // 水平方向上,当内容没有充满scrollView时,滑动scrollView是否有反弹效果,默认NO 114 | 115 | @property (nonatomic, weak) id delegate; 116 | 117 | // 插入item,插入和删除操作时,如果itemIndex超过了了items的个数,则不做任何操作 118 | - (void)insertItemWithTitle:(nonnull NSString *)title atIndex:(NSUInteger)itemIndex animated:(BOOL)animated; 119 | - (void)insertItemWithImage:(nonnull UIImage *)image atIndex:(NSUInteger)itemIndex animated:(BOOL)animated; 120 | - (void)insertItem:(nonnull SPPageMenuButtonItem *)item atIndex:(NSUInteger)itemIndex animated:(BOOL)animated; 121 | // 如果移除的正是当前选中的item(当前选中的item下标不为0),删除之后,选中的item会切换为上一个item 122 | - (void)removeItemAtIndex:(NSUInteger)itemIndex animated:(BOOL)animated; 123 | - (void)removeAllItems; 124 | 125 | - (void)setTitle:(nonnull NSString *)title forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的标题,设置后,仅会有文字 126 | - (nullable NSString *)titleForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的标题 127 | 128 | - (void)setImage:(nonnull UIImage *)image forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的图片,设置后,仅会有图片 129 | - (nullable UIImage *)imageForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的图片 130 | 131 | - (void)setItem:(SPPageMenuButtonItem *)item forItemAtIndex:(NSUInteger)itemIndex; // 同时为指定item设置标题和图片 132 | - (nullable SPPageMenuButtonItem *)itemAtIndex:(NSUInteger)itemIndex; // 获取指定item 133 | 134 | - (void)setContent:(id)content forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的内容,content可以是NSString、UIImage或SPPageMenuButtonItem类型 135 | - (id)contentForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的内容,该方法返回值可能是NSString、UIImage或SPPageMenuButtonItem类型 136 | 137 | - (void)setWidth:(CGFloat)width forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的宽度(如果width为0,item会根据内容自动计算width) 138 | - (CGFloat)widthForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的宽度 139 | 140 | - (void)setCustomSpacing:(CGFloat)spacing afterItemAtIndex:(NSUInteger)itemIndex; // 设置指定item后面的自定义间距 141 | - (CGFloat)customSpacingAfterItemAtIndex:(NSUInteger)itemIndex; // 获取指定item后面的自定义间距 142 | 143 | - (void)setEnabled:(BOOL)enaled forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的enabled状态 144 | - (BOOL)enabledForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的enabled状态 145 | 146 | - (void)setContentEdgeInsets:(UIEdgeInsets)contentEdgeInsets forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的四周内边距 147 | - (UIEdgeInsets)contentEdgeInsetsForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的四周内边距 148 | 149 | // 设置背景图片,barMetrics只有为UIBarMetricsDefault时才生效,如果外界传进来的backgroundImage调用过-resizableImageWithCapInsets:且参数capInsets不为UIEdgeInsetsZero,则直接用backgroundImage作为背景图; 否则内部会自动调用-resizableImageWithCapInsets:进行拉伸 150 | - (void)setBackgroundImage:(nullable UIImage *)backgroundImage barMetrics:(UIBarMetrics)barMetrics; 151 | - (nullable UIImage *)backgroundImageForBarMetrics:(UIBarMetrics)barMetrics; // 获取背景图片 152 | 153 | - (CGRect)titleRectRelativeToPageMenuForItemAtIndex:(NSUInteger)itemIndex; // 文字相对pageMenu位置和大小 154 | - (CGRect)imageRectRelativeToPageMenuForItemAtIndex:(NSUInteger)itemIndex; // 图片相对pageMenu位置和大小 155 | - (CGRect)buttonRectRelativeToPageMenuForItemAtIndex:(NSUInteger)itemIndex; // 按钮相对pageMenu位置和大小 156 | 157 | - (void)addComponentViewInScrollView:(UIView *)componentView; // 在内置的scrollView上添加一个view 158 | 159 | // 设置功能按钮的内容,content可以是NSString、UIImage或SPPageMenuButtonItem类型 160 | - (void)setFunctionButtonContent:(id)content forState:(UIControlState)state; 161 | // 为functionButton配置相关属性,如设置字体、文字颜色等;在此,attributes中,只有NSFontAttributeName、NSForegroundColorAttributeName、NSBackgroundColorAttributeName有效 162 | - (void)setFunctionButtonTitleTextAttributes:(nullable NSDictionary *)attributes forState:(UIControlState)state; 163 | 164 | 165 | /* 1.让跟踪器时刻跟随外界scrollView滑动,实现了让跟踪器的宽度逐渐适应item宽度的功能; 166 | 2.这个方法用于外界的scrollViewDidScroll代理方法中,如 167 | 168 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 169 | [self.pageMenu moveTrackerFollowScrollView:scrollView]; 170 | } 171 | 172 | 3.如果外界设置了SPPageMenu的属性"bridgeScrollView",那么外界就可以不用在scrollViewDidScroll方法中调用这个方法来实现跟踪器时刻跟随外界scrollView的效果,内部会自动处理; 外界对SPPageMenu的属性"bridgeScrollView"赋值是实现此效果的最简便的操作 173 | */ 174 | - (void)moveTrackerFollowScrollView:(UIScrollView *)scrollView; 175 | 176 | 177 | // -------------- 以下方法和属性被废弃,不再建议使用 -------------- 178 | 179 | @property (nonatomic, assign) CGFloat itemPadding NS_DEPRECATED_IOS(6_0, 6_0, "Use spacing instead");; 180 | // 设置指定item的四周内边距,3.0版本的时候不小心多写了一个for,3.4.0版本已纠正 181 | - (void)setContentEdgeInsets:(UIEdgeInsets)contentEdgeInsets forForItemAtIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setContentEdgeInsets:forItemAtIndex:"); 182 | // 默认NO;关闭跟踪器的跟随效果,在外界传了scrollView进来或者调用了moveTrackerFollowScrollView的情况下,如果为YES,则当外界滑动scrollView时,跟踪器不会时刻跟随,只有滑动结束才会跟随; 3.4.0版本开始被废弃,但是依然能使用,使用后相当于设置了SPPageMenuTrackerFollowingModeEnd枚举值 183 | @property (nonatomic, assign) BOOL closeTrackerFollowingMode NS_DEPRECATED_IOS(6_0, 6_0,"Use trackerFollowingMode instead"); 184 | // 下面的方法均有升级,其中ratio参数已失效 185 | - (void)setTitle:(nullable NSString *)title image:(nullable UIImage *)image imagePosition:(SPItemImagePosition)imagePosition imageRatio:(CGFloat)ratio forItemIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setItem: forItemIndex:"); 186 | - (void)setTitle:(nullable NSString *)title image:(nullable UIImage *)image imagePosition:(SPItemImagePosition)imagePosition imageRatio:(CGFloat)ratio imageTitleSpace:(CGFloat)imageTitleSpace forItemIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setItem: forItemIndex:"); 187 | - (void)setFunctionButtonTitle:(nullable NSString *)title image:(nullable UIImage *)image imagePosition:(SPItemImagePosition)imagePosition imageRatio:(CGFloat)ratio forState:(UIControlState)state NS_DEPRECATED_IOS(6_0, 6_0, "Use - setFunctionButtonWithItem:forState:"); 188 | - (void)setFunctionButtonTitle:(nullable NSString *)title image:(nullable UIImage *)image imagePosition:(SPItemImagePosition)imagePosition imageRatio:(CGFloat)ratio imageTitleSpace:(CGFloat)imageTitleSpace forState:(UIControlState)state NS_DEPRECATED_IOS(6_0, 6_0, "Use - setFunctionButtonWithItem:forState:"); 189 | - (id)objectForItemAtIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -contentForItemAtIndex:"); 190 | - (void)setFunctionButtonWithItem:(SPPageMenuButtonItem *)item forState:(UIControlState)state NS_DEPRECATED_IOS(6_0, 6_0, "Use -setFunctionButtonContent:forState:"); 191 | - (void)setItem:(SPPageMenuButtonItem *)item forItemIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setItem:forItemAtIndex:"); 192 | - (void)setContent:(id)content forItemIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setContent:forItemAtIndex:"); 193 | @end 194 | 195 | 196 | // 这个类相当于模型,主要用于同时为某个按钮设置图片和文字时使用 197 | @interface SPPageMenuButtonItem : NSObject 198 | 199 | // 快速创建同时含有标题和图片的item,默认图片在左边,文字在右边 200 | + (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image; 201 | // 快速创建同时含有标题和图片的item,imagePositiona参数为图片位置 202 | + (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image imagePosition:(SPItemImagePosition)imagePosition; 203 | 204 | @property (nonatomic, copy) NSString *title; 205 | @property (nonatomic, copy) UIImage *image; 206 | // 图片的位置 207 | @property (nonatomic, assign) SPItemImagePosition imagePosition; 208 | // 图片与标题之间的间距,默认0.0 209 | @property (nonatomic, assign) CGFloat imageTitleSpace; 210 | 211 | @end 212 | 213 | NS_ASSUME_NONNULL_END 214 | 215 | 216 | 217 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /Example/SPPageMenu/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "ParentViewController.h" 11 | 12 | @interface ViewController () 13 | 14 | @property (nonatomic, weak) UITableView *tableView; 15 | @property (nonatomic, strong) NSArray *titles; 16 | @property (nonatomic, strong) NSArray *dataSource; 17 | 18 | @end 19 | 20 | @implementation ViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; 26 | tableView.dataSource = self; 27 | tableView.delegate = self; 28 | [self.view addSubview:tableView]; 29 | _tableView = tableView; 30 | 31 | [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"testCell"]; 32 | 33 | tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, CGFLOAT_MIN)]; 34 | tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, CGFLOAT_MIN)]; 35 | tableView.sectionFooterHeight = CGFLOAT_MIN; 36 | 37 | self.titles = @[@"跟踪器样式专区",@"排列方式专区",@"跟踪器跟踪模式专区",@"右侧功能按钮(插入和删除操作)",@"其它示例",@"特别属性"]; 38 | self.dataSource = @[@[@"下划线与按钮等宽(默认)",@"下划线比按钮略长",@"下划线“依恋”样式",@"缩放",@"圆角矩形",@"圆角矩形(与pageMenu同时圆角)",@"矩形",@"无样式"],@[@"可滑动的自适应内容排列",@"不可滑动的等宽排列",@"不可滑动的自适应内容排列"],@[@"跟踪器时刻跟随外界scrollView移动",@"外界scrollVie拖动结束后,跟踪器才开始移动",@"外界scrollView拖动距离超过屏幕一半时,跟踪器开始移动"],@[@"显示右侧功能按钮",@"给功能按钮设置图片和文字"],@[@"含有图片的按钮",@"指定按钮携带图片,或同时携带图片和文字,可以设置图片的位置",@"设置背景图片",@"某个按钮上添加一个副标题",@"角标"]]; 39 | } 40 | 41 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 42 | return self.dataSource.count; 43 | } 44 | 45 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 46 | return [self.dataSource[section] count]; 47 | } 48 | 49 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 50 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"testCell" forIndexPath:indexPath]; 51 | cell.textLabel.text = self.dataSource[indexPath.section][indexPath.row]; 52 | cell.textLabel.font = [UIFont systemFontOfSize:15]; 53 | cell.textLabel.numberOfLines = 0; 54 | return cell; 55 | } 56 | 57 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 58 | if (indexPath.section == 2) { 59 | return 60; 60 | } 61 | return 44; 62 | } 63 | 64 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 65 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 66 | 67 | ParentViewController *parentVc = [[ParentViewController alloc] init]; 68 | NSInteger testNumber = indexPath.row; 69 | int i = 1; 70 | while (i <= indexPath.section) { 71 | testNumber += [self.dataSource[indexPath.section-i] count]; 72 | i++; 73 | } 74 | parentVc.testNumber = testNumber; 75 | [self.navigationController pushViewController:parentVc animated:YES]; 76 | } 77 | 78 | - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 79 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; 80 | label.textAlignment = NSTextAlignmentCenter; 81 | label.font = [UIFont boldSystemFontOfSize:18]; 82 | label.text = self.titles[section]; 83 | return label; 84 | } 85 | 86 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 87 | return 50; 88 | } 89 | 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /Example/SPPageMenu/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. 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 | -------------------------------------------------------------------------------- /Example/SPPageMenuTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/SPPageMenuTests/SPPageMenuTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SPPageMenuTests.m 3 | // SPPageMenuTests 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SPPageMenuTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation SPPageMenuTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Example/SPPageMenuUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/SPPageMenuUITests/SPPageMenuUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SPPageMenuUITests.m 3 | // SPPageMenuUITests 4 | // 5 | // Created by 乐升平 on 17/10/26. 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SPPageMenuUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation SPPageMenuUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SPPageMenu 2 | [![Build Status](http://img.shields.io/travis/SPStore/SPPageMenu.svg?style=flat)](https://travis-ci.org/SPStore/SPPageMenu) 3 | [![Pod Version](http://img.shields.io/cocoapods/v/SPPageMenu.svg?style=flat)](http://cocoadocs.org/docsets/SPPageMenu/) 4 | [![Pod Platform](http://img.shields.io/cocoapods/p/SPPageMenu.svg?style=flat)](http://cocoadocs.org/docsets/SPPageMenu/) 5 | ![Language](https://img.shields.io/badge/language-Object--C-ff69b4.svg) 6 | [![Pod License](http://img.shields.io/cocoapods/l/SPPageMenu.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0.html) 7 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/SPStore/SPPageMenu) 8 | ![codecov](https://img.shields.io/badge/codecov-88%25-orange.svg) 9 | 10 | # 目录 11 | * [如何安装](#如何安装) 12 | * [部分功能演示图](#部分功能演示图) 13 | * [重难点讲解](#重难点讲解) 14 | * [使用者提问](#使用者提问) 15 | 16 | ## 如何安装 17 | #### 版本3.5.0 18 | ``` 19 | target 'MyApp' do 20 | pod 'SPPageMenu', '~> 3.5.0' 21 | end 22 | 23 | 说明:3.5.0版本在3.4.5版本的基础上改动如下: 24 | 1、新增7个API 25 | * - (void)setContent:(id)content forItemAtIndex:(NSUInteger)itemIndex; 26 | * - (void)setCustomSpacing:(CGFloat)spacing afterItemAtIndex:(NSUInteger)itemIndex; 27 | * - (CGFloat)customSpacingAfterItemAtIndex:(NSUInteger)itemIndex; 28 | * - (CGRect)titleRectRelativeToPageMenuForItemAtIndex:(NSUInteger)itemIndex; 29 | * - (CGRect)imageRectRelativeToPageMenuForItemAtIndex:(NSUInteger)itemIndex; 30 | * - (CGRect)buttonRectRelativeToPageMenuForItemAtIndex:(NSUInteger)itemIndex; 31 | * - (void)addComponentViewInScrollView:(UIView *)componentView; 32 | 2、在不可滑动自适应内容的排列方式下,设置间距依然生效 33 | 3、修复设置指定item宽度和内间距失效问题 34 | 4、修复多次对bridgeScrollView赋值上一个KVO观察者未移除问题 35 | ``` 36 | #### 版本3.4.5 37 | ``` 38 | target 'MyApp' do 39 | pod 'SPPageMenu', '~> 3.4.5' 40 | end 41 | 42 | 说明:3.4.5版本在3.4.4版本的基础上修复了先设置unSelectedItemTitleFont,再设置items文字显示不全问题 43 | ``` 44 | 45 | #### 版本3.4.4 46 | ``` 47 | target 'MyApp' do 48 | pod 'SPPageMenu', '~> 3.4.4' 49 | end 50 | 51 | 说明:3.4.4版本在3.4.2版本的基础上改动如下: 52 | 1、重构了内部自定义按钮 53 | 2、解决了标题颜色的alpha值小于1时颜色渐变不准确问题 54 | 3、新增SPPageMenuButtonItem模型,用于同时设置文字和图片 55 | ``` 56 | 57 | #### 版本3.4.2 58 | ``` 59 | target 'MyApp' do 60 | pod 'SPPageMenu', '~> 3.4.2' 61 | end 62 | 63 | 说明:3.4.2版本在3.4.1版本的基础上,trackStyle属性支持storyBoard/xib,方便在storyBoard/xib中创建时可以直接设置 64 | ``` 65 | 66 | #### 版本3.4.1 67 | ``` 68 | target 'MyApp' do 69 |  pod 'SPPageMenu', '~> 3.4.1' 70 | end 71 | 72 | 3.4.1版本在3.4.0版本的基础上修复了多次调用setItems:selectedItemIndex:方法引发的问题 73 | ``` 74 | 75 | #### 版本3.4.0 76 | ``` 77 | target 'MyApp' do 78 |  pod 'SPPageMenu', '~> 3.4.0' 79 | end 80 | 81 | 说明:3.4.0版本在3.0版本的基础上主要改动如下: 82 | 1、增加trackerFollowingMode属性,跟踪器跟踪模式 83 | 2、增加selectedItemTitleFont和unSelectedItemTitleFont属性,设置选中item的标题字体和非选中item的标题字体 84 | 3、增加设置和获取背景图片的方法 85 | 4、修复跟踪器缩放文字显示不全问题 86 | 5、优化代码 87 | ``` 88 | 89 | #### 版本3.0 90 | ``` 91 | target 'MyApp' do 92 |  pod 'SPPageMenu', '~> 3.0' 93 | end 94 | 95 | 说明:3.0版本在2.5.5版本的基础上主要改动如下: 96 | 1、新增numberOfItems属性,意思是items的个数 97 | 2、新增bounces属性,滑动scrollView时的边界反弹效果 98 | 3、新增alwaysBounceHorizontal属性,水平方向上,当内容没有充满scrollView时,滑动scrollView是否有反弹效果 99 | 4、新增设置或获取指定按钮的四周内边距的方法 100 | 5、分割线适配屏幕分辨率,并修改了默认颜色 101 | 6、内部scrollView的scrollsToTop属性置为NO,不妨碍外界scrollView的置顶功能 102 | 7、右侧功能按钮的单边阴影效果采用shadowPath 103 | 8、细化内部的自定义按钮,比如可以设置文字与图片之间的间距 104 | 9、修复设置指定item的文字较长时的显示不全的问题 105 | 10、修复插入和删除操作引发的bug 106 | 11、修复长按按钮然后滑动scrollView无法滑动问题 107 | ``` 108 | 109 | #### 版本2.5.5 110 | ``` 111 | target 'MyApp' do 112 |  pod 'SPPageMenu', '~> 2.5.5' 113 | end 114 | 115 | 说明:2.5.5版本在2.5.3版本的基础上主要改动如下: 116 | 1、增加可以设置跟踪器宽度的属性,增加可以设置跟踪器高度和圆角半径的方法 117 | 2、修复了当未选中按钮颜色的alpha值小于1时,颜色渐变不准确问题 118 | 3、废弃了文字缩放(SPPageMenuTrackerStyleTextZoom)的枚举,该枚举由属性selectedItemZoomScale 119 | 代替,增加了SPPageMenuTrackerStyleNothing枚举 120 | 4、可以设置分割线高度 121 | ``` 122 | 123 | ##### 版本2.5.3 124 | ``` 125 | target 'MyApp' do 126 | pod 'SPPageMenu', '~> 2.5.3' 127 | end 128 | ``` 129 | ## 部分功能演示图 130 | (友情提示:如果您的网络较慢,gif图可能会延迟加载,您可以先把宝贵的时间浏览其它信息) 131 | 132 | ![image](https://github.com/SPStore/SPPageMenu/blob/master/3006981-889f087b55f3e57f.gif) 133 | ## 重难点讲解 134 | ``` 135 | // 该属性是选中的按钮下标,大家可以通过这个属性判断选择了第几个按钮,如果改变其值,可以用于切换选中的按钮 136 | 137 | @property (nonatomic) NSInteger selectedItemIndex; 138 | ``` 139 | ``` 140 | // 这个scrollView是外界传进来的scrollView,通常的案例都是在pageMenu的下方有若干个子控制器在切换,子控制器的切换由滑动 141 | scrollView实现,使用者只需要把该scrollView传给bridgeScrollView,SPPageMenu框架内部会监听该scrollView的横向滚动,实 142 | 现了让跟踪器时刻跟随该scrollView滚动的效果。暂时不支持监听垂直方向的滚动,如果你的scrollVeiw要垂直滚动实现切换按钮,你 143 | 不妨可以尝试自己在-scrollViewDidScroll:代理方法中设置selectedItemIndex的值 144 | 145 | @property (nonatomic, strong) UIScrollView *bridgeScrollView; 146 | ``` 147 | ``` 148 | // 排列方式:支持3种排列方式;1、可滑动,按钮宽度根据内容自适应;2、不可滑动,按钮等宽;3、不可滑动,按钮宽度根据内容自 149 | 适应。3种排列方式都有非常高的使用频率。第1种排列方式:SPPageMene的容量会根据按钮个数而定;第2种和第3种排列方式:SPPageMenu 150 | 的容量固定为SPPageMenu的宽度 151 | 152 | @property (nonatomic, assign) SPPageMenuPermutationWay permutationWay; 153 | ``` 154 | ``` 155 | // 跟踪器跟踪模式;这个属性从3.4版本开始闪亮登场。该属性是个枚举,共3个:1、SPPageMenuTrackerFollowingModeAlways,这个 156 | 枚举值的意思是让跟踪器时刻跟随外界scrollView(即bridgeScrollView)横向移动; 2、SPPageMenuTrackerFollowingModeEnd,这个 157 | 枚举的意思是当外界scrollView滑动结束时,跟踪器才开始移动;相当于3.4版本之前的closeTrackerFollowingMode属性 3、 158 | SPPageMenuTrackerFollowingModeHalf,这个枚举的意思是当外界scrollView拖动距离超过屏幕一半时,跟踪器开始移动。 159 | 160 | @property (nonatomic, assign) SPPageMenuTrackerFollowingMode trackerFollowingMode; 161 | ``` 162 | ``` 163 | // 内容的四周内边距(内容不包括分割线),默认UIEdgeInsetsZero;这个属性是个惊喜,往往能做到一些你意想不到的事情。假如你的 164 | SPPageMenu控件高度固定不变,想要设置跟踪器与按钮之间的垂直间距变小,就可以设置该属性的top和bottom值,让SPPageMenu的 165 | 内容在垂直方向上内缩 166 | 167 | @property (nonatomic, assign) UIEdgeInsets contentInset; 168 | ``` 169 | ``` 170 | // 该方法的效果和属性bridgeScrollView功能一致,如果外界想通过该方法实现跟踪器时刻跟随scrollView移动,可以在代理方法 171 | -scrollViewDidScroll:中调用该方法,如果方法和属性同时实现,属性优先级更高 172 | 173 | - (void)moveTrackerFollowScrollView:(UIScrollView *)scrollView; 174 | ``` 175 | ``` 176 | // 代理方法:若以下2个代理方法同时实现了,只会走第2个代理方法(第2个代理方法包含了第1个代理方法的功能) 177 | // 代理方法何时触发?代理方法有2种方式会触发,第一种是点击了SPPageMenu的按钮,这种方式无论点击的按钮是否同一个都会触发; 178 | 第二种是由滑动外界scrollView而触发,当跟踪模式为SPPageMenuTrackerFollowingModeAlways和SPPageMenuTrackerFollowingModeEnd 179 | 时,滑动scrollView结束的时候触发地代理方法,当跟踪器的跟踪模式为SPPageMenuTrackerFollowingModeHalf时,滑动scrollView 180 | 超过一半时就会触发代理方法 181 | 182 | - (void)pageMenu:(SPPageMenu *)pageMenu itemSelectedAtIndex:(NSInteger)index; 183 | - (void)pageMenu:(SPPageMenu *)pageMenu itemSelectedFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex; 184 | ``` 185 | ### 想了解更多使用细节,大家可以把demo下载到本地,里面有非常多的示例以及详细的注释 186 | 187 | # 使用者提问 188 | * **问**:当我设置排列方式为按钮等宽(即SPPageMenuPermutationWayNotScrollEqualWidths),为什么按钮文字显示不全?
189 | **答**:这是因为你的按钮个数较多或者文字较长,你可以通过设置itemPadding属性来调整按钮之间的间距,间距调小,每个按钮的宽度就会增大, 190 | 如果itemPadding设置为0仍然显示不全,那就请选择其它排列方式。 191 | 192 | * **问**:如何不通过点击按钮或者滑动外界scrollView来实现选中按钮的切换 ?
193 | **答**:你可以改变selectedItemIndex的值切换选中按钮 194 | 195 | * **问**:如何在不改变pageMenu高度的情况下,让跟踪器和按钮之间的垂直间距变小 ?
196 | **答**:你可以通过设置contentInset的top和bottom值,让pageMenu的内容在垂直方向上往中间挤压 197 | 198 | * **问**:如何给按钮设置角标 ?
199 | **答**:本框架并未单独提供设置角标的方法,因为设置角标是一个比较大的工程,如果提供角标,又得给角标提供各种属性设置,这将会把本框架搞的非常臃肿,这也 200 | 不是本框架的重点内容,但是也不是不可以设置,你可以通过KVC获取按钮的数组buttons,然后通过该数组获取指定按钮,拿到该按钮就可以设置角标,具体 201 | 事例demo中有示范 202 | 203 | [回到顶部](#目录) 204 | 205 | -------------------------------------------------------------------------------- /SPPageMenu.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint SPPageMenu.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "SPPageMenu" 19 | s.version = "3.5.0" 20 | s.summary = "分页菜单." 21 | 22 | # This description is used to generate tags and improve search results. 23 | # * Think: What does it do? Why did you write it? What is the focus? 24 | # * Try to keep it short, snappy and to the point. 25 | # * Write the description between the DESC delimiters below. 26 | # * Finally, don't worry about the indent, CocoaPods strips it! 27 | s.description = <<-DESC 28 | 这是一个分页菜单 29 | DESC 30 | 31 | s.homepage = "https://github.com/SPStore/SPPageMenu" 32 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 33 | 34 | 35 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 36 | # 37 | # Licensing your code is important. See http://choosealicense.com for more info. 38 | # CocoaPods will detect a license file if there is a named LICENSE* 39 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 40 | # 41 | 42 | s.license = "MIT" 43 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 44 | 45 | 46 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 47 | # 48 | # Specify the authors of the library, with email addresses. Email addresses 49 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 50 | # accepts just a name if you'd rather not provide an email address. 51 | # 52 | # Specify a social_media_url where others can refer to, for example a twitter 53 | # profile URL. 54 | # 55 | 56 | s.author = { "SPStore" => "lesp163@163.com" } 57 | # Or just: s.author = "SPStore" 58 | # s.authors = { "SPStore" => "" } 59 | # s.social_media_url = "http://twitter.com/SPStore" 60 | 61 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 62 | # 63 | # If this Pod runs only on iOS or OS X, then specify the platform and 64 | # the deployment target. You can optionally include the target after the platform. 65 | # 66 | 67 | s.platform = :ios 68 | s.platform = :ios, "8.0" 69 | 70 | # When using multiple platforms 71 | s.ios.deployment_target = "8.0" 72 | # s.osx.deployment_target = "10.7" 73 | # s.watchos.deployment_target = "2.0" 74 | # s.tvos.deployment_target = "9.0" 75 | 76 | 77 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 78 | # 79 | # Specify the location from where the source should be retrieved. 80 | # Supports git, hg, bzr, svn and HTTP. 81 | # 82 | 83 | s.source = { :git => "https://github.com/SPStore/SPPageMenu.git", :tag => s.version } 84 | 85 | 86 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 87 | # 88 | # CocoaPods is smart about how it includes source code. For source files 89 | # giving a folder will include any swift, h, m, mm, c & cpp files. 90 | # For header files it will include any header in the folder. 91 | # Not including the public_header_files will make all headers public. 92 | # 93 | 94 | s.source_files = "SPPageMenu" 95 | s.exclude_files = "Classes/Exclude" 96 | 97 | # s.public_header_files = "Classes/**/*.h" 98 | 99 | 100 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 101 | # 102 | # A list of resources included with the Pod. These are copied into the 103 | # target bundle with a build phase script. Anything else will be cleaned. 104 | # You can preserve files from being cleaned, please don't preserve 105 | # non-essential files like tests, examples and documentation. 106 | # 107 | 108 | # s.resource = "icon.png" 109 | # s.resources = "Resources/*.png" 110 | 111 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave" 112 | 113 | 114 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 115 | # 116 | # Link your library with frameworks, or libraries. Libraries do not include 117 | # the lib prefix of their name. 118 | # 119 | 120 | # s.framework = "SomeFramework" 121 | # s.frameworks = "SomeFramework", "AnotherFramework" 122 | 123 | # s.library = "iconv" 124 | # s.libraries = "iconv", "xml2" 125 | 126 | 127 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 128 | # 129 | # If your library depends on compiler flags you can set them in the xcconfig hash 130 | # where they will only apply to your library. If you depend on other Podspecs 131 | # you can include multiple dependencies to ensure it works. 132 | 133 | # s.requires_arc = true 134 | 135 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 136 | # s.dependency "JSONKit", "~> 1.4" 137 | 138 | end 139 | -------------------------------------------------------------------------------- /SPPageMenu/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SPStore/SPPageMenu/0f9cfa4d98db9d8b625565ccd36e5d35d410e12f/SPPageMenu/.DS_Store -------------------------------------------------------------------------------- /SPPageMenu/SPPageMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // SPPageMenu.h 3 | // SPPageMenu 4 | // 5 | // Created by 乐升平 on 17/10/26. https://github.com/SPStore/SPPageMenu 6 | // Copyright © 2017年 iDress. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSInteger, SPPageMenuTrackerStyle) { 14 | SPPageMenuTrackerStyleLine = 0, // 下划线,默认与item等宽 15 | SPPageMenuTrackerStyleLineLongerThanItem, // 下划线,比item要长(长度为item的宽+间距) 16 | SPPageMenuTrackerStyleLineAttachment, // 下划线“依恋”样式,此样式下默认宽度为字体的pointSize,你可以通过trackerWidth自定义宽度 17 | SPPageMenuTrackerStyleRoundedRect, // 圆角矩形 18 | SPPageMenuTrackerStyleRect, // 矩形 19 | SPPageMenuTrackerStyleTextZoom NS_ENUM_DEPRECATED_IOS(6_0, 6_0, "该枚举值已经被废弃,请用“selectedItemZoomScale”属性代替"), // 缩放(该枚举已经被废弃,用属性代替的目的是让其余样式可与缩放样式配套使用。如果你同时设置了该枚举和selectedItemZoomScale属性,selectedItemZoomScale优先级高于SPPageMenuTrackerStyleTextZoom 20 | SPPageMenuTrackerStyleNothing // 什么样式都没有 21 | }; 22 | 23 | typedef NS_ENUM(NSInteger, SPPageMenuPermutationWay) { 24 | SPPageMenuPermutationWayScrollAdaptContent = 0, // 自适应内容,可以左右滑动 25 | SPPageMenuPermutationWayNotScrollEqualWidths, // 等宽排列,不可以滑动,整个内容被控制在pageMenu的范围之内,等宽是根据pageMenu的总宽度对每个按钮均分 26 | SPPageMenuPermutationWayNotScrollAdaptContent // 自适应内容,不可以滑动,整个内容被控制在pageMenu的范围之内,这种排列方式下,自动计算item之间的间距,itemPadding属性无效 27 | }; 28 | 29 | typedef NS_ENUM(NSInteger, SPPageMenuTrackerFollowingMode) { 30 | SPPageMenuTrackerFollowingModeAlways = 0, // 外界scrollView拖动时,跟踪器时刻跟随外界scrollView移动 31 | SPPageMenuTrackerFollowingModeEnd, // 外界scrollVie拖动结束后,跟踪器才开始移动 32 | SPPageMenuTrackerFollowingModeHalf // 外界scrollView拖动到一半时,跟踪器开始移动 33 | }; 34 | 35 | typedef NS_ENUM(NSInteger, SPItemImagePosition) { 36 | SPItemImagePositionDefault, // 默认图片在左侧 37 | SPItemImagePositionLeft, // 图片在文字左侧 38 | SPItemImagePositionRight, // 图片在文字右侧 39 | SPItemImagePositionTop, // 图片在文字上侧 40 | SPItemImagePositionBottom // 图片在文字下侧 41 | }; 42 | 43 | @class SPPageMenu,SPPageMenuButtonItem; 44 | 45 | @protocol SPPageMenuDelegate 46 | 47 | @optional 48 | // 若以下2个代理方法同时实现了,只会走第2个代理方法(第2个代理方法包含了第1个代理方法的功能) 49 | - (void)pageMenu:(SPPageMenu *)pageMenu itemSelectedAtIndex:(NSInteger)index; 50 | - (void)pageMenu:(SPPageMenu *)pageMenu itemSelectedFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex; 51 | 52 | // 右侧的功能按钮被点击的代理方法 53 | - (void)pageMenu:(SPPageMenu *)pageMenu functionButtonClicked:(UIButton *)functionButton; 54 | @end 55 | 56 | @interface SPPageMenu : UIView 57 | 58 | // 创建pagMenu 59 | + (instancetype)pageMenuWithFrame:(CGRect)frame trackerStyle:(SPPageMenuTrackerStyle)trackerStyle; 60 | - (instancetype)initWithFrame:(CGRect)frame trackerStyle:(SPPageMenuTrackerStyle)trackerStyle; 61 | 62 | /** 63 | * 传递数据 64 | * 65 | * @param items 数组 (数组元素可以是NSString、UIImage类型、SPPageMenuButtonItem类型,其中SPPageMenuButtonItem相当于一个模型,可以同时设置图片和文字) 66 | * @param selectedItemIndex 默认选中item的下标 67 | */ 68 | - (void)setItems:(nullable NSArray *)items selectedItemIndex:(NSInteger)selectedItemIndex; 69 | 70 | @property (nonatomic) NSInteger selectedItemIndex; // 选中的item下标,改变其值可以用于切换选中的item 71 | @property(nonatomic,readonly) NSUInteger numberOfItems; // items的总个数 72 | 73 | #if TARGET_INTERFACE_BUILDER 74 | @property (nonatomic, readonly) IBInspectable NSInteger trackerStyle; // 该枚举属性支持storyBoard/xib,方便在storyBoard/xib中创建时直接设置 75 | #else 76 | @property (nonatomic, readonly) SPPageMenuTrackerStyle trackerStyle; 77 | #endif 78 | 79 | @property (nonatomic, assign) SPPageMenuPermutationWay permutationWay; // 排列方式 80 | 81 | @property (nonatomic, assign) CGFloat spacing; // item之间的间距 82 | 83 | @property (nonatomic, strong) UIColor *selectedItemTitleColor; // 选中的item标题颜色 84 | @property (nonatomic, strong) UIColor *unSelectedItemTitleColor; // 未选中的item标题颜色 85 | 86 | @property (nonatomic, strong) UIFont *itemTitleFont; // 设置所有item标题字体,不区分选中的item和未选中的item 87 | @property (nonnull, nonatomic, strong) UIFont *selectedItemTitleFont; // 选中的item字体 88 | @property (nonnull, nonatomic, strong) UIFont *unSelectedItemTitleFont; // 未选中的item字体 89 | 90 | // 外界添加控制器view的srollView,pageMenu会监听该scrollView的滚动状况,让跟踪器时刻跟随此scrollView滑动;所谓的滚动状况,是指手指拖拽滚动,非手指拖拽不算 91 | @property (nonatomic, strong) UIScrollView *bridgeScrollView; 92 | 93 | // 跟踪器 94 | @property (nonatomic, readonly) UIImageView *tracker; // 跟踪器,它是一个UIImageView类型,你可以拿到该对象去设置一些自己想要的属性,例如颜色,图片等 95 | @property (nonatomic, assign) CGFloat trackerWidth; // 跟踪器的宽度 96 | - (void)setTrackerHeight:(CGFloat)trackerHeight cornerRadius:(CGFloat)cornerRadius; // 设置跟踪器的高度和圆角半径,矩形和圆角矩形样式下半径参数无效。其余样式下:默认的高度为3,圆角半径为高度的一半。 97 | @property (nonatomic, assign) SPPageMenuTrackerFollowingMode trackerFollowingMode; // 跟踪器的跟踪模式 98 | 99 | // 分割线 100 | @property (nonatomic, readonly) UIImageView *dividingLine; // 分割线,你可以拿到该对象设置一些自己想要的属性,如颜色、图片等,如果想要隐藏分割线,拿到该对象直接设置hidden为YES或设置alpha<0.01即可(eg:pageMenu.dividingLine.hidden = YES) 101 | @property (nonatomic) CGFloat dividingLineHeight; // 分割线的高度 102 | 103 | @property (nonatomic, assign) UIEdgeInsets contentInset; // 内容的四周内边距(内容不包括分割线),默认UIEdgeInsetsZero 104 | 105 | // 选中的item缩放系数,默认为1,为1代表不缩放,[0,1)之间缩小,(1,+∞)之间放大,(-1,0)之间"倒立"缩小,(-∞,-1)之间"倒立"放大,为-1"倒立不缩放",如果依然使用了废弃的SPPageMenuTrackerStyleTextZoom样式,则缩放系数默认为1.3 106 | @property (nonatomic) CGFloat selectedItemZoomScale; 107 | @property (nonatomic, assign) BOOL needTextColorGradients; // 是否需要文字渐变,默认为YES 108 | 109 | @property (nonatomic, assign) BOOL showFuntionButton; // 是否显示功能按钮(功能按钮显示在最右侧),默认为NO 110 | @property (nonatomic, assign) CGFloat funtionButtonshadowOpacity; // 功能按钮左侧的阴影透明度,如果设置小于等于0,则没有阴影 111 | 112 | @property(nonatomic) BOOL bounces; // 边界反弹效果,默认YES 113 | @property(nonatomic) BOOL alwaysBounceHorizontal; // 水平方向上,当内容没有充满scrollView时,滑动scrollView是否有反弹效果,默认NO 114 | 115 | @property (nonatomic, weak) id delegate; 116 | 117 | // 插入item,插入和删除操作时,如果itemIndex超过了了items的个数,则不做任何操作 118 | - (void)insertItemWithTitle:(nonnull NSString *)title atIndex:(NSUInteger)itemIndex animated:(BOOL)animated; 119 | - (void)insertItemWithImage:(nonnull UIImage *)image atIndex:(NSUInteger)itemIndex animated:(BOOL)animated; 120 | - (void)insertItem:(nonnull SPPageMenuButtonItem *)item atIndex:(NSUInteger)itemIndex animated:(BOOL)animated; 121 | // 如果移除的正是当前选中的item(当前选中的item下标不为0),删除之后,选中的item会切换为上一个item 122 | - (void)removeItemAtIndex:(NSUInteger)itemIndex animated:(BOOL)animated; 123 | - (void)removeAllItems; 124 | 125 | - (void)setTitle:(nonnull NSString *)title forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的标题,设置后,仅会有文字 126 | - (nullable NSString *)titleForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的标题 127 | 128 | - (void)setImage:(nonnull UIImage *)image forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的图片,设置后,仅会有图片 129 | - (nullable UIImage *)imageForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的图片 130 | 131 | - (void)setItem:(SPPageMenuButtonItem *)item forItemAtIndex:(NSUInteger)itemIndex; // 同时为指定item设置标题和图片 132 | - (nullable SPPageMenuButtonItem *)itemAtIndex:(NSUInteger)itemIndex; // 获取指定item 133 | 134 | - (void)setContent:(id)content forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的内容,content可以是NSString、UIImage或SPPageMenuButtonItem类型 135 | - (id)contentForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的内容,该方法返回值可能是NSString、UIImage或SPPageMenuButtonItem类型 136 | 137 | - (void)setWidth:(CGFloat)width forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的宽度(如果width为0,item会根据内容自动计算width) 138 | - (CGFloat)widthForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的宽度 139 | 140 | - (void)setCustomSpacing:(CGFloat)spacing afterItemAtIndex:(NSUInteger)itemIndex; // 设置指定item后面的自定义间距 141 | - (CGFloat)customSpacingAfterItemAtIndex:(NSUInteger)itemIndex; // 获取指定item后面的自定义间距 142 | 143 | - (void)setEnabled:(BOOL)enaled forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的enabled状态 144 | - (BOOL)enabledForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的enabled状态 145 | 146 | - (void)setContentEdgeInsets:(UIEdgeInsets)contentEdgeInsets forItemAtIndex:(NSUInteger)itemIndex; // 设置指定item的四周内边距 147 | - (UIEdgeInsets)contentEdgeInsetsForItemAtIndex:(NSUInteger)itemIndex; // 获取指定item的四周内边距 148 | 149 | // 设置背景图片,barMetrics只有为UIBarMetricsDefault时才生效,如果外界传进来的backgroundImage调用过-resizableImageWithCapInsets:且参数capInsets不为UIEdgeInsetsZero,则直接用backgroundImage作为背景图; 否则内部会自动调用-resizableImageWithCapInsets:进行拉伸 150 | - (void)setBackgroundImage:(nullable UIImage *)backgroundImage barMetrics:(UIBarMetrics)barMetrics; 151 | - (nullable UIImage *)backgroundImageForBarMetrics:(UIBarMetrics)barMetrics; // 获取背景图片 152 | 153 | - (CGRect)titleRectRelativeToPageMenuForItemAtIndex:(NSUInteger)itemIndex; // 文字相对pageMenu位置和大小 154 | - (CGRect)imageRectRelativeToPageMenuForItemAtIndex:(NSUInteger)itemIndex; // 图片相对pageMenu位置和大小 155 | - (CGRect)buttonRectRelativeToPageMenuForItemAtIndex:(NSUInteger)itemIndex; // 按钮相对pageMenu位置和大小 156 | 157 | - (void)addComponentViewInScrollView:(UIView *)componentView; // 在内置的scrollView上添加一个view 158 | 159 | // 设置功能按钮的内容,content可以是NSString、UIImage或SPPageMenuButtonItem类型 160 | - (void)setFunctionButtonContent:(id)content forState:(UIControlState)state; 161 | // 为functionButton配置相关属性,如设置字体、文字颜色等;在此,attributes中,只有NSFontAttributeName、NSForegroundColorAttributeName、NSBackgroundColorAttributeName有效 162 | - (void)setFunctionButtonTitleTextAttributes:(nullable NSDictionary *)attributes forState:(UIControlState)state; 163 | 164 | 165 | /* 1.让跟踪器时刻跟随外界scrollView滑动,实现了让跟踪器的宽度逐渐适应item宽度的功能; 166 | 2.这个方法用于外界的scrollViewDidScroll代理方法中,如 167 | 168 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 169 | [self.pageMenu moveTrackerFollowScrollView:scrollView]; 170 | } 171 | 172 | 3.如果外界设置了SPPageMenu的属性"bridgeScrollView",那么外界就可以不用在scrollViewDidScroll方法中调用这个方法来实现跟踪器时刻跟随外界scrollView的效果,内部会自动处理; 外界对SPPageMenu的属性"bridgeScrollView"赋值是实现此效果的最简便的操作 173 | */ 174 | - (void)moveTrackerFollowScrollView:(UIScrollView *)scrollView; 175 | 176 | 177 | // -------------- 以下方法和属性被废弃,不再建议使用 -------------- 178 | 179 | @property (nonatomic, assign) CGFloat itemPadding NS_DEPRECATED_IOS(6_0, 6_0, "Use spacing instead");; 180 | // 设置指定item的四周内边距,3.0版本的时候不小心多写了一个for,3.4.0版本已纠正 181 | - (void)setContentEdgeInsets:(UIEdgeInsets)contentEdgeInsets forForItemAtIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setContentEdgeInsets:forItemAtIndex:"); 182 | // 默认NO;关闭跟踪器的跟随效果,在外界传了scrollView进来或者调用了moveTrackerFollowScrollView的情况下,如果为YES,则当外界滑动scrollView时,跟踪器不会时刻跟随,只有滑动结束才会跟随; 3.4.0版本开始被废弃,但是依然能使用,使用后相当于设置了SPPageMenuTrackerFollowingModeEnd枚举值 183 | @property (nonatomic, assign) BOOL closeTrackerFollowingMode NS_DEPRECATED_IOS(6_0, 6_0,"Use trackerFollowingMode instead"); 184 | // 下面的方法均有升级,其中ratio参数已失效 185 | - (void)setTitle:(nullable NSString *)title image:(nullable UIImage *)image imagePosition:(SPItemImagePosition)imagePosition imageRatio:(CGFloat)ratio forItemIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setItem: forItemIndex:"); 186 | - (void)setTitle:(nullable NSString *)title image:(nullable UIImage *)image imagePosition:(SPItemImagePosition)imagePosition imageRatio:(CGFloat)ratio imageTitleSpace:(CGFloat)imageTitleSpace forItemIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setItem: forItemIndex:"); 187 | - (void)setFunctionButtonTitle:(nullable NSString *)title image:(nullable UIImage *)image imagePosition:(SPItemImagePosition)imagePosition imageRatio:(CGFloat)ratio forState:(UIControlState)state NS_DEPRECATED_IOS(6_0, 6_0, "Use - setFunctionButtonWithItem:forState:"); 188 | - (void)setFunctionButtonTitle:(nullable NSString *)title image:(nullable UIImage *)image imagePosition:(SPItemImagePosition)imagePosition imageRatio:(CGFloat)ratio imageTitleSpace:(CGFloat)imageTitleSpace forState:(UIControlState)state NS_DEPRECATED_IOS(6_0, 6_0, "Use - setFunctionButtonWithItem:forState:"); 189 | - (id)objectForItemAtIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -contentForItemAtIndex:"); 190 | - (void)setFunctionButtonWithItem:(SPPageMenuButtonItem *)item forState:(UIControlState)state NS_DEPRECATED_IOS(6_0, 6_0, "Use -setFunctionButtonContent:forState:"); 191 | - (void)setItem:(SPPageMenuButtonItem *)item forItemIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setItem:forItemAtIndex:"); 192 | - (void)setContent:(id)content forItemIndex:(NSUInteger)itemIndex NS_DEPRECATED_IOS(6_0, 6_0, "Use -setContent:forItemAtIndex:"); 193 | @end 194 | 195 | 196 | // 这个类相当于模型,主要用于同时为某个按钮设置图片和文字时使用 197 | @interface SPPageMenuButtonItem : NSObject 198 | 199 | // 快速创建同时含有标题和图片的item,默认图片在左边,文字在右边 200 | + (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image; 201 | // 快速创建同时含有标题和图片的item,imagePositiona参数为图片位置 202 | + (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image imagePosition:(SPItemImagePosition)imagePosition; 203 | 204 | @property (nonatomic, copy) NSString *title; 205 | @property (nonatomic, copy) UIImage *image; 206 | // 图片的位置 207 | @property (nonatomic, assign) SPItemImagePosition imagePosition; 208 | // 图片与标题之间的间距,默认0.0 209 | @property (nonatomic, assign) CGFloat imageTitleSpace; 210 | 211 | @end 212 | 213 | NS_ASSUME_NONNULL_END 214 | 215 | 216 | 217 | --------------------------------------------------------------------------------