├── .gitignore ├── LICENSE ├── LinkageMenu ├── LinkageMenu.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── LinkageMenu │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ └── LaunchScreen.storyboard │ ├── ExampleView │ ├── OneCollectionViewCell.h │ ├── OneCollectionViewCell.m │ ├── OneView.h │ ├── OneView.m │ ├── TwoView.h │ └── TwoView.m │ ├── Info.plist │ ├── LinkageMenu │ ├── LinkageMenuView.h │ └── LinkageMenuView.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── README.md └── gif ├── i5.gif ├── i6.gif └── i6p.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5AD3671D1E7291C80020CF29 /* OneCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AD3671A1E7291C80020CF29 /* OneCollectionViewCell.m */; }; 11 | 5AD3671E1E7291C80020CF29 /* OneView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AD3671C1E7291C80020CF29 /* OneView.m */; }; 12 | 5AD367211E7292D40020CF29 /* TwoView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AD367201E7292D40020CF29 /* TwoView.m */; }; 13 | 5AF648221E6FA87A00A24341 /* LinkageMenuView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AF648211E6FA87A00A24341 /* LinkageMenuView.m */; }; 14 | 5AF9A9851E6EAAB0003929A1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AF9A9841E6EAAB0003929A1 /* main.m */; }; 15 | 5AF9A9881E6EAAB0003929A1 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AF9A9871E6EAAB0003929A1 /* AppDelegate.m */; }; 16 | 5AF9A98B1E6EAAB0003929A1 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AF9A98A1E6EAAB0003929A1 /* ViewController.m */; }; 17 | 5AF9A9901E6EAAB0003929A1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5AF9A98F1E6EAAB0003929A1 /* Assets.xcassets */; }; 18 | 5AF9A9931E6EAAB0003929A1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5AF9A9911E6EAAB0003929A1 /* LaunchScreen.storyboard */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 5AD367191E7291C80020CF29 /* OneCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OneCollectionViewCell.h; sourceTree = ""; }; 23 | 5AD3671A1E7291C80020CF29 /* OneCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OneCollectionViewCell.m; sourceTree = ""; }; 24 | 5AD3671B1E7291C80020CF29 /* OneView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OneView.h; sourceTree = ""; }; 25 | 5AD3671C1E7291C80020CF29 /* OneView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OneView.m; sourceTree = ""; }; 26 | 5AD3671F1E7292D40020CF29 /* TwoView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoView.h; sourceTree = ""; }; 27 | 5AD367201E7292D40020CF29 /* TwoView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TwoView.m; sourceTree = ""; }; 28 | 5AF648201E6FA87A00A24341 /* LinkageMenuView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinkageMenuView.h; sourceTree = ""; }; 29 | 5AF648211E6FA87A00A24341 /* LinkageMenuView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LinkageMenuView.m; sourceTree = ""; }; 30 | 5AF9A9801E6EAAB0003929A1 /* LinkageMenu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LinkageMenu.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 5AF9A9841E6EAAB0003929A1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32 | 5AF9A9861E6EAAB0003929A1 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 33 | 5AF9A9871E6EAAB0003929A1 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 34 | 5AF9A9891E6EAAB0003929A1 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 35 | 5AF9A98A1E6EAAB0003929A1 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 36 | 5AF9A98F1E6EAAB0003929A1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 37 | 5AF9A9921E6EAAB0003929A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 38 | 5AF9A9941E6EAAB0003929A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | 5AF9A97D1E6EAAB0003929A1 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | 5AD367181E7291C80020CF29 /* ExampleView */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 5AD367191E7291C80020CF29 /* OneCollectionViewCell.h */, 56 | 5AD3671A1E7291C80020CF29 /* OneCollectionViewCell.m */, 57 | 5AD3671B1E7291C80020CF29 /* OneView.h */, 58 | 5AD3671C1E7291C80020CF29 /* OneView.m */, 59 | 5AD3671F1E7292D40020CF29 /* TwoView.h */, 60 | 5AD367201E7292D40020CF29 /* TwoView.m */, 61 | ); 62 | path = ExampleView; 63 | sourceTree = ""; 64 | }; 65 | 5AF9A9771E6EAAB0003929A1 = { 66 | isa = PBXGroup; 67 | children = ( 68 | 5AF9A9821E6EAAB0003929A1 /* LinkageMenu */, 69 | 5AF9A9811E6EAAB0003929A1 /* Products */, 70 | ); 71 | sourceTree = ""; 72 | }; 73 | 5AF9A9811E6EAAB0003929A1 /* Products */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 5AF9A9801E6EAAB0003929A1 /* LinkageMenu.app */, 77 | ); 78 | name = Products; 79 | sourceTree = ""; 80 | }; 81 | 5AF9A9821E6EAAB0003929A1 /* LinkageMenu */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 5AD367181E7291C80020CF29 /* ExampleView */, 85 | 5AF9A99A1E6EAFF2003929A1 /* LinkageMenu */, 86 | 5AF9A9861E6EAAB0003929A1 /* AppDelegate.h */, 87 | 5AF9A9871E6EAAB0003929A1 /* AppDelegate.m */, 88 | 5AF9A9891E6EAAB0003929A1 /* ViewController.h */, 89 | 5AF9A98A1E6EAAB0003929A1 /* ViewController.m */, 90 | 5AF9A9831E6EAAB0003929A1 /* Supporting Files */, 91 | ); 92 | path = LinkageMenu; 93 | sourceTree = ""; 94 | }; 95 | 5AF9A9831E6EAAB0003929A1 /* Supporting Files */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 5AF9A98F1E6EAAB0003929A1 /* Assets.xcassets */, 99 | 5AF9A9911E6EAAB0003929A1 /* LaunchScreen.storyboard */, 100 | 5AF9A9941E6EAAB0003929A1 /* Info.plist */, 101 | 5AF9A9841E6EAAB0003929A1 /* main.m */, 102 | ); 103 | name = "Supporting Files"; 104 | sourceTree = ""; 105 | }; 106 | 5AF9A99A1E6EAFF2003929A1 /* LinkageMenu */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 5AF648201E6FA87A00A24341 /* LinkageMenuView.h */, 110 | 5AF648211E6FA87A00A24341 /* LinkageMenuView.m */, 111 | ); 112 | path = LinkageMenu; 113 | sourceTree = ""; 114 | }; 115 | /* End PBXGroup section */ 116 | 117 | /* Begin PBXNativeTarget section */ 118 | 5AF9A97F1E6EAAB0003929A1 /* LinkageMenu */ = { 119 | isa = PBXNativeTarget; 120 | buildConfigurationList = 5AF9A9971E6EAAB0003929A1 /* Build configuration list for PBXNativeTarget "LinkageMenu" */; 121 | buildPhases = ( 122 | 5AF9A97C1E6EAAB0003929A1 /* Sources */, 123 | 5AF9A97D1E6EAAB0003929A1 /* Frameworks */, 124 | 5AF9A97E1E6EAAB0003929A1 /* Resources */, 125 | ); 126 | buildRules = ( 127 | ); 128 | dependencies = ( 129 | ); 130 | name = LinkageMenu; 131 | productName = LinkageMenu; 132 | productReference = 5AF9A9801E6EAAB0003929A1 /* LinkageMenu.app */; 133 | productType = "com.apple.product-type.application"; 134 | }; 135 | /* End PBXNativeTarget section */ 136 | 137 | /* Begin PBXProject section */ 138 | 5AF9A9781E6EAAB0003929A1 /* Project object */ = { 139 | isa = PBXProject; 140 | attributes = { 141 | LastUpgradeCheck = 0810; 142 | ORGANIZATIONNAME = EmotionV; 143 | TargetAttributes = { 144 | 5AF9A97F1E6EAAB0003929A1 = { 145 | CreatedOnToolsVersion = 8.1; 146 | ProvisioningStyle = Automatic; 147 | }; 148 | }; 149 | }; 150 | buildConfigurationList = 5AF9A97B1E6EAAB0003929A1 /* Build configuration list for PBXProject "LinkageMenu" */; 151 | compatibilityVersion = "Xcode 3.2"; 152 | developmentRegion = English; 153 | hasScannedForEncodings = 0; 154 | knownRegions = ( 155 | en, 156 | Base, 157 | ); 158 | mainGroup = 5AF9A9771E6EAAB0003929A1; 159 | productRefGroup = 5AF9A9811E6EAAB0003929A1 /* Products */; 160 | projectDirPath = ""; 161 | projectRoot = ""; 162 | targets = ( 163 | 5AF9A97F1E6EAAB0003929A1 /* LinkageMenu */, 164 | ); 165 | }; 166 | /* End PBXProject section */ 167 | 168 | /* Begin PBXResourcesBuildPhase section */ 169 | 5AF9A97E1E6EAAB0003929A1 /* Resources */ = { 170 | isa = PBXResourcesBuildPhase; 171 | buildActionMask = 2147483647; 172 | files = ( 173 | 5AF9A9931E6EAAB0003929A1 /* LaunchScreen.storyboard in Resources */, 174 | 5AF9A9901E6EAAB0003929A1 /* Assets.xcassets in Resources */, 175 | ); 176 | runOnlyForDeploymentPostprocessing = 0; 177 | }; 178 | /* End PBXResourcesBuildPhase section */ 179 | 180 | /* Begin PBXSourcesBuildPhase section */ 181 | 5AF9A97C1E6EAAB0003929A1 /* Sources */ = { 182 | isa = PBXSourcesBuildPhase; 183 | buildActionMask = 2147483647; 184 | files = ( 185 | 5AF9A98B1E6EAAB0003929A1 /* ViewController.m in Sources */, 186 | 5AF648221E6FA87A00A24341 /* LinkageMenuView.m in Sources */, 187 | 5AD3671D1E7291C80020CF29 /* OneCollectionViewCell.m in Sources */, 188 | 5AF9A9881E6EAAB0003929A1 /* AppDelegate.m in Sources */, 189 | 5AF9A9851E6EAAB0003929A1 /* main.m in Sources */, 190 | 5AD3671E1E7291C80020CF29 /* OneView.m in Sources */, 191 | 5AD367211E7292D40020CF29 /* TwoView.m in Sources */, 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | /* End PBXSourcesBuildPhase section */ 196 | 197 | /* Begin PBXVariantGroup section */ 198 | 5AF9A9911E6EAAB0003929A1 /* LaunchScreen.storyboard */ = { 199 | isa = PBXVariantGroup; 200 | children = ( 201 | 5AF9A9921E6EAAB0003929A1 /* Base */, 202 | ); 203 | name = LaunchScreen.storyboard; 204 | sourceTree = ""; 205 | }; 206 | /* End PBXVariantGroup section */ 207 | 208 | /* Begin XCBuildConfiguration section */ 209 | 5AF9A9951E6EAAB0003929A1 /* Debug */ = { 210 | isa = XCBuildConfiguration; 211 | buildSettings = { 212 | ALWAYS_SEARCH_USER_PATHS = NO; 213 | CLANG_ANALYZER_NONNULL = YES; 214 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 215 | CLANG_CXX_LIBRARY = "libc++"; 216 | CLANG_ENABLE_MODULES = YES; 217 | CLANG_ENABLE_OBJC_ARC = YES; 218 | CLANG_WARN_BOOL_CONVERSION = YES; 219 | CLANG_WARN_CONSTANT_CONVERSION = YES; 220 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 221 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 222 | CLANG_WARN_EMPTY_BODY = YES; 223 | CLANG_WARN_ENUM_CONVERSION = YES; 224 | CLANG_WARN_INFINITE_RECURSION = YES; 225 | CLANG_WARN_INT_CONVERSION = YES; 226 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 227 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 228 | CLANG_WARN_UNREACHABLE_CODE = YES; 229 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 230 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 231 | COPY_PHASE_STRIP = NO; 232 | DEBUG_INFORMATION_FORMAT = dwarf; 233 | ENABLE_STRICT_OBJC_MSGSEND = YES; 234 | ENABLE_TESTABILITY = YES; 235 | GCC_C_LANGUAGE_STANDARD = gnu99; 236 | GCC_DYNAMIC_NO_PIC = NO; 237 | GCC_NO_COMMON_BLOCKS = YES; 238 | GCC_OPTIMIZATION_LEVEL = 0; 239 | GCC_PREPROCESSOR_DEFINITIONS = ( 240 | "DEBUG=1", 241 | "$(inherited)", 242 | ); 243 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 244 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 245 | GCC_WARN_UNDECLARED_SELECTOR = YES; 246 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 247 | GCC_WARN_UNUSED_FUNCTION = YES; 248 | GCC_WARN_UNUSED_VARIABLE = YES; 249 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 250 | MTL_ENABLE_DEBUG_INFO = YES; 251 | ONLY_ACTIVE_ARCH = YES; 252 | SDKROOT = iphoneos; 253 | }; 254 | name = Debug; 255 | }; 256 | 5AF9A9961E6EAAB0003929A1 /* Release */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | ALWAYS_SEARCH_USER_PATHS = NO; 260 | CLANG_ANALYZER_NONNULL = YES; 261 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 262 | CLANG_CXX_LIBRARY = "libc++"; 263 | CLANG_ENABLE_MODULES = YES; 264 | CLANG_ENABLE_OBJC_ARC = YES; 265 | CLANG_WARN_BOOL_CONVERSION = YES; 266 | CLANG_WARN_CONSTANT_CONVERSION = YES; 267 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 268 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 269 | CLANG_WARN_EMPTY_BODY = YES; 270 | CLANG_WARN_ENUM_CONVERSION = YES; 271 | CLANG_WARN_INFINITE_RECURSION = YES; 272 | CLANG_WARN_INT_CONVERSION = YES; 273 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 274 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 275 | CLANG_WARN_UNREACHABLE_CODE = YES; 276 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 277 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 278 | COPY_PHASE_STRIP = NO; 279 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 280 | ENABLE_NS_ASSERTIONS = NO; 281 | ENABLE_STRICT_OBJC_MSGSEND = YES; 282 | GCC_C_LANGUAGE_STANDARD = gnu99; 283 | GCC_NO_COMMON_BLOCKS = YES; 284 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 285 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 286 | GCC_WARN_UNDECLARED_SELECTOR = YES; 287 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 288 | GCC_WARN_UNUSED_FUNCTION = YES; 289 | GCC_WARN_UNUSED_VARIABLE = YES; 290 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 291 | MTL_ENABLE_DEBUG_INFO = NO; 292 | SDKROOT = iphoneos; 293 | VALIDATE_PRODUCT = YES; 294 | }; 295 | name = Release; 296 | }; 297 | 5AF9A9981E6EAAB0003929A1 /* Debug */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 301 | INFOPLIST_FILE = LinkageMenu/Info.plist; 302 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 303 | PRODUCT_BUNDLE_IDENTIFIER = com.EmotionV.LinkageMenu; 304 | PRODUCT_NAME = "$(TARGET_NAME)"; 305 | }; 306 | name = Debug; 307 | }; 308 | 5AF9A9991E6EAAB0003929A1 /* Release */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 312 | INFOPLIST_FILE = LinkageMenu/Info.plist; 313 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 314 | PRODUCT_BUNDLE_IDENTIFIER = com.EmotionV.LinkageMenu; 315 | PRODUCT_NAME = "$(TARGET_NAME)"; 316 | }; 317 | name = Release; 318 | }; 319 | /* End XCBuildConfiguration section */ 320 | 321 | /* Begin XCConfigurationList section */ 322 | 5AF9A97B1E6EAAB0003929A1 /* Build configuration list for PBXProject "LinkageMenu" */ = { 323 | isa = XCConfigurationList; 324 | buildConfigurations = ( 325 | 5AF9A9951E6EAAB0003929A1 /* Debug */, 326 | 5AF9A9961E6EAAB0003929A1 /* Release */, 327 | ); 328 | defaultConfigurationIsVisible = 0; 329 | defaultConfigurationName = Release; 330 | }; 331 | 5AF9A9971E6EAAB0003929A1 /* Build configuration list for PBXNativeTarget "LinkageMenu" */ = { 332 | isa = XCConfigurationList; 333 | buildConfigurations = ( 334 | 5AF9A9981E6EAAB0003929A1 /* Debug */, 335 | 5AF9A9991E6EAAB0003929A1 /* Release */, 336 | ); 337 | defaultConfigurationIsVisible = 0; 338 | defaultConfigurationName = Release; 339 | }; 340 | /* End XCConfigurationList section */ 341 | }; 342 | rootObject = 5AF9A9781E6EAAB0003929A1 /* Project object */; 343 | } 344 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/7. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // github: https://github.com/EmotionV/LinkageMenu 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/7. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // github: https://github.com/EmotionV/LinkageMenu 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 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 | 21 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 22 | self.window.backgroundColor = [UIColor whiteColor]; 23 | [self.window makeKeyAndVisible]; 24 | 25 | UITabBarController *tabVC = [[UITabBarController alloc] init]; 26 | ViewController *mainVC = [[ViewController alloc] init]; 27 | tabVC.viewControllers = @[mainVC]; 28 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:tabVC]; 29 | self.window.rootViewController = nav; 30 | 31 | return YES; 32 | } 33 | 34 | 35 | - (void)applicationWillResignActive:(UIApplication *)application { 36 | // 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. 37 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 38 | } 39 | 40 | 41 | - (void)applicationDidEnterBackground:(UIApplication *)application { 42 | // 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. 43 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 44 | } 45 | 46 | 47 | - (void)applicationWillEnterForeground:(UIApplication *)application { 48 | // 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. 49 | } 50 | 51 | 52 | - (void)applicationDidBecomeActive:(UIApplication *)application { 53 | // 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. 54 | } 55 | 56 | 57 | - (void)applicationWillTerminate:(UIApplication *)application { 58 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 59 | } 60 | 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/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 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/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 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/ExampleView/OneCollectionViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // OneCollectionViewCell.h 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/10. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OneCollectionViewCell : UICollectionViewCell 12 | 13 | @property (nonatomic, strong) UIView *backView; 14 | @property (nonatomic, strong) UILabel *titleLabel; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/ExampleView/OneCollectionViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // OneCollectionViewCell.m 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/10. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // 8 | 9 | #import "OneCollectionViewCell.h" 10 | 11 | @implementation OneCollectionViewCell 12 | 13 | - (instancetype)initWithFrame:(CGRect)frame{ 14 | if (self = [super initWithFrame:frame]) { 15 | self.frame = frame; 16 | [self addSubview:self.backView]; 17 | [self addSubview:self.titleLabel]; 18 | } 19 | return self; 20 | } 21 | 22 | - (UIView *)backView{ 23 | if (!_backView) { 24 | _backView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, self.frame.size.width - 20, self.frame.size.width - 20)]; 25 | _backView.backgroundColor = [UIColor grayColor]; 26 | } 27 | return _backView; 28 | } 29 | 30 | - (UILabel *)titleLabel{ 31 | if (!_titleLabel) { 32 | _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, _backView.frame.origin.y + _backView.frame.size.height + 10, self.frame.size.width, 20)]; 33 | _titleLabel.textAlignment = NSTextAlignmentCenter; 34 | _titleLabel.font = [UIFont systemFontOfSize:13]; 35 | } 36 | return _titleLabel; 37 | } 38 | @end 39 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/ExampleView/OneView.h: -------------------------------------------------------------------------------- 1 | // 2 | // OneView.h 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/10. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OneView : UIView 12 | 13 | @property (nonatomic, strong) NSArray *dataArray; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/ExampleView/OneView.m: -------------------------------------------------------------------------------- 1 | // 2 | // OneView.m 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/10. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // 8 | 9 | #import "OneView.h" 10 | #import "OneCollectionViewCell.h" 11 | @interface OneView() 12 | 13 | @property (nonatomic, strong) UICollectionView *collectionView; 14 | 15 | @end 16 | 17 | @implementation OneView 18 | 19 | - (instancetype)initWithFrame:(CGRect)frame{ 20 | if (self = [super initWithFrame:frame]) { 21 | self.frame = frame; 22 | [self.collectionView registerClass:[OneCollectionViewCell class] forCellWithReuseIdentifier:@"cell"]; 23 | [self addSubview:self.collectionView]; 24 | self.collectionView.backgroundColor = [UIColor whiteColor]; 25 | } 26 | return self; 27 | } 28 | 29 | - (void)setDataArray:(NSArray *)dataArray{ 30 | _dataArray = dataArray; 31 | [self.collectionView reloadData]; 32 | } 33 | 34 | - (UICollectionView *)collectionView{ 35 | if (!_collectionView) { 36 | UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new]; 37 | layout.minimumInteritemSpacing = 0; 38 | layout.scrollDirection = UICollectionViewScrollDirectionVertical; 39 | _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) collectionViewLayout:layout]; 40 | _collectionView.delegate = self; 41 | _collectionView.dataSource = self; 42 | } 43 | return _collectionView; 44 | } 45 | 46 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 47 | return _dataArray.count; 48 | } 49 | 50 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { 51 | CGFloat cellWidth = (self.frame.size.width - 5.0) / 3.0; 52 | CGFloat cellHeight = cellWidth + 20; 53 | return CGSizeMake(cellWidth, cellHeight); 54 | } 55 | 56 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { 57 | return 10; 58 | } 59 | 60 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 61 | 62 | OneCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath]; 63 | cell.titleLabel.text = [_dataArray objectAtIndex:indexPath.row]; 64 | return cell; 65 | 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/ExampleView/TwoView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TwoView.h 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/10. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TwoView : UITableView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/ExampleView/TwoView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TwoView.m 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/10. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // 8 | 9 | #import "TwoView.h" 10 | 11 | @implementation TwoView 12 | 13 | - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style{ 14 | if (self = [super initWithFrame:frame style:style]) { 15 | self.delegate = self; 16 | self.dataSource = self; 17 | } 18 | return self; 19 | } 20 | 21 | #pragma mark - UITableViewDelegate 22 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 23 | return 15; 24 | } 25 | 26 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ 27 | return 1; 28 | } 29 | 30 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 31 | return 44; 32 | } 33 | 34 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 35 | 36 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 37 | if (cell == nil) { 38 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"]; 39 | } 40 | cell.textLabel.text = [NSString stringWithFormat:@"cell-%ld", (long)indexPath.row]; 41 | return cell; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/LinkageMenu/LinkageMenuView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LinkageMenuView.h 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/8. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // github: https://github.com/EmotionV/LinkageMenu 8 | 9 | #import 10 | 11 | @interface LinkageMenuView : UIView 12 | 13 | @property (nonatomic, strong) UIColor *selectViewColor; /**< select view color (滑块颜色)*/ 14 | @property (nonatomic, strong) UIColor *textColor; /**< text color (标题颜色)*/ 15 | @property (nonatomic, strong) UIColor *selectTextColor; /**< select text color (标题选中的颜色)*/ 16 | @property (nonatomic, assign) CGFloat textSize; /**< text size (标题字体大小)*/ 17 | 18 | /** 19 | Init Method 20 | 21 | @param frame LinkageMenu frame 22 | @param menu titles array 23 | @param views right views array 24 | 25 | */ 26 | - (instancetype)initWithFrame:(CGRect)frame WithMenu:(NSArray *)menu andViews:(NSArray *)views; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/LinkageMenu/LinkageMenuView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LinkageMenuView.m 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/8. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // github: https://github.com/EmotionV/LinkageMenu 8 | 9 | #import "LinkageMenuView.h" 10 | #define MENU_WIDTH 100 //左侧菜单栏宽度,默认100 11 | #define BOTTOMVIEW_HEIGHT 25 //滑块高度 12 | #define BOTTOMVIEW_WIDTH (MENU_WIDTH - 10) //滑块宽度 13 | #define LINEVIEW_WIDTH 1.0 //分割线宽度 14 | #define ANIMATION_TIME 0.2 //菜单栏滚动的时间 15 | 16 | #define FULLVIEW_FOR6 667 //iPhone6(s)高度 17 | #define NAVIGATION_HEIGHT 64 //navigationbar高度 18 | #define TABBAR_HEIGHT 49 //tabbar高度 19 | #define FUll_VIEW_WIDTH ([[UIScreen mainScreen] bounds].size.width) 20 | #define FUll_VIEW_HEIGHT ([[UIScreen mainScreen] bounds].size.height) 21 | 22 | @interface LinkageMenuView() 23 | 24 | @property (nonatomic, strong) UIScrollView *menuView; 25 | @property (nonatomic, strong) UIView *bottomView; 26 | @property (nonatomic, strong) UIView *lineView; 27 | @property (nonatomic, strong) UIView *rightview; 28 | 29 | @end 30 | 31 | @implementation LinkageMenuView{ 32 | NSArray *menuArray; 33 | NSArray *viewArray; 34 | NSInteger titlesCount; //菜单总数 35 | NSInteger newChoseTag; //选择的button tag 36 | NSInteger choseTag; //上次选择的button tag 37 | CGFloat btnHeight; //button高度,适配不同屏幕 38 | NSInteger DTScrollTag; //滚动tag 39 | CGFloat blankHeight; 40 | CGFloat half_blankHeight; 41 | } 42 | 43 | #pragma mark - Init Method 44 | - (instancetype)initWithFrame:(CGRect)frame WithMenu:(NSArray *)menu andViews:(NSArray *)views{ 45 | if (self = [super init]) { 46 | if (FUll_VIEW_HEIGHT < FULLVIEW_FOR6) { 47 | btnHeight = 43; 48 | DTScrollTag = 5; 49 | }else if (FUll_VIEW_HEIGHT == FULLVIEW_FOR6){ 50 | btnHeight = 44; 51 | DTScrollTag = 6; 52 | }else if (FUll_VIEW_HEIGHT > FULLVIEW_FOR6){ 53 | btnHeight = 42.7; 54 | DTScrollTag = 7; 55 | } 56 | //Default Menu Style 57 | _textSize = 14.0; 58 | _textColor = [UIColor blackColor]; 59 | _selectTextColor = [UIColor whiteColor]; 60 | _selectViewColor = [UIColor blackColor]; 61 | 62 | if (views.count < menu.count) { 63 | NSLog(@"Please Add More Views"); 64 | } 65 | for (int i = 0; i < views.count; i++) { 66 | UIView *view = [views objectAtIndex:i]; 67 | view.frame = self.rightview.bounds; 68 | } 69 | [self.rightview addSubview:(UIView *)[views objectAtIndex:0]]; 70 | 71 | menuArray = menu; 72 | viewArray = views; 73 | titlesCount = menuArray.count; 74 | blankHeight = btnHeight - BOTTOMVIEW_HEIGHT; 75 | half_blankHeight = (btnHeight - BOTTOMVIEW_HEIGHT) / 2.0; 76 | choseTag = 1; //默认选中菜单栏第一个 77 | self.frame = frame; 78 | [self addSubview:self.menuView]; 79 | [self addSubview:self.lineView]; 80 | [self addSubview:self.rightview]; 81 | } 82 | return self; 83 | } 84 | 85 | #pragma mark - Setter Method 86 | - (void)setSelectViewColor:(UIColor *)selectViewColor{ 87 | _selectTextColor = selectViewColor; 88 | _bottomView.backgroundColor = _selectViewColor; 89 | } 90 | - (void)setTextColor:(UIColor *)textColor{ 91 | _textColor = textColor; 92 | for (int i = 2; i <= menuArray.count; i++) { 93 | UIButton *button = [self viewWithTag:i]; 94 | [button setTitleColor:textColor forState:UIControlStateNormal]; 95 | } 96 | } 97 | - (void)setSelectTextColor:(UIColor *)selectTextColor{ 98 | _selectTextColor = selectTextColor; 99 | UIButton *button = [self viewWithTag:1]; 100 | [button setTitleColor:_selectTextColor forState:UIControlStateNormal]; 101 | } 102 | - (void)setTextSize:(CGFloat)textSize{ 103 | _textSize = textSize; 104 | for (int i = 1; i <= menuArray.count; i++) { 105 | UIButton *button = [self viewWithTag:i]; 106 | button.titleLabel.font = [UIFont systemFontOfSize:textSize]; 107 | } 108 | } 109 | 110 | #pragma mark - LazyLoad 111 | - (UIView *)lineView{ 112 | if (!_lineView) { 113 | _lineView = [[UIView alloc] initWithFrame:CGRectMake(MENU_WIDTH, 0, LINEVIEW_WIDTH, self.frame.size.height)]; 114 | _lineView.backgroundColor = [UIColor lightGrayColor]; 115 | } 116 | return _lineView; 117 | } 118 | 119 | - (UIView *)rightview{ 120 | if (!_rightview) { 121 | _rightview = [[UIView alloc] initWithFrame:CGRectMake(MENU_WIDTH + LINEVIEW_WIDTH, NAVIGATION_HEIGHT, FUll_VIEW_WIDTH - MENU_WIDTH + LINEVIEW_WIDTH, FUll_VIEW_HEIGHT)]; 122 | } 123 | return _rightview; 124 | } 125 | 126 | - (UIScrollView *)menuView{ 127 | if (!_menuView) { 128 | _menuView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, MENU_WIDTH, self.frame.size.height)]; 129 | _menuView.backgroundColor = [UIColor whiteColor]; 130 | _menuView.scrollsToTop = NO; 131 | _menuView.showsVerticalScrollIndicator = NO; 132 | 133 | _menuView.contentSize = CGSizeMake(0, titlesCount * btnHeight + blankHeight + 5.0); 134 | 135 | _bottomView = [[UIView alloc] initWithFrame:CGRectMake((MENU_WIDTH - BOTTOMVIEW_WIDTH) / 2.0, blankHeight + 1.0,BOTTOMVIEW_WIDTH , BOTTOMVIEW_HEIGHT)]; 136 | _bottomView.layer.cornerRadius = BOTTOMVIEW_HEIGHT / 2.0; 137 | _bottomView.backgroundColor = _selectViewColor; 138 | [_menuView addSubview:_bottomView]; 139 | 140 | for (int i = 1; i <= menuArray.count; i++) { 141 | UIButton *menuButton = [[UIButton alloc] init]; 142 | menuButton.tag = i; 143 | menuButton.titleLabel.font = [UIFont systemFontOfSize:_textSize]; 144 | [menuButton setTitle:[menuArray objectAtIndex:(i - 1)] forState:UIControlStateNormal]; 145 | [menuButton setBackgroundColor:[UIColor clearColor]]; 146 | menuButton.frame = CGRectMake(0, btnHeight * (i - 1) + half_blankHeight + 1.0, MENU_WIDTH, btnHeight); 147 | if (i == 1) { 148 | [menuButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 149 | }else{ 150 | [menuButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 151 | } 152 | [menuButton addTarget:self action:@selector(choseMenu:) forControlEvents:UIControlEventTouchUpInside]; 153 | [_menuView addSubview:menuButton]; 154 | } 155 | } 156 | return _menuView; 157 | } 158 | 159 | #pragma mark - MenuButton Method 160 | - (void)choseMenu:(UIButton *)button{ 161 | NSLog(@"%ld==%@",(long)button.tag,button.titleLabel.text); 162 | newChoseTag = button.tag; 163 | 164 | if (newChoseTag != choseTag) { 165 | UIButton *lastButton = (UIButton *)[self viewWithTag:choseTag]; 166 | [lastButton setTitleColor:_textColor forState:UIControlStateNormal]; 167 | 168 | CGFloat scroHeight = _menuView.contentSize.height - FUll_VIEW_HEIGHT + TABBAR_HEIGHT; 169 | 170 | if (menuArray.count > DTScrollTag * 2.0) { 171 | if (button.tag <= DTScrollTag) { 172 | [UIView animateWithDuration:ANIMATION_TIME animations:^{ 173 | [_menuView setContentOffset:CGPointMake(0,- NAVIGATION_HEIGHT) animated:NO]; 174 | }]; 175 | }else if (button.tag > menuArray.count - DTScrollTag){ 176 | [UIView animateWithDuration:ANIMATION_TIME animations:^{ 177 | [_menuView setContentOffset:CGPointMake(0, scroHeight) animated:NO]; 178 | }]; 179 | }else if(button.tag == DTScrollTag + 1){ 180 | [UIView animateWithDuration:ANIMATION_TIME animations:^{ 181 | [_menuView setContentOffset:CGPointMake(0,- NAVIGATION_HEIGHT + blankHeight + 1.0) animated:NO]; 182 | }]; 183 | }else if (button.tag > DTScrollTag + 1 && button.tag < menuArray.count - DTScrollTag){ 184 | [UIView animateWithDuration:ANIMATION_TIME animations:^{ 185 | [_menuView setContentOffset:CGPointMake(0,- NAVIGATION_HEIGHT + blankHeight + 1.0 + button.frame.size.height * (button.tag - DTScrollTag - 1)) animated:NO]; 186 | }]; 187 | }else if (button.tag == menuArray.count - DTScrollTag){ 188 | [UIView animateWithDuration:ANIMATION_TIME animations:^{ 189 | [_menuView setContentOffset:CGPointMake(0, scroHeight - blankHeight - 5.0) animated:NO]; 190 | }]; 191 | } 192 | 193 | } 194 | 195 | [UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{ 196 | _bottomView.frame = CGRectMake((MENU_WIDTH - BOTTOMVIEW_WIDTH) / 2.0,button.frame.origin.y + half_blankHeight, BOTTOMVIEW_WIDTH, BOTTOMVIEW_HEIGHT); 197 | } completion:nil]; 198 | [self performSelector:@selector(delayChangeTextColor) withObject:nil afterDelay:0.07]; 199 | 200 | for (UIView *view in [_rightview subviews]) { 201 | [view removeFromSuperview]; 202 | } 203 | 204 | NSInteger viewtag; 205 | if (button.tag >= viewArray.count) { 206 | viewtag = viewArray.count - 1; 207 | }else{ 208 | viewtag = button.tag - 1; 209 | } 210 | UIView *rigView = [viewArray objectAtIndex:viewtag]; 211 | [_rightview addSubview:rigView]; 212 | } 213 | } 214 | 215 | #pragma mark - Delay Method 216 | - (void)delayChangeTextColor{ 217 | UIButton *button = (UIButton *)[self viewWithTag:newChoseTag]; 218 | [button setTitleColor:_selectTextColor forState:UIControlStateNormal]; 219 | choseTag = newChoseTag; 220 | } 221 | 222 | @end 223 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/7. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // github: https://github.com/EmotionV/LinkageMenu 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/7. 6 | // Copyright © 2017年 EmotionV. All rights reserved. 7 | // github: https://github.com/EmotionV/LinkageMenu 8 | 9 | #import "ViewController.h" 10 | #import "LinkageMenuView.h" 11 | #import "OneView.h" 12 | #import "TwoView.h" 13 | #import "OneCollectionViewCell.h" 14 | #define FUll_VIEW_WIDTH ([[UIScreen mainScreen] bounds].size.width) 15 | #define FUll_VIEW_HEIGHT ([[UIScreen mainScreen] bounds].size.height) 16 | #define NAVIGATION_HEIGHT 64 //navigationbar height 17 | #define TABBAR_HEIGHT 49 //tabbar height 18 | 19 | @interface ViewController () 20 | 21 | @property (strong,nonatomic) OneView *oneView; 22 | @property (strong,nonatomic) OneView *twoView; 23 | @property (strong,nonatomic) TwoView *threeView; 24 | @property (strong,nonatomic) UIView *fourView; 25 | @property (strong,nonatomic) OneView *fiveView; 26 | 27 | @end 28 | 29 | @implementation ViewController 30 | 31 | - (void)viewDidLoad { 32 | [super viewDidLoad]; 33 | 34 | //example view 1 35 | _oneView = [[OneView alloc] initWithFrame:CGRectMake(0, 0, FUll_VIEW_WIDTH - 101, FUll_VIEW_HEIGHT - TABBAR_HEIGHT - NAVIGATION_HEIGHT)]; 36 | _oneView.dataArray = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9"]; 37 | 38 | //example view 2 39 | _twoView = [[OneView alloc] initWithFrame:CGRectMake(0, 0, FUll_VIEW_WIDTH - 101, FUll_VIEW_HEIGHT - TABBAR_HEIGHT - NAVIGATION_HEIGHT)]; 40 | _twoView.dataArray = @[@"11",@"22",@"33",@"44",@"55",@"66",@"77",@"88"]; 41 | 42 | //example view 3 43 | _threeView = [[TwoView alloc] initWithFrame:CGRectMake(0, 0, FUll_VIEW_WIDTH - 101, FUll_VIEW_HEIGHT - TABBAR_HEIGHT - NAVIGATION_HEIGHT) style:UITableViewStylePlain]; 44 | 45 | //example view 4 46 | _fourView = [[UIView alloc] init]; 47 | _fourView.backgroundColor = [UIColor redColor]; 48 | 49 | //example view 5 50 | _fiveView = [[OneView alloc] initWithFrame:CGRectMake(0, 0, FUll_VIEW_WIDTH - 101, FUll_VIEW_HEIGHT - TABBAR_HEIGHT - NAVIGATION_HEIGHT)]; 51 | _fiveView.dataArray = @[@"11",@"22",@"33",@"44",@"55",@"66",@"77",@"88",@"99",@"1010"]; 52 | 53 | //views array 54 | NSArray *views = @[_oneView,_twoView,_threeView,_fourView,_fiveView]; 55 | 56 | //if views count less than menu count, leftover views will load the last view of the views 57 | //如果view数量少于标题数量,剩下的view会默认加载view数组的最后一个view 58 | LinkageMenuView *lkMenu = [[LinkageMenuView alloc] initWithFrame:CGRectMake(0, 0,FUll_VIEW_WIDTH , FUll_VIEW_HEIGHT - TABBAR_HEIGHT) WithMenu:@[@"为您推荐",@"美容美妆",@"奶粉纸尿裤",@"母婴专区",@"箱包配饰",@"家居个护",@"营养保健",@"服饰鞋靴",@"海外直邮",@"数码家电",@"环球美食",@"运动户外",@"生鲜",@"国家馆",@"品牌馆"] andViews:views]; 59 | 60 | // lkMenu.textSize = 11; 61 | // lkMenu.textColor = [UIColor blueColor]; 62 | // lkMenu.selectTextColor = [UIColor redColor]; 63 | // lkMenu.bottomViewColor = [UIColor yellowColor]; 64 | 65 | [self.view addSubview:lkMenu]; 66 | 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /LinkageMenu/LinkageMenu/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LinkageMenu 4 | // 5 | // Created by 风间 on 2017/3/7. 6 | // Copyright © 2017年 EmotionV. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linkage Menu View 2 | 3 | ##Preview 4 | 5 | **iPhone5 Simulator** 6 | ![image](https://github.com/EmotionV/LinkageMenu/blob/master/gif/i5.gif) 7 | 8 | **iPhone6 Simulator** 9 | ![image](https://github.com/EmotionV/LinkageMenu/blob/master/gif/i6.gif) 10 | 11 | **iPhone6p Simulator** 12 | ![image](https://github.com/EmotionV/LinkageMenu/blob/master/gif/i6p.gif) 13 | 14 | 15 | ##Usage 16 | 17 | `#import "LinkageMenuView.h"` 18 | Then, create LinkageMenuView 19 | ```objc 20 | NSArray *titles = @[@"11",@"22",@"33",@"44"]; 21 | NSArray *views = @[view1,view2,view3,view4]; 22 | LinkageMenuView *lkMenu = [[LinkageMenuView alloc] initWithFrame:FRAME WithMenu:titles andViews:views]; 23 | ``` 24 | also you can change the menu style, include `textSize` `textColor` `selectTextColor` `bottomViewColor` 25 | ```objc 26 | lkMenu.textSize = 11; 27 | lkMenu.textColor = [UIColor blueColor]; 28 | lkMenu.selectTextColor = [UIColor redColor]; 29 | lkMenu.bottomViewColor = [UIColor yellowColor]; 30 | ``` 31 | 32 | ##License 33 | MIT 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /gif/i5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emogh/LinkageMenu/3759013c156f8d84df38de8d3cf9da5b269ac129/gif/i5.gif -------------------------------------------------------------------------------- /gif/i6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emogh/LinkageMenu/3759013c156f8d84df38de8d3cf9da5b269ac129/gif/i6.gif -------------------------------------------------------------------------------- /gif/i6p.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emogh/LinkageMenu/3759013c156f8d84df38de8d3cf9da5b269ac129/gif/i6p.gif --------------------------------------------------------------------------------